diff --git a/README.md b/README.md index fcb7b4d9c..97ff2be57 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # 极客大学「算法训练营第四期 - 1 班」作业提交仓库 - 请大家通过该链接查看讲师课件并进行下载: https://pan.baidu.com/s/1k1BHhltBkZLJw0TG-uYC7g 密码:p5op + 请大家通过该链接查看讲师课件并进行下载:https://pan.baidu.com/s/1O6HNBmmIzLptVUedLvO18Q 密码:5a9g + +《算法四期1-5班社群往期分享汇总》 https://shimo.im/docs/hdx98DVvVwDC6PyC/ ## 仓库目录结构说明 diff --git a/Week 01/id_136/LeetCode_189_136.java b/Week 01/id_136/LeetCode_189_136.java new file mode 100644 index 000000000..dd3cd7166 --- /dev/null +++ b/Week 01/id_136/LeetCode_189_136.java @@ -0,0 +1,18 @@ +public class Solution { + public void rotate(int[] nums, int k) { + k %= nums.length; + //先反转整个数组,再反转前k个,再反转后面的 + reverse(nums, 0, nums.length - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, nums.length - 1); + } + public void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } +} diff --git a/Week 01/id_136/LeetCode_21_136.java b/Week 01/id_136/LeetCode_21_136.java new file mode 100644 index 000000000..251466a10 --- /dev/null +++ b/Week 01/id_136/LeetCode_21_136.java @@ -0,0 +1,27 @@ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode result = new ListNode(0); + ListNode cur = result; + + while (l1 != null && l2 != null) { + + if (l1.val > l2.val) { + cur.next = l2; + cur = cur.next; + l2 = l2.next; + } else { + cur.next = l1; + cur = cur.next; + l1 = l1.next; + } + + } + if (l1 == null) { + cur.next = l2; + } else { + cur.next = l1; + } + + return result.next; + } +} diff --git a/Week 01/id_136/LeetCode_26_136.java b/Week 01/id_136/LeetCode_26_136.java new file mode 100644 index 000000000..6c6d371c0 --- /dev/null +++ b/Week 01/id_136/LeetCode_26_136.java @@ -0,0 +1,20 @@ +/** + * 使用双指针,i快tail慢。 当i和i-1不同时,tail指针设为i的值 + * Created by 115477 on 2019/8/26. + */ +public class n0026 { + public int removeDuplicates(int[] nums) { + int l = nums.length; + if (l <= 1) { + return l; + } + int tail = 1; + for (int i = 1;i=0;i--) { + if (ia >=0 && ib >= 0) { + if (nums1[ia] > nums2[ib]) { + nums1[i] = nums1[ia]; + ia--; + } else { + nums1[i] = nums2[ib]; + ib--; + } + } else if (ia >=0 && ib < 0) { + break; + } else if (ia <0 && ib >= 0) { + nums1[i] = nums2[ib]; + ib--; + } + } + } +} diff --git a/Week 01/id_156/186_java.java b/Week 01/id_156/186_java.java new file mode 100644 index 000000000..f2e5d2653 --- /dev/null +++ b/Week 01/id_156/186_java.java @@ -0,0 +1,11 @@ +public class Solution { + public void rotate(int[] nums, int k) { + int[] a = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + a[(i + k) % nums.length] = nums[i]; + } + for (int i = 0; i < nums.length; i++) { + nums[i] = a[i]; + } + } +} diff --git a/Week 01/id_156/21_java.java b/Week 01/id_156/21_java.java new file mode 100644 index 000000000..67853255f --- /dev/null +++ b/Week 01/id_156/21_java.java @@ -0,0 +1,19 @@ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + + if (l2 == null) { + return l1; + } + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + } +} diff --git a/Week 01/id_181/11.js b/Week 01/id_181/11.js new file mode 100644 index 000000000..92235a973 --- /dev/null +++ b/Week 01/id_181/11.js @@ -0,0 +1,39 @@ + +/** + * [11. 盛最多水的容器 - 力扣(LeetCode)](https://leetcode-cn.com/problems/container-with-most-water/) + * @param {number[]} height + * @return {number} + */ +/** + * 粗暴解法,直接遍历 n^2 + */ + +var maxArea = function(height) { + let maxArea=0; + if(!(height.length>0)) return maxArea + for(let i=0;i0)) return maxArea; + let i = 0,j = height.length-1; + while(i < j) { + maxArea = height[i] < height[j] ? Math.max(maxArea,(j-i)*height[i++]):Math.max(maxArea,(j-i)*height[j--]); + } + return maxArea +}; \ No newline at end of file diff --git a/Week 01/id_231/leedcode-26.go b/Week 01/id_231/leedcode-26.go new file mode 100644 index 000000000..223545889 --- /dev/null +++ b/Week 01/id_231/leedcode-26.go @@ -0,0 +1,18 @@ +package lessions + +func removeDuplicates(nums []int) int { + if len(nums) == 0 { + return 0 + } + + cur := 0 + for i := 1; i < len(nums); i++ { + if nums[cur] == nums[i] { + continue + } + nums[cur+1] = nums[i] + cur = cur + 1 + } + + return cur + 1 +} diff --git a/Week 01/id_231/leedcode-88.go b/Week 01/id_231/leedcode-88.go new file mode 100644 index 000000000..af5bcd5fc --- /dev/null +++ b/Week 01/id_231/leedcode-88.go @@ -0,0 +1,26 @@ +package lessions + +func merge(nums1 []int, m int, nums2 []int, n int) { + p1 := m - 1 + p2 := n - 1 + p := m + n - 1 + for p1 >= 0 && p2 >= 0 { + if nums1[p1] > nums2[p2] { + nums1[p] = nums1[p1] + p1-- + } else { + nums1[p] = nums2[p2] + p2-- + } + p-- + } + + if p1 < 0 && p2 >= 0 { + copyArray(nums1, nums2, 0, p2+1) + } +} +func copyArray(dst, src []int, start, n int) { + for i := 0; i < n; i++ { + dst[start+i] = src[i] + } +} diff --git a/Week 01/id_251/LeetCode_141_251.py b/Week 01/id_251/LeetCode_141_251.py index bcbf92de2..4bec03b82 100644 --- a/Week 01/id_251/LeetCode_141_251.py +++ b/Week 01/id_251/LeetCode_141_251.py @@ -63,20 +63,15 @@ def hasCycle(self, head): """ hash_set = set() while head: - if head in hash_set: - return True + if head in hash_set: return True hash_set.add(head) head = head.next return False # 快慢指针法 def hasCycleSlowFastIndex(self, head): - slow = fast = head + slow, fast = head, head while fast and fast.next: - slow = slow.next - fast = fast.next.next - if slow is fast: - return True + slow, fast = slow.next, fast.next.next + if slow is fast: return True return False - -# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_155_251.py b/Week 01/id_251/LeetCode_155_251.py index c6195c4b3..873f04ded 100644 --- a/Week 01/id_251/LeetCode_155_251.py +++ b/Week 01/id_251/LeetCode_155_251.py @@ -39,7 +39,7 @@ def __init__(self): initialize your data structure here. """ # 数据栈 - self.data = [] + self.stack = [] # 辅助栈 self.helper = [] @@ -48,9 +48,9 @@ def push(self, x): :type x: int :rtype: None """ - self.data.append(x) + self.stack.append(x) # 这里 x < self.helper[-1] 或者 x <= self.helper[-1] 都可以 - if len(self.helper) == 0 or x <= self.helper[-1]: + if len(self.helper) == 0 or x < self.helper[-1]: self.helper.append(x) else: self.helper.append(self.helper[-1]) @@ -59,19 +59,16 @@ def pop(self): """ :rtype: None """ - if self.data: - # del 时间复杂度比pop高 - # del self.helper[-1] - # del self.data[-1] + if self.stack: self.helper.pop() - self.data.pop() + self.stack.pop() def top(self): """ :rtype: int """ - if self.data: - return self.data[-1] + if self.stack: + return self.stack[-1] def getMin(self): """ @@ -94,7 +91,7 @@ def __init__(self): initialize your data structure here. """ # 数据栈 - self.data = [] + self.stack = [] # 辅助栈 self.helper = [] @@ -103,7 +100,7 @@ def push(self, x): :type x: int :rtype: None """ - self.data.append(x) + self.stack.append(x) # 关键1 和 关键2 if len(self.helper) == 0 or x <= self.helper[-1]: self.helper.append(x) @@ -112,20 +109,17 @@ def pop(self): """ :rtype: None """ - if self.data: - if self.data[-1] == self.helper[-1]: - # del 时间复杂度比pop高 - # del self.helper[-1] - # del self.data[-1] + if self.stack: + if self.stack[-1] == self.helper[-1]: self.helper.pop() - self.data.pop() + self.stack.pop() def top(self): """ :rtype: int """ - if self.data: - return self.data[-1] + if self.stack: + return self.stack[-1] def getMin(self): """ @@ -147,7 +141,6 @@ def push(self, x): def pop(self): if self.stack: - # del self.stack[-1] self.stack.pop() def top(self): @@ -162,21 +155,21 @@ def getMin(self): # 方法3 升级 class MinStack4(object): def __init__(self): - self.data = [(None, float('inf'))] + self.stack = [(None, float('inf'))] def push(self, x): - self.data.append((x, min(x, self.data[-1][1]))) + self.stack.append((x, min(x, self.stack[-1][1]))) def pop(self): - if len(self.data) > 1: - self.data.pop() - # del self.data[-1] + if len(self.stack) > 1: + self.stack.pop() def top(self): - return self.data[-1][0] + return self.stack[-1][0] def getMin(self): - return self.data[-1][1] + if len(self.stack) > 1: + return self.stack[-1][1] # Your MinStack object will be instantiated and called as such: # obj = MinStack() diff --git a/Week 01/id_251/LeetCode_20_251.py b/Week 01/id_251/LeetCode_20_251.py index abacbb0fb..e533b7a6f 100644 --- a/Week 01/id_251/LeetCode_20_251.py +++ b/Week 01/id_251/LeetCode_20_251.py @@ -71,13 +71,13 @@ def isValid2(self, s): stack = [] hash_map = {')': '(', ']': '[', '}': '{'} - for char in s: - if char in hash_map: + for c in s: + if c in hash_map: top_element = stack.pop() if stack else '#' - if hash_map[char] != top_element: + if hash_map[c] != top_element: return False else: - stack.append(char) + stack.append(c) return not stack # 栈方法 正向思维 推荐 @@ -90,14 +90,13 @@ def isValid3(self, s): for c in s: if c in hash_map: stack.append(c) - continue elif stack and hash_map[stack[-1]] == c: - del stack[-1] + stack.pop() else: return False return not stack - # 栈方法 + # 栈方法 优化 增加一个特殊字符 def isValid3_1(self, s): if len(s) & 1 == 1: # 位运算判断奇偶 return False @@ -109,5 +108,4 @@ def isValid3_1(self, s): stack.append(c) elif hash_map[stack.pop()] != c: return False - return len(stack) == 1 -# leetcode submit region end(Prohibit modification and deletion) + return len(stack) == 1 \ No newline at end of file diff --git a/Week 01/id_251/LeetCode_25_251.py b/Week 01/id_251/LeetCode_25_251.py index 3ce2294f1..311c3b5f4 100644 --- a/Week 01/id_251/LeetCode_25_251.py +++ b/Week 01/id_251/LeetCode_25_251.py @@ -51,6 +51,15 @@ def reverseKGroup(self, head, k): # 判断不是整数倍跳出 if end is None: break + """ + pre --> start --> …… --> end --> end.next + to + pre.next --> [reverse(start --> …… --> end)] --> end.next + 此处先将end --> None, end.next 存入临时变量 _next + reverse(start --> …… --> end): start --> …… --> end + to + end --> …… --> start + """ start, end.next, _next = pre.next, None, end.next pre.next, start.next = self.reverse(start), _next end = pre = start @@ -61,5 +70,3 @@ def reverse(self, head): while curr: curr.next, pre, curr = pre, curr, curr.next return pre - -# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_641_251.py b/Week 01/id_251/LeetCode_641_251.py index 75e6a06fd..688bc01a1 100644 --- a/Week 01/id_251/LeetCode_641_251.py +++ b/Week 01/id_251/LeetCode_641_251.py @@ -84,7 +84,7 @@ def deleteFront(self): """ if self.isEmpty(): return False - del self.q[0] + self.q.pop(0) return True def deleteLast(self): @@ -231,7 +231,7 @@ def isFull(self): return self._size == self._capacity -# k+1 cycle优化 牺牲一个存储单元 +# k+1 cycle优化 牺牲一个存储单元 最有解法 class MyCircularDeque(object): def __init__(self, k): @@ -239,7 +239,6 @@ def __init__(self, k): Initialize your data structure here. Set the size of the deque to be k. :type k: int """ - self._size = k # rear 不存元素, rear-1 是队尾 self._front, self._rear = 0, 0 self._capacity = k + 1 @@ -267,7 +266,7 @@ def insertLast(self, value): return False self._data[self._rear] = value # 尾部牺牲一个存储空间 - self._rear = (self._rear + 1) % self._capacity + self._rear = (self._rear + 1 + self._capacity) % self._capacity return True def deleteFront(self): @@ -278,7 +277,7 @@ def deleteFront(self): if self.isEmpty(): return False self._data[self._front] = -1 - self._front = (self._front + 1) % self._capacity + self._front = (self._front + 1 + self._capacity) % self._capacity return True def deleteLast(self): @@ -318,7 +317,8 @@ def isFull(self): Checks whether the circular deque is full or not. :rtype: bool """ - return (self._rear - self._front + self._capacity) % self._capacity == self._size + return (self._rear + 1 + self._capacity) % self._capacity == self._front + # Your MyCircularDeque object will be instantiated and called as such: # obj = MyCircularDeque(k) # param_1 = obj.insertFront(value) diff --git a/Week 01/id_251/LeetCode_84_251.py b/Week 01/id_251/LeetCode_84_251.py index ca4f0e35a..017f15660 100644 --- a/Week 01/id_251/LeetCode_84_251.py +++ b/Week 01/id_251/LeetCode_84_251.py @@ -84,8 +84,8 @@ def largestRectangleArea3_1(self, heights): """ heights.append(0) 这里很巧妙有2点 1:将第一个while的stack[-1] != -1判断省掉 - 因为当stack[-1] == -1时,height[i] > 0, heights[stack[-1]] = heights[-1] = 0 - 从而 heights[i] < heights[stack[-1]] 包含 stack[-1= != -1 的判断 + 因为当stack[-1] == -1时,height[i] >= 0, heights[stack[-1]] = heights[-1] = 0 + 从而 stack[-1]= != -1 的判断可以省略 2:讲上一方法的最后for循环提升到前面来实现 while stack[-1] != -1: max_area = max(max_area, heights[stack.pop()] * (len(heights) - stack[-1] - 1)) @@ -100,5 +100,3 @@ def largestRectangleArea3_1(self, heights): max_area = max(max_area, heights[stack.pop()] * (i - stack[-1] - 1)) stack.append(i) return max_area - -# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_371/LeetCode_1_371.java b/Week 01/id_371/LeetCode_1_371.java index 3f69a7989..43e4ea540 100644 --- a/Week 01/id_371/LeetCode_1_371.java +++ b/Week 01/id_371/LeetCode_1_371.java @@ -19,6 +19,28 @@ public static void main(String[] args) { Arrays.stream(twoSum).forEach(System.out::println); } + + /** + * 重解1: + * @author Shaobo.Qian + * @date 2019/11/9 + */ + public static int[] twoSum2(int[] nums, int target) { + Map map = new HashMap<>(nums.length); + for (int i = 0; i < nums.length; i++) { + int key = target - nums[i]; + if (map.containsKey(key)) { + return new int[]{map.get(key), i}; + } else { + map.put(nums[i], i); + } + } + return null; + } + + + + public static int[] twoSum(int[] nums, int target) { //遍历数组,将数组元素相加和目标值比较 for (int i = 0; i < nums.length - 1; i++) { diff --git a/Week 01/id_371/Leetcode_155_371.java b/Week 01/id_371/Leetcode_155_371.java new file mode 100644 index 000000000..63898bc9c --- /dev/null +++ b/Week 01/id_371/Leetcode_155_371.java @@ -0,0 +1,60 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-10 16:09 + **/ + +public class Leetcode_155_371 { + /** + * 原解1:使用数组 + * @author Shaobo.Qian + * @date 2019/11/10 + */ + class MinStack { + List nums; + int minIndex; + + /** + * initialize your data structure here. + */ + public MinStack() { + nums = new ArrayList<>(); + minIndex = 0; + } + + public void push(int x) { + nums.add(x); + int currIndex = nums.size() - 1; + minIndex = nums.get(minIndex) > x ? currIndex : minIndex; + } + + public void pop() { + if (nums.size() == 0) return; + nums.remove(nums.size() - 1); + if (minIndex > (nums.size() - 1)) { + minIndex = getMinIndex(nums); + } + } + + private int getMinIndex(List nums) { + if (nums.size() == 0) return 0; + int minIndex = 0; + for (int i = 1; i < nums.size(); i++) { + minIndex = nums.get(i) < nums.get(minIndex) ? i : minIndex; + } + return minIndex; + } + public int top() { + if (nums.size() == 0) throw new RuntimeException("has no element"); + return nums.get(nums.size() - 1); + } + + public int getMin() { + return nums.get(minIndex); + } + } +} diff --git a/Week 01/id_371/Leetcode_20_371.java b/Week 01/id_371/Leetcode_20_371.java new file mode 100644 index 000000000..7ffaf5fbb --- /dev/null +++ b/Week 01/id_371/Leetcode_20_371.java @@ -0,0 +1,48 @@ +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-10 16:07 + **/ + +public class Leetcode_20_371 { + + public static void main(String[] args) { +// System.out.println(isValid2("()")); +// System.out.println(isValid2("()[]{}")); +// System.out.println(isValid2("(]")); +// System.out.println(isValid2("([)]")); +// System.out.println(isValid2("(")); + System.out.println(isValid1("[])")); + + } + + /** + * 原解1:stack+字符串 + * @author Shaobo.Qian + * @date 2019/11/10 + */ + public static boolean isValid1(String s) { + if(s.isEmpty()) return true; + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + String singleStr = String.valueOf(s.charAt(i)); + if ("{".equals(singleStr)) { + stack.push("}"); + } else if ("[".equals(singleStr)) { + stack.push("]"); + } else if ("(".equals(singleStr)) { + stack.push(")"); + } else { + if(stack.isEmpty()) return false; + String currStr = stack.pop(); + if (!currStr.equals(singleStr)) { + return false; + } + } + } + return stack.isEmpty(); + } +} diff --git a/Week 01/id_371/Leetcode_239_371.java b/Week 01/id_371/Leetcode_239_371.java new file mode 100644 index 000000000..b4348766f --- /dev/null +++ b/Week 01/id_371/Leetcode_239_371.java @@ -0,0 +1,10 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-10 16:09 + **/ + +public class Leetcode_239_371 { + +} diff --git a/Week 01/id_371/Leetcode_84_371.java b/Week 01/id_371/Leetcode_84_371.java new file mode 100644 index 000000000..c472c7a08 --- /dev/null +++ b/Week 01/id_371/Leetcode_84_371.java @@ -0,0 +1,85 @@ +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-10 16:08 + **/ + +public class Leetcode_84_371 { + + public static void main(String[] args) { + int[] heights = {2, 1, 5, 6, 2, 3}; + int largeArea = largestRectangleArea2(heights); + System.out.println("largeArea = " + largeArea); + } + + /** + * 仿解2:(单调递增栈:栈中保存bar 对应的索引,索引对应的 bar 高度单调递增,这样利用栈非常方便确定当前索引的 bar 往左右延伸最大面积时的边界)方便确定边界==>栈顶的上一元素就是左边界 + * + * @author Shaobo.Qian + * @date 2019/11/10 + */ + public static int largestRectangleArea2(int[] heights) { + Stack stack = new Stack<>(); + //1.设置index=0的 bar 的左边界 + stack.push(-1); + int maxArea = 0; + //2.将所有元素压入栈 + for (int i = 0; i < heights.length; i++) { + while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) { + maxArea = Math.max(maxArea, heights[stack.pop()] * (i - stack.peek() - 1));//i是右边界,栈顶的上一个元素:stack.peek()就是左边界 + } + stack.push(i); + } + //3.减剩下栈中所有元素弹出 + while (stack.peek() != -1) { + maxArea = Math.max(maxArea, heights[stack.pop()] * (heights.length - stack.peek() -1));//heights.length是右边界额额,栈顶的上一个元素:stack.peek()就是左边界 + } + return maxArea; + } + + /** + * 仿解1:jump index + * + * @author Shaobo.Qian + * @date 2019/11/10 + * @link https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhao-liang-bian-di-yi-ge-xiao-yu-ta-de-zhi-by-powc/ + * @link + */ + public static int largestRectangleArea1(int[] heights) { + if (heights == null || heights.length == 0) { + return 0; + } + int count = heights.length;//为 bar 的个数 + int[] lessFromLeft = new int[count]; + int[] lessFromRight = new int[count]; + //设置左右边界 + lessFromLeft[0] = -1; //lessFromLeft[0]即,在第一个bar的位置(currentIndex=0),指针往左出现的第一个比 currentIndex 对应 bar 的高度 矮的 bar 对应的索引,因为 currentIndex = 0对应的为一个 bar,比它还矮的没有了,所以设置为-1(设置为-1符合后面计算rectangle 长度的公式) + lessFromRight[count - 1] = count; //和上面的解释同理 + + for (int currIndex = 1; currIndex < count; currIndex++) { + int preIndex = currIndex - 1; + while (preIndex >= 0 && heights[preIndex] >= heights[currIndex]) { + preIndex = lessFromLeft[preIndex];//lessFromLeft[preIndex]指向的是从当前位置指针向左,第一次出现的比currIndex-1索引对应 bar 高度矮的 bar 对应的索引,索引将它赋值给 preIndex,从而实现 jump index,而不需要将 currIndex 之前的每一个 bar 的高度来和当前 bar 高度比较 + } + lessFromLeft[currIndex] = preIndex; + } + + for (int currIndex = count - 2; currIndex >= 0; currIndex--) { + int nextIndex = currIndex + 1; + while (nextIndex < count && heights[nextIndex] >= heights[currIndex]) { + nextIndex = lessFromRight[nextIndex]; + } + lessFromRight[currIndex] = nextIndex; + } + + //找到每个索引位置向左右延伸能达到的最大面积,依次比较,每次保存更大的 + int maxArea = 0; + for (int i = 0; i < count; i++) { + maxArea = Math.max(maxArea, heights[i] * (lessFromRight[i] - lessFromLeft[i] - 1)); + } + return maxArea; + } +} diff --git a/Week 01/id_401/26.remove-duplicates-from-sorted-array.js b/Week 01/id_401/26.remove-duplicates-from-sorted-array.js index fb954aaa5..1a37f5ec7 100644 --- a/Week 01/id_401/26.remove-duplicates-from-sorted-array.js +++ b/Week 01/id_401/26.remove-duplicates-from-sorted-array.js @@ -2,16 +2,16 @@ * @param {number[]} nums * @return {number} */ -var removeDuplicates = function(nums) { - if(!nums || nums.length<=1) return nums.length; - let temp=nums[0]; - let i=1; - while(i diff --git a/Week 01/id_516/NOTE.md b/Week 01/id_516/NOTE.md index 49c227b89..ed7c6b12a 100644 --- a/Week 01/id_516/NOTE.md +++ b/Week 01/id_516/NOTE.md @@ -68,22 +68,6 @@ 7. 经常忘记查看discuss 1. feedback的感觉不是很强烈 除了有一次看到比较逗比的算法除外 - - - - - - - - - - - - - - - - ## 其他 1. 奇妙算法 diff --git a/Week 01/id_531/leetCode_21_531.go b/Week 01/id_531/leetCode_21_531.go index 12fc33416..18f63698a 100644 --- a/Week 01/id_531/leetCode_21_531.go +++ b/Week 01/id_531/leetCode_21_531.go @@ -1,25 +1,38 @@ - package id531 - - type ListNode struct { - Val int - Next *ListNode - } + Val int + Next *ListNode +} func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { - if l1==nil { + if l1 == nil { return l2 } - if l2 ==nil { + if l2 == nil { return l1 } - if l1.Val deque = new ArrayDeque(); + //deque的queue用法 + deque.offer("1"); //offer继承于queue,先进先出。 +// deque.addFirst("1"); //offer的新api +// deque.offerFirst("1"); + deque.offer("2"); + deque.offer("3"); + deque.offer("4"); + deque.addFirst("0"); + System.out.println(deque); //[1, 2, 3, 4] + deque.pollFirst(); + System.out.println(deque); //[1, 2, 3, 4] + + String polledElement = deque.poll(); // == 1 ,符合queue的先进先出 + System.out.println(polledElement); + System.out.println(deque); //[2, 3, 4] + + String peekElement = deque.peek(); // == 2 (只看不拿) , + System.out.println(peekElement); + System.out.println(deque); //[2, 3, 4] + + while (deque.size()>0){ + System.out.println(deque.poll()); //先进先出 2,3,4 + } + } + + public static void mainDeque(String[] args) { + +// Queue queue = newew + + Deque deque = new LinkedList(); + Deque deque1 = new ArrayDeque(); + //deque的用法 + deque.addLast("1"); // queue的offer = deque的addLast + deque.addLast("2"); + deque.addLast("3"); + deque.addLast("4"); + deque1.isEmpty(); + System.out.println(deque); //[1, 2, 3, 4] + System.out.println(deque.getFirst()); + + String polledElement = deque.pollFirst(); // + System.out.println(polledElement); + System.out.println(deque); //[2, 3, 4] + + String peekElement = deque.peekFirst(); // + System.out.println(peekElement); + System.out.println(deque); //[2, 3, 4] + + while (deque.size()>0){ + System.out.println(deque.pollFirst()); //先进先出 2,3,4 + } + } + + + private static void printElemrnt(Deque deque) { + for (String s: deque){ + System.out.println(s); + } + } +} diff --git a/Week 01/id_541/P42TrappingRainWater.java b/Week 01/id_541/P42TrappingRainWater.java new file mode 100644 index 000000000..c825e78fb --- /dev/null +++ b/Week 01/id_541/P42TrappingRainWater.java @@ -0,0 +1,89 @@ +//给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 +// +// +// +// 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。 +// +// 示例: +// +// 输入: [0,1,0,2,1,0,1,3,2,1,2,1] +//输出: 6 +// Related Topics 栈 数组 双指针 + + +package leetcode.editor.cn; + +import java.util.Stack; + +//Java:接雨水 +//第一周 +public class P42TrappingRainWater{ + public static void main(String[] args) { + Solution solution = new P42TrappingRainWater().new Solution(); + // TO TEST + //解法1.其实就是求低和高的问题,低恒等于1,然后本题则演变成求高的问题 ,时间复杂度 0(n) + //解法2.将每个位置i的面积累加,该位置i是否有面积,则根据他的左右邻高度确定,时间复杂度 0(n) + //这个思路进一步优化,可以考虑为,i节点的左右最近哥哥(比i高的为哥哥)高的问题 + +// int[] aa = new int[]{0,1,0,2,1,0,1,3,2,1,2,1}; + int[] aa = new int[]{2,1,0,2}; + System.out.println(solution.trap(aa)); + } + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int trap(int[] height) { +// Stack stack = new Stack(); +// stack.push(height[0]); + //[0,1,0,2,1,0,1,3,2,1,2,1] + //[2,1,0,2] + //[4,2,3] + int maxLeft = 0,maxRight = 0,minHeight = 0; + int area = 0; + int length = height.length; + if (length == 0){ + return 0; + } + maxRight = maxRight(0,height);; + for (int i = 1; i < length - 1; i++) { + if (maxRight <= i){ + maxRight = maxRight(i,height); + } + maxLeft = maxLeft(i,height); + minHeight = Math.min(height[maxLeft],height[maxRight]); + if (minHeight >= height[i]){ + area += minHeight -height[i]; + } + } + return area; + } + + + private int maxRight(int index,int[] height){ + int maxValue = 0; + int maxIndex = 0; + for (int i = index+1; i < height.length; i++) { + if (i < height.length && maxValue <= height[i] ){ + maxValue = height[i]; + maxIndex= i; + } + } + return maxIndex; + } + + private int maxLeft(int index,int[] height){ + int maxValue = 0; + int maxIndex = 0; + for (int i = index - 1; i >= 0; i--) { + if (i >= 0 && maxValue <= height[i] ){ + maxValue = height[i]; + maxIndex= i; + } + } + return maxIndex; + } +} +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 01/id_541/P641DesignCircularDeque.java b/Week 01/id_541/P641DesignCircularDeque.java new file mode 100644 index 000000000..e88844baa --- /dev/null +++ b/Week 01/id_541/P641DesignCircularDeque.java @@ -0,0 +1,153 @@ +//设计实现双端队列。 +//你的实现需要支持以下操作: +// +// +// MyCircularDeque(k):构造函数,双端队列的大小为k。 +// insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +// insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +// deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +// deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +// getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +// getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +// isEmpty():检查双端队列是否为空。 +// isFull():检查双端队列是否满了。 +// +// +// 示例: +// +// MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 +//circularDeque.insertLast(1); // 返回 true +//circularDeque.insertLast(2); // 返回 true +//circularDeque.insertFront(3); // 返回 true +//circularDeque.insertFront(4); // 已经满了,返回 false +//circularDeque.getRear(); // 返回 2 +//circularDeque.isFull(); // 返回 true +//circularDeque.deleteLast(); // 返回 true +//circularDeque.insertFront(4); // 返回 true +//circularDeque.getFront(); // 返回 4 +//  +// +// +// +// 提示: +// +// +// 所有值的范围为 [1, 1000] +// 操作次数的范围为 [1, 1000] +// 请不要使用内置的双端队列库。 +// +// Related Topics 设计 队列 + +package leetcode.editor.cn; + +import java.lang.reflect.Array; + +//https://leetcode-cn.com/problems/design-circular-deque/solution/641-she-ji-xun-huan-shuang-duan-dui-lie-by-alexer-/ +//Java:设计循环双端队列 +public class P641DesignCircularDeque { + public static void main(String[] args) { + MyCircularDeque solution = new P641DesignCircularDeque().new MyCircularDeque(10); + // TO TEST + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class MyCircularDeque { + + + private int[] objects; + private int head; + private int tail; + private int MAX_SIZE; + private int count; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + objects = new int[k]; + head = tail = -1; + MAX_SIZE = k; + count = 0; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (isFull()) return false; + head = (head - 1 + MAX_SIZE) % MAX_SIZE; + objects[head] = value; + count++; + if (count == 1) { + tail = head; + } + return true; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (isFull()) return false; + tail = (tail + 1) % MAX_SIZE; + objects[tail] = value; + count++; + if (count == 1) { + head = tail; + } + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (isEmpty()) return false; + head = (head + 1) % MAX_SIZE; + count--; + return true; + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (isEmpty()) return false; + tail = (tail - 1 + MAX_SIZE) % MAX_SIZE; + count--; + return true; + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (isEmpty()) return -1; + return objects[head]; + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (isEmpty()) return -1; + return objects[tail]; + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return count == 0; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return count == MAX_SIZE; + } + + } +} \ No newline at end of file diff --git "a/Week 01/id_541/\347\254\254\344\270\200\345\221\250Queue,PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/Week 01/id_541/\347\254\254\344\270\200\345\221\250Queue,PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" new file mode 100644 index 000000000..79dd874a9 --- /dev/null +++ "b/Week 01/id_541/\347\254\254\344\270\200\345\221\250Queue,PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -0,0 +1,41 @@ +1. + 本来对queue持有很清晰的印象,但是随着接触的越来越多,反倒是越模糊 + + 首先,在我的死记硬背中,队列属于线性结构,但是至于是连续性还是非连续性,这个就要另当别论了。因为接口只规范功能,不限制属性。而属性才是判断线性还是非线性的依据。下面来分析一下: + + Queue是一个接口,其子接口有Deque,(注意是有且不仅有的关系,莫要混淆) + Queue有自己的实现类,比如ArrayQueue,PriorityQueue,TaskQueue等等,他们内部是持有一个数组容器进行操作的,所以这个队列算是连续性线性结构。 + 当然了,Queue有别的子接口的实现类,比如接口BlockingQueue的实现类LinkedBlockingDeque等等,这个实现类内部则持有一个结点类型的数据结构,那么这时候他就是非连续的线性(一维)结构 + 至于别的案例,有时间自己仔细看看,会发现天下大同 + + queue的方法: + add + offer + remove + poll + element + peek + +2. + PriorityQueue + 集成Queue,所以queue该有的方法他也有。 + 但是属性里面,多了一个很特殊的Comparator,也因此衍生出了很多函数,都用于和优先级有关。 + 和Queue不同的是,他是一个类,集成了AbstractQueue。 + DelayQueue的操作就是基于PriorityQueue的。 + + PriorityBlockingQueue 持有PriorityQueue的引用,同时内部也含有一个Comparator. + 这个以后在研究 + + +3. 写完1,2后,我开始补写代码作业,设计循环双端队列。 + 初始的时候,很迷惑,因为对jdk自带的Deque了解的没有那么彻底,导致我的思路一致卡在了怎么设计一个和Deque一样的数据结构。这时候的思想还停留在模仿造车,但是模仿的前提是要对模仿对象足够了解。 + 自己也看了Deque的源码,对每个函数都能理解,但是真的要融会贯通,做到能跳出当局者的角度去思考这样的高度,还差火候。 + + 后来很纠结的时候,开始多次读题,终于发现自己不小心进了牛角尖,原来我不需要去照着Deque写,我只需要满足题目的条件就可以,对着题目的案例很容易就能理解循环双端这个结构。同理,学习jdk自带的deque的时候,也要用demo带入学习i即可。 + + 按照题目的意思,他们来不同的在于。jdk自带的支持grow,而本题目不需要支持。对着题目给的案例,去写,就会觉得思路很清晰。 + + + + + \ No newline at end of file diff --git a/Week 01/id_661/LeetCode_189_661.py b/Week 01/id_661/LeetCode_189_661.py new file mode 100644 index 000000000..38cd7fd0f --- /dev/null +++ b/Week 01/id_661/LeetCode_189_661.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3.7 +class Solution: + def rotate(self, nums, k): + n = len(nums) + k %= n + if k: + self.numsReverse(nums, 0, n - 1) + self.numsReverse(nums, 0, k - 1) + self.numsReverse(nums, k, n - 1) + return nums + + def numsReverse(self, nums, start, end): + while start < end: + nums[start], nums[end] = nums[end], nums[start] + start += 1 + end -= 1 + return + + +test = [1, 2, 3, 4, 5, 6, 7, 8] +print(Solution().rotate(test, 3)) diff --git a/Week 01/id_661/LeetCode_1_661.py b/Week 01/id_661/LeetCode_1_661.py new file mode 100644 index 000000000..124ada3de --- /dev/null +++ b/Week 01/id_661/LeetCode_1_661.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def twoSum(self, nums, target): + dct = {} + for k, v in enumerate(nums): + if target - v in dct: + return [dct[target - v], k] + dct[v] = k + return [] + + +nums = [2, 7, 11, 15] +print(Solution().twoSum(nums, 9)) diff --git a/Week 01/id_661/LeetCode_21_661.py b/Week 01/id_661/LeetCode_21_661.py new file mode 100644 index 000000000..661ab94bd --- /dev/null +++ b/Week 01/id_661/LeetCode_21_661.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def mergeTwoLists(self, l1, l2): + if l1 and l2: + if l1.val > l2.val: + l1, l2 = l2, l1 + l1.next = self.mergeTwoLists(l1.next, l2) + return l1 or l2 diff --git a/Week 01/id_661/LeetCode_26_661.py b/Week 01/id_661/LeetCode_26_661.py new file mode 100644 index 000000000..2317623e7 --- /dev/null +++ b/Week 01/id_661/LeetCode_26_661.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3.7 +class Solution: + def removeDuplication(self, nums): + if not nums: + return 0 + j = 1 + for i in range(1, len(nums)): + if nums[i] != nums[i - 1]: + nums[j] = nums[i] + j += 1 + return j + + +nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] +print(Solution().removeDuplication(nums)) diff --git a/Week 01/id_661/LeetCode_283_661.py b/Week 01/id_661/LeetCode_283_661.py new file mode 100644 index 000000000..2c8159b90 --- /dev/null +++ b/Week 01/id_661/LeetCode_283_661.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3.7 + + +class Solution: + """ + Don't return anything, modify nums in-place instead. + """ + + def moveZeros(self, nums): + zero = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[zero], nums[i] = nums[i], nums[zero] + zero += 1 + + def test_case(self, nums): + self.moveZeros(nums) + return nums + + +test = [0, 1, 0, -1, 4, 0, 6] +print(Solution().test_case(test)) diff --git a/Week 01/id_661/LeetCode_66_661.py b/Week 01/id_661/LeetCode_66_661.py new file mode 100644 index 000000000..ec04f94b2 --- /dev/null +++ b/Week 01/id_661/LeetCode_66_661.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def plusOne(self, digits): + n = len(digits) - 1 + return self._plusOne(digits, n) + + def _plusOne(self, nums, n): + if not nums[n] < 9: + nums[n] = (nums[n] + 1) % 10 + if n == 0: + nums.insert(0, 1) + else: + self._plusOne(nums, n - 1) + else: + nums[n] += 1 + + return nums + + +test = [9, 9] +print(Solution().plusOne(test)) diff --git a/Week 01/id_661/LeetCode_88_661.py b/Week 01/id_661/LeetCode_88_661.py new file mode 100644 index 000000000..99f80b2cf --- /dev/null +++ b/Week 01/id_661/LeetCode_88_661.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3.7 +class Solution: + def merge(self, nums1, m, nums2, n): + nums1[m:] = nums2[:n] + nums1.sort() + + +t1 = [1, 2, 3, 4, 5, 0, 0, 0] +m = 5 +t2 = [3, 4, 5] +n = 3 +Solution().merge(t1, m, t2, n) +print(t1) diff --git "a/Week 01/id_766/66.\345\212\240\344\270\200.java" "b/Week 01/id_766/66.\345\212\240\344\270\200.java" deleted file mode 100644 index f80bd1d66..000000000 --- "a/Week 01/id_766/66.\345\212\240\344\270\200.java" +++ /dev/null @@ -1,22 +0,0 @@ -/* - * @lc app=leetcode.cn id=66 lang=java - * - * [66] 加一 - */ - -// @lc code=start -class Solution { - public int[] plusOne(int[] digits) { - for (int i = digits.length - 1; i >=0; i--) { - digits[i]++; - digits[i] = digits[i] % 10; - if (digits[i] != 0) return digits; - } - digits = new int[digits.length + 1]; - digits[0] = 1; - return digits; - - } -} -// @lc code=end - diff --git a/Week 02/id_021/algorithm/build.gradle b/Week 02/id_021/algorithm/build.gradle index 79485fe34..3881c13e1 100644 --- a/Week 02/id_021/algorithm/build.gradle +++ b/Week 02/id_021/algorithm/build.gradle @@ -9,8 +9,6 @@ group = 'com.lqw' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' -def nexusUrl = 'http://nexus.webuy.ai/nexus/content/groups/public/' - repositories { maven { name 'eleph-repository' diff --git a/Week 02/id_026/InorderTraversal.java b/Week 02/id_026/InorderTraversal.java new file mode 100644 index 000000000..3ae7831bb --- /dev/null +++ b/Week 02/id_026/InorderTraversal.java @@ -0,0 +1,16 @@ +// 中序遍历 +public class InorderTraversal { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + private void helper(TreeNode root, List res) { + if (root == null) return; + helper(root.left, res); + res.add(root.val); + helper(root.right, res); + } + +} diff --git a/Week 02/id_026/IsAnagram.java b/Week 02/id_026/IsAnagram.java new file mode 100644 index 000000000..40c0ba3bf --- /dev/null +++ b/Week 02/id_026/IsAnagram.java @@ -0,0 +1,28 @@ +package com.abc.week02; + +// 字母异位词 +public class IsAnagram { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i) - 'a']++; + counter[t.charAt(i) - 'a']--; + } + for (int i = 0; i < counter.length; i++) { + if (counter[i] != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + String a = "anagram"; + String b = "nagaram"; + IsAnagram anagram = new IsAnagram(); + System.out.println(anagram.isAnagram(a, b)); + } +} diff --git a/Week 02/id_026/TwoSum.java b/Week 02/id_026/TwoSum.java new file mode 100644 index 000000000..0fb56abb9 --- /dev/null +++ b/Week 02/id_026/TwoSum.java @@ -0,0 +1,30 @@ +package com.abc.week02; + +import java.util.HashMap; +import java.util.Map; + +//两数之和 +public class TwoSum { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + map.put(nums[i], i); + } + + for (int i = 0; i < nums.length; i++) { + int temp = target - nums[i]; + if (map.containsKey(temp) && map.get(temp) != i) { + return new int[]{i,map.get(temp)}; + } + } + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args) { + TwoSum twoSum = new TwoSum(); + int[] nums = new int[]{2, 7, 11, 15}; + int target = 9; + twoSum.twoSum(nums, target); + + } +} diff --git a/Week 02/id_091/LeetCode_242_091.py b/Week 02/id_091/LeetCode_242_091.py index c6e0a0f3d..0d14e7d34 100644 --- a/Week 02/id_091/LeetCode_242_091.py +++ b/Week 02/id_091/LeetCode_242_091.py @@ -5,25 +5,29 @@ def isAnagram(self, s: str, t: str) -> bool: dic1[item] = dic1.get(item, 0) + 1 for item in t: dic2[item] = dic2.get(item, 0) + 1 + #print(dic1, dic2) {'a': 3, 'n': 1, 'g': 1, 'r': 1, 'm': 1} {'n': 1, 'a': 3, 'g': 1, 'r': 1, 'm': 1} return dic1 == dic2 + def isAnagram2(self, s, t): + dic1, dic2 = [0] * 26, [0] * 26 + print(dic1, dic2) + for item in s: + dic1[ord(item) - ord('a')] += 1 + for item in t: + dic2[ord(item) - ord('a')] += 1 + #print(dic1, dic2) [3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] [3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] + print(dic1, dic2) + return dic1 == dic2 -def isAnagram2(self, s, t): - dic1, dic2 = [0] * 26, [0] * 26 - for item in s: - dic1[ord(item) - ord('a')] += 1 - for item in t: - dic2[ord(item) - ord('a')] += 1 - return dic1 == dic2 - + def isAnagram3(self, s, t): + #print(sorted(s), sorted(t))['a', 'a', 'a', 'g', 'm', 'n', 'r'] ['a', 'a', 'a', 'g', 'm', 'n', 'r'] -def isAnagram3(self, s, t): - return sorted(s) == sorted(t) + return sorted(s) == sorted(t) if __name__ == '__main__': - s = "anagram" - t = "nagaram" + s = "a" + t = "n" solution = Solution() - res = solution.isAnagram(s, t) + res = solution.isAnagram2(s, t) print(res) diff --git a/Week 02/id_111/NOTE.md b/Week 02/id_111/NOTE.md index bc95be083..310abba51 100644 --- a/Week 02/id_111/NOTE.md +++ b/Week 02/id_111/NOTE.md @@ -89,3 +89,66 @@ HashMap 小总结 ## 前中后序遍历 ## leetcode 题目 +# 递归的实现、特性、 +## 理论部分 + 树的面试题解法一般是递归 +### 递归的本质是循环 +- 循环体调用自身 +- 类比《盗梦空间》 + - 向下进入不同梦境,向上回到上一层 + - 每层之间相互独立 + - 可以穿越梦境的主角类似于参数 + - 简单递归形式 + - 求阶乘 n! + - n! = 1*2*3*4*5...*n + - 代码实现 + def Factorial(n): if n <= 1: return 1 return 1​ n* Factorial(n -1 )​​​ + - 递归栈 +- 递归注意点 + 1. 不要人肉递归(画递归图辅助理解,入门可使用,进阶需抛弃,直接看函数) + 2. 找最近重复子问题 + 3. 数学归纳法 + 1 成立、2 成立 ,同时可证明n成立 n+成立 + 4. 机械化记忆递归代码模板 +## 算法题 +- 爬楼梯 +- 找最近重复性 +- 思考到三级台阶时,考虑重复性问题,否则陷入人肉递归 + f(3)=f(1)+f(2) + f(n)=f(n-1)+f(n-2) + mutual exclusive | complete exhaustive + 括号生成 + https://leetcode-cn.com/problems/generate-parentheses/ + +# 分治 Divide & Conque + 本质就是递归,找重复性,递归为多个子问题 +- 分治代码模板 + 泛型递归模板(类似) + 回溯 Backtracking + +- leecode 22 生成括号 + - 暴力回溯 +建立完六层,最后发现不可行,去掉,再回到前一层 +分治、回溯习题 +leecode 50 Pow(x,n) **高频** + - 暴力法: +for 循环n 次,得到x的n次方 +时间复杂度为O(n) + - 分治 +- 递归模板: + 1. terminator 终结条件 + 2. process(split your big problem) + 3. drill down (subproblems),merge (subresult) + 4. reserve states +- pow(x,n) + - subproblem : subresult = pow(x,n/2) + - merge: +判断奇偶,进行处理(考虑负数问题,若负数,取其绝对值进行判断 +if n % 2 ==1: result = subresult * subresult *xelse result = ​​​ subresult * subresult +时间复杂度 O(logn) + - 快速幂法 + - 牛顿迭代 +- leetcode 78.子集 +写过排列组合再看此题 + + diff --git a/Week 02/id_111/leetcode_1_111.py b/Week 02/id_111/leetcode_1_111.py index b840366d6..14fb8b1b4 100644 --- a/Week 02/id_111/leetcode_1_111.py +++ b/Week 02/id_111/leetcode_1_111.py @@ -16,38 +16,20 @@ def twoSum(self, nums: List[int], target: int) -> List[int]: if nums[i] == target - nums[j]: return i,j #哈希表法: -方法二:两遍哈希表 -为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。 -如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表。 +#字典模拟哈希 -通过以空间换取速度的方式,我们可以将查找时间从 O(n)O(n) 降低到 O(1)O(1)。 -哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。 -我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)O(n)。 -但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)O(1)。 - -一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。 -然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i]target−nums[i])是否存在于表中。 -注意,该目标元素不能是 nums[i]nums[i] 本身! - -Java -class Solution { - public int[] twoSum(int[] nums, int target) { - Map map = new HashMap<>(); - for (int i = 0; i < nums.length; i++) { - map.put(nums[i], i); - } - for (int i = 0; i < nums.length; i++) { - int complement = target - nums[i]; - if (map.containsKey(complement) && map.get(complement) != i) { - return new int[] { i, map.get(complement) }; - } - } - throw new IllegalArgumentException("No two sum solution"); - } -} - -复杂度分析: +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + _dict = {}#定义空字典 + for i, m in enumerate(nums): + _dict[m] = i#i值赋给下标 + for i, m in enumerate(nums): + j = _dict.get(target - m) #在哈希表中匹配出目标值 + if j is not None and i != j: + return [i, j]#如果目标值不等于初始值自身 则返回 + #return [_dict.get(target - m), i] + 时间复杂度:O(n)O(n), 我们把包含有 nn 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1)O(1) ,所以时间复杂度为 O(n)O(n)。 diff --git a/Week 02/id_111/leetcode_242_1111.py b/Week 02/id_111/leetcode_242_1111.py new file mode 100644 index 000000000..d076f6959 --- /dev/null +++ b/Week 02/id_111/leetcode_242_1111.py @@ -0,0 +1,17 @@ +#给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + +#解法 1 +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + # 定义默认布尔值参与后续运算 + result = True + # 利用 Python 数据结构 set 去重去序 + set_tmp = set(s) + # 先判断组成字符串的各个字符元素是否一致 + if set_tmp == set(t): + for i in set_tmp: + # 利用逻辑运算符判断各个字符元素的数量一致,均为 True 才输出 True + result = result and (s.count(i) == t.count(i)) + else: + result = False + return (result) \ No newline at end of file diff --git "a/Week 02/id_116/[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.py" "b/Week 02/id_116/[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.py" new file mode 100644 index 000000000..e763c983c --- /dev/null +++ "b/Week 02/id_116/[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.py" @@ -0,0 +1,46 @@ +#给定一个二叉树,返回它的 前序 遍历。 +# +# 示例: +# +# 输入: [1,null,2,3] +# 1 +# \ +# 2 +# / +# 3 +# +#输出: [1,2,3] +# +# +# 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +# Related Topics 栈 树 + + + +#leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + + +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + ret = [] + stack = [root] + while stack: + node = stack.pop() + if node: + ret.append(node.val) + stack.append(node.right) + stack.append(node.left) + return ret + + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 02/id_116/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" "b/Week 02/id_116/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..8dc431d13 --- /dev/null +++ "b/Week 02/id_116/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,40 @@ +#给定一个 N 叉树,返回其节点值的前序遍历。 +# +# 例如,给定一个 3叉树 : +# +# +# +# +# +# +# +# 返回其前序遍历: [1,3,5,6,2,4]。 +# +# +# +# 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 + + + +#leetcode submit region begin(Prohibit modification and deletion) +""" +# Definition for a Node. +class Node(object): + def __init__(self, val, children): + self.val = val + self.children = children +""" +class Solution(object): + def preorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + ret, q = [], root and [root] + while q: + node = q.pop() + ret.append(node.val) + q += [child for child in node.children[::-1] if child] + return ret + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 02/id_116/[590]N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" "b/Week 02/id_116/[590]N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..33e111232 --- /dev/null +++ "b/Week 02/id_116/[590]N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,44 @@ +#给定一个 N 叉树,返回其节点值的后序遍历。 +# +# 例如,给定一个 3叉树 : +# +# +# +# +# +# +# +# 返回其后序遍历: [5,6,3,2,4,1]. +# +# +# +# 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 + + + +#leetcode submit region begin(Prohibit modification and deletion) +""" +# Definition for a Node. +class Node(object): + def __init__(self, val, children): + self.val = val + self.children = children +""" +class Solution(object): + def postorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + res = [] + if root == None: return res + + stack = [root] + while stack: + curr = stack.pop() + res.append(curr.val) + stack.extend(curr.children) + + return res[::-1] + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 02/id_116/[77]\347\273\204\345\220\210.py" "b/Week 02/id_116/[77]\347\273\204\345\220\210.py" new file mode 100644 index 000000000..654d32180 --- /dev/null +++ "b/Week 02/id_116/[77]\347\273\204\345\220\210.py" @@ -0,0 +1,31 @@ +#给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 +# +# 示例: +# +# 输入: n = 4, k = 2 +#输出: +#[ +# [2,4], +# [3,4], +# [2,3], +# [1,2], +# [1,3], +# [1,4], +#] +# Related Topics 回溯算法 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + if k == 0: + return [[]] + return [pre + [i] for i in range(k, n+1) for pre in self.combine(i-1, k-1)] + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 02/id_156/105_java.java b/Week 02/id_156/105_java.java new file mode 100644 index 000000000..39e196fee --- /dev/null +++ b/Week 02/id_156/105_java.java @@ -0,0 +1,38 @@ +class Solution { + int[] preOrder; + int[] inOrder; + int preIndex = 0; + + HashMap array2Dict = new HashMap<>(); + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.inOrder = inorder; + this.preOrder = preorder; + int index = 0; + + for (Integer val : inorder) { + array2Dict.put(val,index); + index++; + } + return BuildTree(0, inorder.length); + } + + /* 递归调用--构建树 */ + private TreeNode BuildTree(int left, int right) { + //terminator + if (left >= right) { + return null; + } + //process + int rootVal = preOrder[preIndex]; + TreeNode root = new TreeNode(rootVal); + preIndex++; + + int rootIndex = array2Dict.get(rootVal); + + root.left = BuildTree(left, rootIndex); + root.right = BuildTree(rootIndex + 1, right); + + return root; + } +} diff --git a/Week 02/id_156/236_java.java b/Week 02/id_156/236_java.java new file mode 100644 index 000000000..3f69c612a --- /dev/null +++ b/Week 02/id_156/236_java.java @@ -0,0 +1,36 @@ +class Solution { + private TreeNode ans; + + public Solution() { + this.ans = null; + } + + private Boolean reverseTree(TreeNode root, TreeNode p, TreeNode q) { + int mid = 0; + int right = 0; + int left = 0; + + if (null == root) { + return false; + } + + if (root.val == p.val || root.val == q.val) { + mid++; + } + + right = this.reverseTree(root.right, p, q) ? 1 : 0; + left = this.reverseTree(root.left, p, q) ? 1 : 0; + + if (mid + right + left > 1) { + this.ans = root; + } + + return (mid + right+ left) > 0; + } + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + //递归处理 + this.reverseTree(root, p, q); + return this.ans; + } +} diff --git a/Week 02/id_181/105.construct-binary-tree-from-preorder-and-inorder-traversal.py b/Week 02/id_181/105.construct-binary-tree-from-preorder-and-inorder-traversal.py index 9d93fea4c..9d463ad02 100644 --- a/Week 02/id_181/105.construct-binary-tree-from-preorder-and-inorder-traversal.py +++ b/Week 02/id_181/105.construct-binary-tree-from-preorder-and-inorder-traversal.py @@ -1 +1,9 @@ -# [Python 递归详解 - 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal) \ No newline at end of file +# [Python 递归详解 - 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal) + +# 前序遍历第一个元素是根节点,后序遍历 该节点所在位置的左侧为左子树,右侧为右子树 + +# [3,9,20,15,7] + +# [9,3,15,20,7] + +# 3 [9] [15,20,7] \ No newline at end of file diff --git a/Week 02/id_251/LeetCode_226_251.py b/Week 02/id_251/LeetCode_226_251.py index 9f3d51eb7..cfd4c6c25 100644 --- a/Week 02/id_251/LeetCode_226_251.py +++ b/Week 02/id_251/LeetCode_226_251.py @@ -35,7 +35,7 @@ """ 1 递归 -2 栈 迭代 +2 栈 迭代 BFS """ diff --git a/Week 02/id_251/LeetCode_98_251.py b/Week 02/id_251/LeetCode_98_251.py index f33c54aaa..b5b469a7c 100644 --- a/Week 02/id_251/LeetCode_98_251.py +++ b/Week 02/id_251/LeetCode_98_251.py @@ -42,8 +42,8 @@ """ 1 递归 -2 中序遍历 -3 stack +2 中序遍历 为升序 +3 stack 用栈实现计算机的递归函数调用的底层调用栈 """ @@ -57,15 +57,7 @@ def isValidBST(self, root): def valid(node, lower, upper): if not node: return True - """ - if not (lower < node.val < upper): - return False - if not valid(node.left, lower, node.val): - return False - if not valid(node.right, node.val, upper): - return False - return True - """ + return lower < node.val < upper and valid(node.left, lower, node.val) and valid(node.right, node.val, upper) return valid(root, float('-inf'), float('inf')) @@ -105,8 +97,7 @@ def isValidBST(self, root): # 另一种写法 def isValidBST_(self, root): - stack = [] - pre = None + stack, pre = [], None while stack or root: while root: stack.append(root) diff --git a/Week 02/id_256/LeetCode_169_256.js b/Week 02/id_256/LeetCode_169_256.js new file mode 100644 index 000000000..0cf1f37ec --- /dev/null +++ b/Week 02/id_256/LeetCode_169_256.js @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=169 lang=javascript + * + * [169] 求众数 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var majorityElement = function(nums) { + // 暴力 + // let num_map = {}; + // for (let i = 0; i < nums.length; i++) { + // if(num_map[nums[i]] == undefined) { + // num_map[nums[i]] = 0; + // } + // num_map[nums[i]]++; + // if(num_map[nums[i]] > nums.length / 2) { + // return nums[i]; + // } + // } + // 排序 + // nums.sort(); + // return nums[Math.floor(nums.length/2)] + // Boyer-Moore 投票算法 + let candidate = -1; + let count = 0; + for (let key in nums) { + if (count == 0) { + candidate = nums[key]; + } + count += candidate == nums[key] ? 1 : -1; + } + return candidate; +}; +// @lc code=end diff --git a/Week 02/id_256/LeetCode_17_256.js b/Week 02/id_256/LeetCode_17_256.js new file mode 100644 index 000000000..b98d5a15a --- /dev/null +++ b/Week 02/id_256/LeetCode_17_256.js @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=17 lang=javascript + * + * [17] 电话号码的字母组合 + */ + +// @lc code=start +/** + * @param {string} digits + * @return {string[]} + */ +var letterCombinations = function(digits) { + //回溯 + if(!digits) return []; + let letters_map = ['','','abc','def','ghi','jkl','mno','qprs','tuv','wxyz']; + let res = []; + dfs(res, digits, letters_map, ''); + return res; +}; +let dfs = function(res, digits, letters_map, tmp) { + if (tmp.length == digits.length) { + res.push(tmp); + return; + } + let currLetters = letters_map[parseInt(digits[tmp.length])]; + for (let i = 0; i < currLetters.length; i++) { + tmp = tmp + currLetters[i]; + dfs(res, digits, letters_map, tmp); + tmp = tmp.substring(0, tmp.length - 1); + } +} +// @lc code=end + diff --git a/Week 02/id_256/LeetCode_236_256.js b/Week 02/id_256/LeetCode_236_256.js new file mode 100644 index 000000000..3fcb17109 --- /dev/null +++ b/Week 02/id_256/LeetCode_236_256.js @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=236 lang=javascript + * + * [236] 二叉树的最近公共祖先 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function(root, p, q) { + this.node = null; + recursionTree(root, q, p); + return this.node; + }; + let recursionTree = function(node, p, q) { + if (!node) return false; + let left = recursionTree(node.left, p, q) ? 1 : 0; + let right = recursionTree(node.right, p, q) ? 1 : 0; + let mid = (node == p || node == q) ? 1 : 0; + if (left + right + mid >= 2) { + this.node = node; + } + return (left + right + mid > 0); + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 02/id_256/LeetCode_50_256.js b/Week 02/id_256/LeetCode_50_256.js new file mode 100644 index 000000000..a37eaa89b --- /dev/null +++ b/Week 02/id_256/LeetCode_50_256.js @@ -0,0 +1,57 @@ +/* + * @lc app=leetcode.cn id=50 lang=javascript + * + * [50] Pow(x, n) + */ + +// @lc code=start +/** + * @param {number} x + * @param {number} n + * @return {number} + */ +var myPow = function(x, n) { + //暴力 + // if(n == 0) return 1; + // let result = x; + // let temp = n; + // if(n < 0) { + // temp = Math.abs(n); + // } + // while(temp > 1) { + // result *= x; + // temp--; + // } + // return n < 0 ? 1/result : result; + // 暴力二 + // if(n == 0) return 1; + // let N = n; + // if(n < 0) { + // N = -n; + // x = 1 / x; + // } + // let result = 1; + // for (let i = 0; i < N; i++) { + // result *= x; + // } + // return result; + // 快递递归幂 + if (n < 0) { + n = -n; + x = 1 / x; + } + return fastPow(x, n); + }; + var fastPow = function(x, n) { + if (n == 0) { + return 1; + } + let half = fastPow(x, parseInt(n / 2)); + if (n % 2 == 0) { + return half * half; + } else { + return half * half * x; + } + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 02/id_261/leetcode_105_261.go b/Week 02/id_261/leetcode_105_261.go new file mode 100644 index 000000000..d4c27b506 --- /dev/null +++ b/Week 02/id_261/leetcode_105_261.go @@ -0,0 +1,31 @@ +// leetcode - https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var inPos map[int]int +func buildTree(preorder []int, inorder []int) *TreeNode { + inPos = make(map[int]int) + for i := 0; i < len(inorder); i++ { + inPos[inorder[i]] = i + } + return helper(preorder, 0, len(preorder) - 1, 0) +} + + +func helper(pre []int, preLeft, preRight, inStart int) *TreeNode { + if preLeft > preRight { + return nil + } + root := &TreeNode{Val: pre[preLeft]} + rootIndex := inPos[pre[preLeft]] + leftLen := rootIndex - inStart + root.Left = helper(pre, preLeft + 1, preLeft + leftLen, inStart) + root.Right = helper(pre, preLeft + leftLen + 1, preRight, rootIndex + 1) + return root +} \ No newline at end of file diff --git a/Week 02/id_261/leetcode_236_261.go b/Week 02/id_261/leetcode_236_261.go new file mode 100644 index 000000000..8c7329749 --- /dev/null +++ b/Week 02/id_261/leetcode_236_261.go @@ -0,0 +1,32 @@ +// leetcode - https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree + +/** + * Definition for TreeNode. + * type TreeNode struct { + * Val int + * Left *ListNode + * Right *ListNode + * } + */ +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + if root == nil { + return nil + } + if root == p || root == q { + return root + } + x1, x2 := lowestCommonAncestor(root.Left, p, q), lowestCommonAncestor(root.Right, p, q) + if x1 != nil && x2 != nil { + return root + } + if (x1 != nil || x2 != nil) && (root == p || root == q) { + return root + } + if x1 != nil { + return x1 + } + if x2 != nil { + return x2 + } + return nil +} diff --git a/Week 02/id_281/LeetCode_105_281.java b/Week 02/id_281/LeetCode_105_281.java new file mode 100644 index 000000000..b790e4160 --- /dev/null +++ b/Week 02/id_281/LeetCode_105_281.java @@ -0,0 +1,59 @@ +import java.util.HashMap; +import java.util.Map; + +import javax.management.RuntimeErrorException; +import javax.swing.tree.TreeNode; + +/* + * @lc app=leetcode.cn id=105 lang=java + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + // 内层O(n)的查找,可以通过hash表降为O(1) + private int[] preorder; + private Map hash; + + public TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder.length != inorder.length) { + throw new RuntimeException("Incorrect input data."); + } + + this.preorder = preorder; + this.hash = new HashMap<>(); + for (int i = 0; i < inorder.length; i++) { + this.hash.put(inorder[i], i); + } + + return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); + } + + private TreeNode buildTree(int[] preodrder, int preLeft, int preRight, int[] inorder, int inLeft, int inRight) { + if (preLeft > preRight || inLeft > inRight) { + return null; + } + + int pivot = preodrder[preLeft]; + TreeNode root = new TreeNode(pivot); + int pivotIndex = hash.get(pivot); + + // while (inorder[pivotIndex] != pivot) { + // pivotIndex++; + // } + root.left = buildTree(preodrder, preLeft + 1, preLeft + pivotIndex - inLeft, inorder, inLeft, pivotIndex-1); + root.right = buildTree(preodrder, preLeft + pivotIndex - inLeft + 1, preRight, inorder, pivotIndex + 1, inRight); + return root; + } +} \ No newline at end of file diff --git a/Week 02/id_281/LeetCode_236_281.java b/Week 02/id_281/LeetCode_236_281.java new file mode 100644 index 000000000..19776f596 --- /dev/null +++ b/Week 02/id_281/LeetCode_236_281.java @@ -0,0 +1,57 @@ +/* + * @lc app=leetcode.cn id=236 lang=java + * + * [236] 二叉树的最近公共祖先 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + private TreeNode ans; + + public Solution() { + this.ans = null; + } + + private boolean recurseTree (TreeNode currentNode, TreeNode p, TreeNode q) { + if (currentNode == null) { + return false; + } + + int left = this.recurseTree(currentNode.left, p, q) ? 1 : 0; + int right = this.recurseTree(currentNode.right, p, q) ? 1 : 0; + + int mid = (currentNode == p || currentNode == q) ? 1 : 0; + + if (mid + left + right >= 2) { + this.ans = currentNode; + } + + return (mid + left + right > 0); + } + + // 回溯 + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + this.recurseTree(root, p, q); + return this.ans; + } + + + 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); + + return left == null ? right : right == null ? left : root; + } +} \ No newline at end of file diff --git a/Week 02/id_281/NOTE.md b/Week 02/id_281/NOTE.md index a6321d6e2..41957567c 100644 --- a/Week 02/id_281/NOTE.md +++ b/Week 02/id_281/NOTE.md @@ -1,4 +1,72 @@ -# NOTE +### 第二周学习总结 +* hash表具有O(1)的查找时间复杂度,在遍历时间复杂度为O(n)时,可以考虑用hash表来代替遍历查找。 +* hash表存在hash碰撞的情况,采用链表来处理,根据性能可改为红黑树实现。 +#### 切题四件套回顾 +* clarification +* possible solutions --> optimal(time&space) +* code +* test case + +#### 遍历树 +* 前序遍历 +* 中序遍历 +* 后序遍历 + +### 递归模板 +```python +def recursion(level, param1, param2,...): + # recursion terminator + if level > MAX_LEVEL: + process_result + return + + # process logic in current level + process(level, data, ...) + + #dirll down + self.recursion(level + 1, p1, ...) + + # reverse the current level status if needed +``` + +#### 思维要点 +* 不要进行人肉递归 (最大误区) +* 找到最近最简方法,将其拆解成可重复解决的子问题 +* 数学归纳法思维 + + +### 分治模板 +```python +def divide_conquer(problem, parma1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[0], p1, ...) + ... + + result = process_result(subresult1, subresult2, subresult2, ...) + + # revert the current level status + +``` + +### 回溯 + +* 回溯法采用的是错思想,尝试分步去解决一个问题。在分步解决问题的过程中,当通过尝试发现现有分步的答案不能得到有效的正确的解答时,它将取消上一步或者上几步的计算,在通过其他的可能的分步解答再次尝试寻找问题的答案。 + +* 回溯法通常采用递归的方法来实现。 + + + diff --git a/Week 02/id_311/LeetCode_105_Solution.java b/Week 02/id_311/LeetCode_105_Solution.java new file mode 100644 index 000000000..fac86f111 --- /dev/null +++ b/Week 02/id_311/LeetCode_105_Solution.java @@ -0,0 +1,65 @@ +//根据一棵树的前序遍历与中序遍历构造二叉树。 +// +// 注意: +//你可以假设树中没有重复的元素。 +// +// 例如,给出 +// +// 前序遍历 preorder = [3,9,20,15,7] +//中序遍历 inorder = [9,3,15,20,7] +// +// 返回如下的二叉树: +// +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// Related Topics 树 深度优先搜索 数组 + + +//leetcode submit region begin(Prohibit modification and deletion) + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + public TreeNode buildTree(int[] preorder, int[] inorder) { + + if (preorder.length == 1) { + return new TreeNode(preorder[0]); + } + if (preorder.length == 0) { + return null; + } + int index = 0; + while (inorder[index] != preorder[0]) { + index++; + } + TreeNode gen = new TreeNode(preorder[0]); + int[] leftPre = new int[index]; + int[] leftIn = new int[index]; + for (int i = 0; i < index; i++) { + leftIn[i] = inorder[i]; + leftPre[i] = preorder[i + 1]; + } + int[] rightPre = new int[preorder.length - index - 1]; + int[] rightIn = new int[preorder.length - index - 1]; + for (int i = 0; i < rightPre.length; i++) { + rightPre[i] = preorder[index + 1 + i]; + rightIn[i] = inorder[index + 1 + i]; + } + gen.left = buildTree(leftPre, leftIn); + gen.right = buildTree(rightPre, rightIn); + return gen; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 02/id_311/LeetCode_46_Solution.java b/Week 02/id_311/LeetCode_46_Solution.java new file mode 100644 index 000000000..8421a7889 --- /dev/null +++ b/Week 02/id_311/LeetCode_46_Solution.java @@ -0,0 +1,43 @@ +//给定一个没有重复数字的序列,返回其所有可能的全排列。 +// +// 示例: +// +// 输入: [1,2,3] +//输出: +//[ +// [1,2,3], +// [1,3,2], +// [2,1,3], +// [2,3,1], +// [3,1,2], +// [3,2,1] +//] +// Related Topics 回溯算法 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + private List> result = new ArrayList>(); + private List list = new ArrayList(); + + public List> permute(int[] nums) { + for (int i = 0; i < nums.length; i++) { + list.add(nums[i]); + } + backtrack(nums.length, 0); + return result; + } + + private void backtrack(int n, int index) { + if (n == index) { + result.add(new ArrayList(list)); + return; + } + for (int i = index; i < n; i++) { + Collections.swap(list, index, i); + backtrack(n, index + 1); + Collections.swap(list, index, i); + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 02/id_311/LeetCode_47_Solution.java b/Week 02/id_311/LeetCode_47_Solution.java new file mode 100644 index 000000000..faa58501e --- /dev/null +++ b/Week 02/id_311/LeetCode_47_Solution.java @@ -0,0 +1,46 @@ +//给定一个可包含重复数字的序列,返回所有不重复的全排列。 +// +// 示例: +// +// 输入: [1,1,2] +//输出: +//[ +// [1,1,2], +// [1,2,1], +// [2,1,1] +//] +// Related Topics 回溯算法 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + private List> result = new ArrayList>(); + private LinkedList list = new LinkedList(); + + public List> permuteUnique(int[] nums) { + int[] visited = new int[nums.length]; + Arrays.sort(nums); + backtrack(0, nums, visited); + return result; + } + + private void backtrack(int index, int[] nums, int[] visited) { + if (index == nums.length) { + result.add(new LinkedList(list)); + return; + } + for (int i = 0; i < nums.length; i++) { + if (visited[i] != 1) { + if (i > 0 && (nums[i] == nums[i - 1]) && (visited[i - 1] != 1)) { + continue; + } + visited[i] = 1; + list.add(nums[i]); + backtrack(index +1 , nums, visited); + list.removeLast(); + visited[i] = 0; + } + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 02/id_311/LeetCode_77_Solution.java b/Week 02/id_311/LeetCode_77_Solution.java new file mode 100644 index 000000000..e99739ed0 --- /dev/null +++ b/Week 02/id_311/LeetCode_77_Solution.java @@ -0,0 +1,43 @@ +//给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 +// +// 示例: +// +// 输入: n = 4, k = 2 +//输出: +//[ +// [2,4], +// [3,4], +// [2,3], +// [1,2], +// [1,3], +// [1,4], +//] +// Related Topics 回溯算法 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + private List> result = new ArrayList>(); + private LinkedList list = new LinkedList(); + + public List> combine(int n, int k) { + if (n <= 0 || k <= 0 || n < k) { + return result; + } + backtrack(1, n, k); + return result; + } + + private void backtrack(int index, int n, int k) { + if (list.size() == k) { + result.add(new LinkedList(list)); + return; + } + for (int i = index; i < n + 1; i++) { + list.add(i); + backtrack(i + 1, n, k); + list.removeLast(); + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 02/id_346/GroupAnagrams_49.java b/Week 02/id_346/GroupAnagrams_49.java new file mode 100644 index 000000000..26e0d6136 --- /dev/null +++ b/Week 02/id_346/GroupAnagrams_49.java @@ -0,0 +1,28 @@ +import java.util.*; + +/** + * @auther: TKQ + * @Title: GroupAnagrams_49 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-02 10:04 + */ +public class GroupAnagrams_49 { + public List> groupAnagrams(String[] strs) { + if(strs.length == 0){ + return new ArrayList<>(); + } + Map> result = new HashMap<>(); + for(String word:strs){ + char[] c = word.toCharArray(); + Arrays.sort(c); + String key = String.valueOf(c); + if(!result.containsKey(key)){ + result.put(key,new ArrayList()); + } + result.get(key).add(word); + } + return new ArrayList(result.values()); + } +} diff --git a/Week 02/id_346/InorderTraversal_94.java b/Week 02/id_346/InorderTraversal_94.java new file mode 100644 index 000000000..9cbc02785 --- /dev/null +++ b/Week 02/id_346/InorderTraversal_94.java @@ -0,0 +1,38 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * @auther: TKQ + * @Title: InorderTraversal_94 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-02 10:06 + */ +public class InorderTraversal_94 { + + public List inorderTraversal(TreeNode root) { + List result = new ArrayList(); + helper(root,result); + return result; + } + + public void helper(TreeNode root,List result){ + if(root!=null){ + if(root.left!=null){ + helper(root.left,result); + } + result.add(root.val); + if(root.right!=null){ + helper(root.right,result); + } + } + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week 02/id_346/IsAnagram_242.java b/Week 02/id_346/IsAnagram_242.java new file mode 100644 index 000000000..d50a17bf0 --- /dev/null +++ b/Week 02/id_346/IsAnagram_242.java @@ -0,0 +1,31 @@ +package com; + +/** + * @auther: TKQ + * @Title: IsAnagram_242 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-02 10:02 + */ +public class IsAnagram_242 { + + public boolean isAnagram(String s, String t) { + if(s.length()!=t.length()){ + return false; + } + char[] s_array = s.toCharArray(); + char[] t_array = t.toCharArray(); + int[] temp = new int[26]; + for (int i = 0; i < s.length(); i++) { + temp[s.charAt(i) - 'a']++; + temp[t.charAt(i) - 'a']--; + } + for (int i = 0; i < temp.length; i++) { + if(temp[i]!=0){ + return false; + } + } + return true; + } +} diff --git a/Week 02/id_346/LevelOrder_429.java b/Week 02/id_346/LevelOrder_429.java new file mode 100644 index 000000000..50272cb6a --- /dev/null +++ b/Week 02/id_346/LevelOrder_429.java @@ -0,0 +1,51 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * @auther: TKQ + * @Title: LevelOrder_429 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-02 12:17 + */ +public class LevelOrder_429 { + + public List> levelOrder(Node root) { + if(root == null){ + return Collections.emptyList(); + } + List> result = new ArrayList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while(!queue.isEmpty()){ + int size = queue.size(); + List curRes = new ArrayList<>(size); + for(int i=size;i>0;i--){ + Node node = queue.poll(); + curRes.add(node.val); + if(node.children!=null){ + for(int j=0;j children; + + public Node() {} + + public Node(int _val,List _children) { + val = _val; + children = _children; + } + }; +} diff --git a/Week 02/id_346/NOTE.md b/Week 02/id_346/NOTE.md index a6321d6e2..7c556fe28 100644 --- a/Week 02/id_346/NOTE.md +++ b/Week 02/id_346/NOTE.md @@ -1,4 +1,5 @@ # NOTE - - +这段时间忙着找工作,实在是比较忙,直到现在才有时间把上周的题补上 +自己算法的基础比较差,到后边剪枝,回溯这些感觉答案都得来来回回看好多遍才能看懂 +明显感觉根本没有时间去五遍刷题,等忙完这段时间自己一定多花时间来整这一块 diff --git a/Week 02/id_346/Permute_46.java b/Week 02/id_346/Permute_46.java new file mode 100644 index 000000000..5e1a95db0 --- /dev/null +++ b/Week 02/id_346/Permute_46.java @@ -0,0 +1,42 @@ +package com; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @auther: TKQ + * @Title: Permute_46 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-02 16:26 + */ +public class Permute_46 { + public List> permute(int[] nums) { + int len = nums.length; + List> res = new ArrayList<>(); + boolean[] used = new boolean[len]; + if(len == 0){ + return res; + } + genPermution(nums,used,0,len,new Stack<>(),res); + return res; + } + + private void genPermution(int[] nums,boolean[] visited,int curSize,int len,Stack path,List> res){ + if(curSize == len){ + res.add(new ArrayList<>(path)); + return; + } + for(int i = 0;i map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if(map.containsKey(nums[i])){ + return new int[]{map.get(nums[i]),i}; + } + map.put(target - nums[i],i); + } + return null; + } +} diff --git a/Week 02/id_371/Leetcode_0051_371.java b/Week 02/id_371/Leetcode_0051_371.java new file mode 100644 index 000000000..9c43b429a --- /dev/null +++ b/Week 02/id_371/Leetcode_0051_371.java @@ -0,0 +1,82 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:28 + **/ + +public class Leetcode_0051_371 { + public static void main(String[] args) { + List> res = solveNQueens(4); + res.forEach(System.out::println); + } + + /** + * 仿解1:回溯+减枝 + * + * @author Shaobo.Qian + * @date 2019/11/10 + * @link https://leetcode-cn.com/problems/n-queens/solution/gen-ju-di-46-ti-quan-pai-lie-de-hui-su-suan-fa-si-/ + */ + public static List> solveNQueens(int n) { + List> res = new ArrayList<>(); + if (n == 0) return res; + //构建列,为列赋值 + int[] nums = new int[n]; + for (int i = 0; i < n; i++) { + nums[i] = i; + } + //被占用的主对角线 + Set master = new HashSet<>(); + //被占用的副对角线 + Set slave = new HashSet<>(); + //被占用的列 + Set colSet = new HashSet<>(); + Stack stack = new Stack<>(); + + backtrace(nums, 0, n, colSet, master, slave, stack, res); + return res; + } + + private static void backtrace(int[] nums, int row, int n, Set colSet, Set master, Set slave, Stack stack, List> res) { + //1.出口 + if (row == n) { + List board = convert2board(stack, n); + res.add(board); + return; + } + //2. enumerate possible col position for queen of current row) + for (int col = 0; col < n; col++) { + if (!colSet.contains(col) && !master.contains(row + col) && !slave.contains(row - col)) { + //2.处理当前层(当前行)的状态 + stack.add(nums[col]); + colSet.add(col); + master.add(row + col); + slave.add(row - col); + //3.去下一层(下一行) + backtrace(nums, row + 1, n, colSet, master, slave, stack, res); + + //4.回溯,重置状态(restore for the next possible col position for queen of current row) + stack.pop(); + colSet.remove(col); + master.remove(row + col); + slave.remove(row - col); + } + } + } + + private static List convert2board(Stack stack, int n) { + List board = new ArrayList<>(); + for (Integer num : stack) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append("."); + } + sb.replace(num, num + 1, "Q"); + board.add(sb.toString()); + } + return board; + } +} diff --git a/Week 02/id_371/Leetcode_104_371.java b/Week 02/id_371/Leetcode_104_371.java index 3a9c97c6e..2951c94f3 100644 --- a/Week 02/id_371/Leetcode_104_371.java +++ b/Week 02/id_371/Leetcode_104_371.java @@ -16,6 +16,25 @@ public TreeNode(int val) { } + /** + * 重解1:递归 + * + * @author Shaobo.Qian + * @date 2019/11/9 + */ + public int maxDepth2(TreeNode root) { + //1.递归出口 + if (root == null) { + return 0; + } else { + //3.带上参数,向下一层 + int leftMax = maxDepth2(root.right); + int rightMax = maxDepth2(root.left); + //2.处理当前层 + return Math.max(leftMax, rightMax) + 1; + } + } + /** * 仿解1:递归 */ @@ -45,8 +64,10 @@ public int maxDepth(TreeNode root) { } return recur(root, 0); } + /** * 原解1:(未解出-->对递归理解不透彻) + * * @param root * @param depth * @return diff --git a/Week 02/id_371/Leetcode_105_371.java b/Week 02/id_371/Leetcode_105_371.java new file mode 100644 index 000000000..eaa7ea7e8 --- /dev/null +++ b/Week 02/id_371/Leetcode_105_371.java @@ -0,0 +1,72 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:29 + **/ + +public class Leetcode_105_371 { + + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + this.val = val; + } + } + + /** + * 仿解1:分治+哈希表 + * + * @author Shaobo.Qian + * @date 2019/11/6 + * @myProblem (因为一开始没理解为什么需要前序遍历数组和中序遍历数组才能确定树的样子) + * @link https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--22/ + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + Map map = new HashMap<>(inorder.length); + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } + return buildTreeHelper(preorder, 0, preorder.length, inorder, 0, inorder.length, map); + } + + /** + * @param preorder 前序数组 + * @param p_start 前序数组的头指针 + * @param p_end 前序数组的尾指针 + * @param inorder 中序数组 + * @param i_start 中序数组的头指针 + * @param i_end 中序数组的尾指针 + * @return + */ + private TreeNode buildTreeHelper(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end, Map map) { + //1.递归出口(preorder 为空,返回 null) + if (p_start == p_end) return null; + + //2.1处理当前层逻辑,分治,构建根节点 + int root_val = preorder[p_start]; + TreeNode root = new TreeNode(root_val); + //确定左子树的数量 + int i_root_index = map.get(root_val); + /* int i_root_index = 0; + for (int i = 0; i < inorder.length; i++) { + if (root_val == inorder[i]) { + i_root_index = i; + break; + } + }*/ + int leftNum = i_root_index - i_start; + //2.2处理当前层逻辑,分治,构建左子树 + root.left = buildTreeHelper(preorder, p_start + 1, p_start + leftNum + 1, inorder, i_start, i_root_index, map); + //2.3处理当前层逻辑,分治,构建右子树 + root.right = buildTreeHelper(preorder, p_start + leftNum + 1, p_end, inorder, i_root_index + 1, i_end, map); + //3.合并子问题的结果,返回 + return root; + } + +} diff --git a/Week 02/id_371/Leetcode_111_371.java b/Week 02/id_371/Leetcode_111_371.java new file mode 100644 index 000000000..3aa7bc812 --- /dev/null +++ b/Week 02/id_371/Leetcode_111_371.java @@ -0,0 +1,103 @@ +import java.util.LinkedList; +import java.util.Queue; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 06:18 + **/ + +public class Leetcode_111_371 { + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + this.val = val; + } + } + + /** + * 防解1:DFS + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public int minDepth3(TreeNode root) { + if (root == null) return 0; + return recur3(root); + } + + private int recur3(TreeNode root) { + //1.递归出口,遇到叶子节点 + if (root.left == null && root.right == null) return 1; + //2.1 处理当前层逻辑,如果左节点为空,去递归右节点 + if (root.left == null) { + //3. 去下一层,每走一层,结果+1 + return recur3(root.right) + 1; + } + //2.2处理当前层逻辑,如果右节点为空,去递归左节点 + if (root.right == null) { + return recur3(root.left) + 1; + } + //2.3处理当前层逻辑,如果左右节点都不为空,取较小值 + return Math.min(recur3(root.left), recur3(root.right)) + 1; + } + + /** + * 原解2:BFS + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public int minDepth2(TreeNode root) { + if (root == null) return 0; + Queue queue = new LinkedList<>(); + queue.offer(root); + int step = 1; + while (!queue.isEmpty()) { + int count = queue.size(); + while (count-- > 0) { + TreeNode curr = queue.poll(); + if (curr.left == null && curr.right == null) { + return step; + } + if (curr.left != null) queue.add(curr.left); + if (curr.right != null) queue.add(curr.right); + } + step++; + } + return step; + } + + /** + * 原解1:DFS(未解出)--->反映出对 DFS 理解的不够 + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public int minDepth1(TreeNode root) { + if (root == null) return 0; + int step = 1; + return recur(root, step); + } + + private int recur(TreeNode root, int step) { + //1.递归出口 + if (root.left == null && root.right == null) { + return step; + } + //2.处理当前层 + + if (root.left != null) { + //3.去下一层 + recur(root.left, step + 1); + } + + if (root.right != null) { + recur(root.right, step + 1); + } + return step; + } +} diff --git a/Week 02/id_371/Leetcode_169_371.java b/Week 02/id_371/Leetcode_169_371.java new file mode 100644 index 000000000..8bd6aa34c --- /dev/null +++ b/Week 02/id_371/Leetcode_169_371.java @@ -0,0 +1,90 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:28 + **/ + +public class Leetcode_169_371 { + + public static void main(String[] args) { + + int[] nums = {2, 2, 1, 1, 1, 2, 2}; +// int[] nums = {3, 2, 3}; + int target = majorityElement1(nums); + System.out.println("target = " + target); + } + + + /** + * 仿解1:分治 + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public static int majorityElement1(int[] nums) { + + return divideConquer(nums, 0, nums.length - 1); + } + + private static int divideConquer(int[] nums, int lo, int hi) { + //1.递归出口 + if (lo == hi) { + return nums[lo]; + } + + //2.处理子问题 + int mid = lo + (hi - lo) / 2; + int left = divideConquer(nums, lo, mid); + int right = divideConquer(nums, mid + 1, hi); + //3.合并结果 + if (left == right) { + return left; + } else { + int leftCount = countMajorityElement(nums, left, lo, mid); + int rightCount = countMajorityElement(nums, right, mid + 1, hi); + return leftCount > rightCount ? left : right; + } + } + + /** + * 计算在左右half 数组中中位数出现的次数 + * @author Shaobo.Qian + * @date 2019/11/5 + */ + private static int countMajorityElement(int[] nums, int majority, int lo, int hi) { + int count = 0; + for (int i = lo; i <= hi; i++) { + if (nums[i] == majority) count++; + } + return count; + } + + /** + * 原解1: map(是否存在-->map) + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public static int majorityElement(int[] nums) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + Integer count = 0; + if (!map.containsKey(nums[i])) { + map.put(nums[i], 1); + count = 1; + } else { + count = map.get(nums[i]) + 1; + map.put(nums[i], count); + } + if (2 * count > nums.length) { + return nums[i]; + } + } + return 0; + } + +} diff --git a/Week 02/id_371/Leetcode_17_371.java b/Week 02/id_371/Leetcode_17_371.java new file mode 100644 index 000000000..4187f5ad8 --- /dev/null +++ b/Week 02/id_371/Leetcode_17_371.java @@ -0,0 +1,55 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:28 + **/ + +public class Leetcode_17_371 { + public static void main(String[] args) { + String digits = "23"; + List res = letterCombinations(digits); + res.stream().forEach(System.out::println); + + } + + /** + * 原解1:(回溯) + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public static List letterCombinations(String digits) { + List list = new ArrayList<>(); + if ("".equals(digits)) { + return list; + } + String[] dicts = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; + char[] sources = digits.toCharArray(); + char[] targets = new char[digits.length()]; + backtrace(sources, dicts, list, 0, targets); + return list; + } + + private static void backtrace(char[] sources, String[] dicts, List list, int startIndex, char[] targets) { + //1.递归出口 + if (startIndex == sources.length) { + list.add(String.valueOf(targets)); + return; + } + + //2.处理当前层 + char source = sources[startIndex]; + String dict = dicts[Integer.parseInt(String.valueOf(source))]; + for (int i = 0; i < dict.length(); i++) { + char target = dict.charAt(i); + targets[startIndex] = target;//每次循环,之前的值会被覆盖,相当于回溯 + //3.去下一层 + backtrace(sources, dicts, list, startIndex + 1, targets); + } + } + +} diff --git a/Week 02/id_371/Leetcode_236_371.java b/Week 02/id_371/Leetcode_236_371.java new file mode 100644 index 000000000..fb857b9f0 --- /dev/null +++ b/Week 02/id_371/Leetcode_236_371.java @@ -0,0 +1,81 @@ +import java.util.LinkedList; +import java.util.Queue; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:29 + **/ + +public class Leetcode_236_371 { + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + this.val = val; + } + + } + + /** + * 仿解1:(分治) + * @author Shaobo.Qian + * @date 2019/11/5 + * @link https://www.youtube.com/watch?v=13m9ZCB8gjw + */ + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + //1.1递归出口 + if(root == null) return null; + //1.2递归出口 当前节点即要找的节点,找到了节点,直接返回 + if(root == p || root == q) return root; + //2.分治,化成子问题处理 + TreeNode leftNode = lowestCommonAncestor1(root.left, p, q); + TreeNode rightNode = lowestCommonAncestor1(root.right, p, q); + //3.对子问题返回的结果综合处理 + //3.1子问题结果都不为 null + if(leftNode !=null && rightNode!=null) return root; + //3.2子问题结果都为 null + if(leftNode == null && rightNode == null) return null; + //3.1子问题结果一个 null,一个不为 null + return leftNode != null ? leftNode:rightNode; + } + + + + /** + * 原解1:(分治)-->未解除(对递归理解不深入,可以画递归图帮助理解) + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + Queue queue = new LinkedList<>(); + queue.add(root); + recur(root, p, q,queue); + return queue.poll(); + } + + private void recur(TreeNode node, TreeNode p, TreeNode q, Queue queue) { + if (isAncestor(node, p) && isAncestor(node, q)) { + queue.add( node); + } + if (node.left != null) recur(node.left, p, q,queue); + if (node.right != null) recur(node.right, p, q,queue); + + } + + /** + * 判断一个节点是否是另外一个节点的祖先 + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public boolean isAncestor(TreeNode p, TreeNode q) { + if (p == q) return true; + if (p.left != null) isAncestor(p.left, q); + if (p.right != null) isAncestor(p.right, q); + return false; + } +} diff --git a/Week 02/id_371/Leetcode_297_371.java b/Week 02/id_371/Leetcode_297_371.java new file mode 100644 index 000000000..b85128d12 --- /dev/null +++ b/Week 02/id_371/Leetcode_297_371.java @@ -0,0 +1,67 @@ +import java.util.Arrays; +import java.util.Deque; +import java.util.LinkedList; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 06:18 + **/ + +public class Leetcode_297_371 { + + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + this.val = val; + } + } + + /** + * 仿解1:DFS + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + // Encodes a tree to a single string. + public String serialize(TreeNode root) { + StringBuilder sb = new StringBuilder(); + return buildString(root, sb).toString(); + } + + private StringBuilder buildString(TreeNode root, StringBuilder sb) { + //1.递归出口 + if (root == null) { + return sb.append("null,"); + } else { + //2.处理当前层逻辑,拼接当前层当前节点的 val + sb.append(root.val).append(","); + //3.1去下一层,拼接左节点 + sb = buildString(root.left, sb); + //3.2去下一层,拼接右节点 + sb = buildString(root.right, sb); + } + return sb; + } + + // Decodes your encoded data to tree. + public TreeNode deserialize(String data) { + Deque nodes = new LinkedList<>(Arrays.asList(data.split(","))); + return buildTree(nodes); + } + + private TreeNode buildTree(Deque nodes) { + String val = nodes.remove(); + if ("null".equals(val)) { + return null; + } else { + TreeNode root = new TreeNode(Integer.parseInt(val)); + root.left = buildTree(nodes); + root.right = buildTree(nodes); + return root; + } + } +} diff --git a/Week 02/id_371/Leetcode_46_371.java b/Week 02/id_371/Leetcode_46_371.java new file mode 100644 index 000000000..f4b4c8d6a --- /dev/null +++ b/Week 02/id_371/Leetcode_46_371.java @@ -0,0 +1,90 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:30 + **/ + +public class Leetcode_46_371 { + public static void main(String[] args) { + + int[] nums = {1, 2, 3}; + List> res = permute(nums); + res.forEach(System.out::println); + + } + + /** + * 仿解1:(回溯+enumerate numbers for a position) + * @author Shaobo.Qian + * @date 2019/11/9 + * @link https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/ + * @link https://www.youtube.com/watch?v=d2ivgA4F1As + */ + public static List> permute1(int[] nums) { + int len = nums.length; + List> res = new ArrayList<>(); + if (len == 0) return res; + //因为需要考虑当前的位置可以放哪些 + boolean[] visited = new boolean[len]; + + generatePermute1(nums, visited, 0, len, new Stack(), res); + return res; + } + + private static void generatePermute1(int[] nums, boolean[] visited, int curSize, int len, Stack path, List> res) { + //1.递归出口 + if (curSize == len) { + res.add(new ArrayList<>(path)); + return; + } + //2.处理当前层(// enumerate possible numbers for current position) + for (int i = 0; i < len; i++) { + if (!visited[i]) { + visited[i] = true; + path.push(nums[i]); + //3.去下一层 + generatePermute1(nums, visited, curSize + 1, len, path, res); + //4.回溯,所有状态清除(restore for the next possible number for current position) + path.pop(); + visited[i] = false; + } + } + } + + /** + * 原解1:回溯法(未解除,对回溯时,状态的重置理解不够深入,应该需要将所有改变的状态重置) + * + * @author Shaobo.Qian + * @date 2019/11/9 + */ + public static List> permute(int[] nums) { + List> results = new ArrayList<>(); + if (nums == null || nums.length == 0) return results; + List subList = new ArrayList<>(); + backtrace(nums, 0, subList, results); + return results; + } + + private static void backtrace(int[] nums, int index, List subList, List> results) { + if (subList.size() == nums.length) { + results.add(new ArrayList<>(subList)); + return; + } + + int count = nums.length - subList.size(); + for (int i = index; count > 0; count--) { + subList.add(nums[i]); + i++; + if (i == nums.length) { + i = 0; + } + backtrace(nums, i, subList, results); + subList.remove(subList.size() - 1); + } + } +} diff --git a/Week 02/id_371/Leetcode_47_371.java b/Week 02/id_371/Leetcode_47_371.java new file mode 100644 index 000000000..13a23a2f7 --- /dev/null +++ b/Week 02/id_371/Leetcode_47_371.java @@ -0,0 +1,57 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:30 + **/ + +public class Leetcode_47_371 { + public static void main(String[] args) { + int[] nums = {1, 1, 2}; + } + + /** + * 仿解1:(回溯+当前位置可能的值) + * + * @author Shaobo.Qian + * @date 2019/11/10 + * @link https://www.youtube.com/watch?v=eLUPUB_hC8I + * @link https://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liwe-2/ + */ + public List> permuteUnique(int[] nums) { + List> res = new ArrayList<>(); + int length = nums.length; + if (length == 0) return res; + boolean[] visited = new boolean[nums.length]; + Arrays.sort(nums); + backtrace(nums, 0, length, visited, new Stack(), res); + return res; + } + + private void backtrace(int[] nums, int depth, int length, boolean[] visited, Stack path, List> res) { + //1.递归出口 + if (depth == length) { + res.add(new ArrayList<>(path)); + return; + } + //2.处理当前层(// enumerate possible numbers for current position) + for (int i = 0; i < length; i++) { + if (!visited[i]) {//判断当前元素是否可选 + if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) continue; //回溯里的剪枝 + path.push(nums[i]); + visited[i] = true; + //3.去下一层 + backtrace(nums, depth + 1, length, visited, path, res); + //4.回溯,重置状态(restore for the next possible number for current position) + path.pop(); + visited[i] = false; + } + } + } + +} diff --git a/Week 02/id_371/Leetcode_70_371.java b/Week 02/id_371/Leetcode_70_371.java index cee18860c..12bfdc80b 100644 --- a/Week 02/id_371/Leetcode_70_371.java +++ b/Week 02/id_371/Leetcode_70_371.java @@ -13,6 +13,44 @@ public static void main(String[] args) { } + /** + * 动态规划(自顶向下) +数组缓存 + * + * @param n + * @return + */ + public static int climbStair4(int n) { + int[] arr = new int[n + 1]; + arr[0] = 1; + arr[1] = 1; + for (int i = 2; i < n + 1; i++) { + arr[i] = arr[i - 1] + arr[i - 2]; + } + return arr[n]; + } + + /** + * 重接1:递归+数组缓存 + * + * @author Shaobo.Qian + * @date 2019/11/9 + */ + public static int climbStair3(int n) { + int[] memo = new int[n + 1]; + return climb_stair3(0, n, memo); + } + + + private static int climb_stair3(int i, int n, int[] memo) { + if (i > n) return 0; + if (i == n) return 1; + if (memo[i] > 0) return memo[i]; + + memo[i] = climb_stair3(i + 1, n, memo) + climb_stair3(i + 2, n, memo); + return memo[i]; + } + + /** * 仿解2: 递归 + 数组缓存 */ @@ -22,17 +60,16 @@ public static int climbStairs2(int n) { } /** - * - * @param i 表示从当前层爬到第n层的各种个你可能 - * @param n 要跑到的目标层 - * @param memo 数组缓存 + * @param i 当前层 + * @param n 要跑到的目标层 + * @param memo 数组缓存,从第 i 层爬到 第n 层的所有可能 * @return */ private static int climb_stair(int i, int n, int[] memo) { //1.递归出口 - if(i >n) return 0; + if (i > n) return 0; if (i == n) return 1; - if (memo[i]>0) return memo[i]; //有缓存取缓存 + if (memo[i] > 0) return memo[i]; //有缓存取缓存 //2.处理当前层 //3.带上参数,去下一层(每次递归调用-->爬一层或者爬两层) diff --git a/Week 02/id_371/Leetcode_77_371.java b/Week 02/id_371/Leetcode_77_371.java new file mode 100644 index 000000000..0be67cf3d --- /dev/null +++ b/Week 02/id_371/Leetcode_77_371.java @@ -0,0 +1,88 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:30 + **/ + +public class Leetcode_77_371 { + + public static void main(String[] args) { + List> results = combine1(4, 2); + results.forEach(System.out::println); + + } + + /** + * 仿解1:(回溯+减枝) + * + * @author Shaobo.Qian + * @date 2019/11/9 + * @link https://leetcode-cn.com/problems/combinations/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-ma-/ + */ + public static List> combine1(int n, int k) { + List> results = new ArrayList<>(); + if (n <= 0 || n < k || k <= 0) { + return results; + } + Stack stack = new Stack<>(); + backtrace1(1, n, k, stack, results); + return results; + } + + private static void backtrace1(int start, int n, int k, Stack stack, List> results) { + if (stack.size() == k) { + results.add(new ArrayList<>(stack)); + return; + } + for (int i = start; i <= n - (k - stack.size()) + 1; i++) {//减枝,stack.size()已确定的元素个数 + stack.add(i); + backtrace1(i + 1, n, k, stack, results); + stack.pop(); + } + } + + /** + * 原解1:回溯(使用的数据结构) + * + * @author Shaobo.Qian + * @date 2019/11/6 + */ + public static List> combine(int n, int k) { + + List> results = new ArrayList<>(); + if (n <= 0 || k <= 0 || n < k) { + return results; + } + List subList = new ArrayList<>(); + backtrace(1, n, k, subList, results); + return results; + } + + /** + * @param start (1...n)个数中的第start个数 + * @param n 所有可能的数(1...n) + * @param k (由k个不同数组成的某一种结果) + * @param subList 用来存储某一种组合的结果 + * @param results 所有的可能组合的结果 + */ + private static void backtrace(int start, int n, int k, List subList, List> results) { + //1.递归出口(p) + if (subList.size() == k) { + results.add(new ArrayList<>(subList)); + return; + } + //2.处理当前层 + for (int i = start; i <= n; i++) { + subList.add(i); + //3.去下一层 + backtrace(i + 1, n, k, subList, results); + //4.回溯 + subList.remove(subList.size() - 1); + } + } +} diff --git a/Week 02/id_371/Leetcode_78_371.java b/Week 02/id_371/Leetcode_78_371.java new file mode 100644 index 000000000..fa59df33a --- /dev/null +++ b/Week 02/id_371/Leetcode_78_371.java @@ -0,0 +1,91 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-05 08:27 + **/ + +public class Leetcode_78_371 { + + public static void main(String[] args) { + int[] nums = {1, 2, 3}; + + List> subsets = subsets2(nums); + subsets.stream().forEach(System.out::println); + + } + + + /** + * 仿解2:dfs+一层一层决策 + * + * @author Shaobo.Qian + * @date 2019/11/5 + */ + public static List> subsets2(int[] nums) { + List> results = new ArrayList<>(); + if (nums == null) return results; + ArrayList subList = new ArrayList<>(); + if (nums.length == 0) { + results.add(subList); + return results; + } + Arrays.sort(nums); + return dfs(nums, subList, 0, results); + } + + private static List> dfs(int[] nums, ArrayList subList, int index, List> results) { + //1.递归出口 + if (index == nums.length) { + results.add(new ArrayList<>(subList)); + return results; + } + //2.1处理当前层,决策:当前层加入元素 + subList.add(nums[index]); + //3.1去下一层 + dfs(nums, subList, index + 1, results); + //2.1处理当前层,决策:当前层不加入元素 + subList.remove(subList.size() - 1); + //3.2去下一层 + dfs(nums, subList, index + 1, results); + return results; + } + + /** + * 仿解1:回溯法 + * + * @author Shaobo.Qian + * @date 2019/11/5 + * @link https://www.jiuzhang.com/solution/subsets + */ + public static List> subsets1(int[] nums) { + List> results = new ArrayList<>(); + if (nums == null) return results; + ArrayList subList = new ArrayList<>(); + if (nums.length == 0) { + results.add(subList); + return results; + } + Arrays.sort(nums); + backtrace(nums, subList, 0, results); + return results; + + } + + private static void backtrace(int[] nums, ArrayList subList, int startIndex, List> results) { + results.add(new ArrayList<>(subList)); + for (int i = startIndex; i < nums.length; i++) { + //[1] ->[1,2] + subList.add(nums[i]); + //寻找以[1,2]开头的集合,存入 results + backtrace(nums, subList, i + 1, results); + //[1,2]->[1] 移除末尾的元素,回溯 + subList.remove(subList.size() - 1); + } + } + +} diff --git a/Week 02/id_406/LeetCode_1213_406.py b/Week 02/id_406/LeetCode_1213_406.py new file mode 100644 index 000000000..265f8bfdf --- /dev/null +++ b/Week 02/id_406/LeetCode_1213_406.py @@ -0,0 +1,3 @@ +class Solution: + def game(self, guess: List[int], answer: List[int]) -> int: + return sum(guess[i]==answer[i] for i in range(len(guess))) \ No newline at end of file diff --git a/Week 02/id_406/LeetCode_46_406.py b/Week 02/id_406/LeetCode_46_406.py index bf53a0c5f..e9e1792f1 100644 --- a/Week 02/id_406/LeetCode_46_406.py +++ b/Week 02/id_406/LeetCode_46_406.py @@ -1,3 +1,7 @@ class Solution: def permute(self, nums: List[int]) -> List[List[int]]: +<<<<<<< HEAD return list(itertools.permutations(nums)) +======= + return list(itertools.permutations(nums)) +>>>>>>> master diff --git a/Week 02/id_406/LeetCode_49_406.py b/Week 02/id_406/LeetCode_49_406.py index a98053c6f..e114c3444 100644 --- a/Week 02/id_406/LeetCode_49_406.py +++ b/Week 02/id_406/LeetCode_49_406.py @@ -3,4 +3,8 @@ def groupAnagrams(self, strs: List[str]) -> List[List[str]]: ans = collections.defaultdict(list) for s in strs: ans[tuple(sorted(s))].append(s) +<<<<<<< HEAD return ans.values() +======= + return ans.values() +>>>>>>> master diff --git a/Week 02/id_406/LeetCode_51_406.py b/Week 02/id_406/LeetCode_51_406.py index ee0250e6b..92cd7091d 100644 --- a/Week 02/id_406/LeetCode_51_406.py +++ b/Week 02/id_406/LeetCode_51_406.py @@ -24,4 +24,8 @@ def __backtracking(self, nums, row, n, col, master, slave, stack, res): stack.append(nums[i]) col.add(i) master.add(row + i) +<<<<<<< HEAD slave.add(row - i) +======= + slave.add(row - i) +>>>>>>> master diff --git a/Week 02/id_431/LeetCode_169_431.java b/Week 02/id_431/LeetCode_169_431.java index 4d845fe7e..18876df90 100644 --- a/Week 02/id_431/LeetCode_169_431.java +++ b/Week 02/id_431/LeetCode_169_431.java @@ -9,20 +9,49 @@ */ public class MajorityElement { - public int majorityElement(int[] nums) { - Map map = new HashMap<>(); - for (int i = 0; i < nums.length; i++) { - if (map.containsKey(nums[i])) { - map.put(nums[i], map.get(nums[i]) + 1); - } else { - map.put(nums[i], 1); - } - } - for (Integer key : map.keySet()) { - if (map.get(key) > (nums.length / 2) + 1) { - return key; - } +// public int majorityElement(int[] nums) { +// Map map = new HashMap<>(); +// for (int i = 0; i < nums.length; i++) { +// if (map.containsKey(nums[i])) { +// map.put(nums[i], map.get(nums[i]) + 1); +// } else { +// map.put(nums[i], 1); +// } +// } +// for (Integer key : map.keySet()) { +// if (map.get(key) > (nums.length / 2) + 1) { +// return key; +// } +// } +// return -1; +// } + +// public int majorityElement(int[] nums) { +// Map map = new HashMap<>(); +// for (int i = 0; i < nums.length; i++) { +// if (!map.containsKey(nums[i])) map.put(nums[i], 0); +// map.put(nums[i], map.get(nums[i]) + 1); +// } +// for (Integer key : map.keySet()) { +// if (map.get(key) > nums.length / 2) return key; +// } +// return -1; +// } + + /** + * 解题思路:因为众数会至少出现n/2次,所以用一个变量标志众数,一个变量标志数量, + * 当数量为0时,则数量加1并将当前数标志为众数,当当前数和众数不一致时,数量减1, + * 当当前数与众数一致时,数量加1 + * @param nums + * @return + */ + public int majorityElement(int[] nums){ + int majority = nums[0], count = 1; + for (int i = 1; i < nums.length; i++) { + if (count == 0) {majority = nums[i]; count = 1;} + else if (majority != nums[i]) count--; + else if (majority == nums[i]) count++; } - return -1; + return majority; } } diff --git a/Week 02/id_431/LeetCode_17_431.java b/Week 02/id_431/LeetCode_17_431.java index 25c637bcc..4783abfbe 100644 --- a/Week 02/id_431/LeetCode_17_431.java +++ b/Week 02/id_431/LeetCode_17_431.java @@ -1,5 +1,7 @@ package medium; +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -8,24 +10,45 @@ * @date 2019/10/27 */ public class LetterCombinationsOfAPhoneNumber { - private static final String[] KEYS = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; +// private static final String[] KEYS = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; +// +// public List letterCombinations(String digits) { +// +// List ret = new LinkedList(); +// combination("", digits, 0, ret); +// return ret; +// } +// +// private void combination(String prefix, String digits, int offset, List ret) { +// if(digits == null || digits.length() == 0) return; +// if (offset >= digits.length()) { +// ret.add(prefix); +// return; +// } +// String letters = KEYS[(digits.charAt(offset) - '0')]; +// for (int i = 0; i < letters.length(); i++) { +// combination(prefix + letters.charAt(i), digits, offset + 1, ret); +// } +// } - public List letterCombinations(String digits) { + private String[] keys = new String[]{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; - List ret = new LinkedList(); - combination("", digits, 0, ret); - return ret; + public List letterCombinations(String digits) { + if ("".equals(digits)) return Collections.emptyList(); + List list = new ArrayList<>(); + traversal(new StringBuilder(), digits, 0, list); + return list; } - private void combination(String prefix, String digits, int offset, List ret) { - if(digits == null || digits.length() == 0) return; - if (offset >= digits.length()) { - ret.add(prefix); - return; - } - String letters = KEYS[(digits.charAt(offset) - '0')]; - for (int i = 0; i < letters.length(); i++) { - combination(prefix + letters.charAt(i), digits, offset + 1, ret); + private void traversal(StringBuilder priex, String digits, int offset, List result){ + if (offset > digits.length() - 1) result.add(priex.toString()); + else { + String letter = keys[digits.charAt(offset) - '0']; + for (int i = 0; i < letter.length(); i++) { + priex.append(letter.charAt(i)); + traversal(priex, digits, offset + 1, result); + priex.delete(priex.length() - 1, priex.length()); + } } } } diff --git a/Week 02/id_431/LeetCode_50_431.java b/Week 02/id_431/LeetCode_50_431.java new file mode 100644 index 000000000..58937df70 --- /dev/null +++ b/Week 02/id_431/LeetCode_50_431.java @@ -0,0 +1,40 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/6 + */ +public class PowXN { + /** + * 分治 + * @param x + * @param n + * @return + */ +// public double myPow(double x, int n) { +// if (n == 0) return 1.0; +// else if (n > 0) return _myPow(x, n); +// else if (n != Integer.MIN_VALUE) return _myPow(1 / x, -n); +// else return _myPow(1 / (x * x), -(n / 2)); +// } +// +// private double _myPow(double x, int n) { +// if (n == 1) return x; +// double tmp = _myPow(x, n / 2); +// return n % 2 == 1 ? tmp * tmp * x : tmp * tmp; +// } + + /** + * 精彩代码 + * @param x + * @param n + * @return + */ + public double myPow(double x, int n){ + if (n == 1) return x; + if (n == -1) return 1 / x; + if (n == 0) return 1.0; + double tmp = myPow(x, n / 2); + return tmp * tmp * myPow(x, n % 2); + } +} diff --git a/Week 02/id_431/LeetCode_51_431.java b/Week 02/id_431/LeetCode_51_431.java new file mode 100644 index 000000000..a351e550e --- /dev/null +++ b/Week 02/id_431/LeetCode_51_431.java @@ -0,0 +1,49 @@ +package hard; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/6 + */ +public class NQueens { +// public List> solveNQueens(int n) { +// List> result = new ArrayList<>(); +// for (int i = 0; i < n; i++) +// traversal(result, new ArrayList(), n, i, 1); +// return result; +// } +// +// private void traversal(List> result, List list, int n, int offset, int level){ +// list.add(setQueen(n, offset)); +// //判断是否能够攻击到前面已经摆放好的皇后 +// if(canAttack(list, n, offset)) return; +// if(level == n) {result.add(new ArrayList<>(list)); return;}; +// for (int i = 0; i < n; i++) { +// traversal(result, list, n, i, level + 1); +// list.remove(list.size() - 1); +// } +// } +// +// private boolean canAttack(List list, int n, int offset) { +// int count = 0; +// for (int i = list.size() - 2; i >= 0; i--){ +// count += 1; +// String tmp = list.get(i); +// if (tmp.charAt(offset) == 'Q') return true; +// if ((offset - count) >= 0 && tmp.charAt(offset - count) == 'Q') return true; +// if ((offset + count) < n && tmp.charAt(offset + count) == 'Q') return true; +// } +// return false; +// } +// +// private String setQueen(int n, int offset){ +// StringBuilder str = new StringBuilder(); +// for (int i = 0; i < n; i++) { +// if (i == offset) str.append('Q'); +// else str.append('.'); +// } +// return str.toString(); +// } +} diff --git a/Week 02/id_431/LeetCode_78_431.java b/Week 02/id_431/LeetCode_78_431.java new file mode 100644 index 000000000..5c4486a26 --- /dev/null +++ b/Week 02/id_431/LeetCode_78_431.java @@ -0,0 +1,29 @@ +package medium; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/6 + */ +public class Subsets { + public List> subsets(int[] nums) { + List> result = new ArrayList<>(); + result.add(new ArrayList<>()); + for (int i = 0; i < nums.length; i++) { + _subsets(result, new ArrayList(), nums, i); + } + return result; + } + + private void _subsets(List> result, List list, int[] nums, int start) { + if (start > nums.length - 1) return; + list.add(nums[start]); + result.add(new ArrayList<>(list)); + for (int i = start + 1; i < nums.length; i++) { + _subsets(result, list, nums, i); + } + list.remove(list.size() - 1); + } +} diff --git a/Week 02/id_431/NOTE.md b/Week 02/id_431/NOTE.md index ff7c2a747..05dfba579 100644 --- a/Week 02/id_431/NOTE.md +++ b/Week 02/id_431/NOTE.md @@ -8,32 +8,23 @@ 题目名称|难易度|第一遍时间|第二遍时间|第三遍时间|第四遍时间|第五遍时间|地址 :-:|:-:|:-:|:-:|:-:|:-:|:-:|:-: -Valid Anagram|Easy|2019-10-23|||||https://leetcode.com/problems/valid-anagram/ -Group Anagrams|Medium|2019-10-23|||||https://leetcode.com/problems/group-anagrams/ -Binary Tree Inorder Traversal|Medium|2019-10-23|||||https://leetcode.com/problems/binary-tree-inorder-traversal/ -Binary Tree Preorder Traversal|Medium|2019-10-23|||||https://leetcode.com/problems/binary-tree-preorder-traversal/ -N-ary Tree Postorder Traversal|Easy|2019-10-23|||||https://leetcode.com/problems/n-ary-tree-postorder-traversal/ -N-ary Tree Preorder Traversal|Easy|2019-10-23|||||https://leetcode.com/problems/n-ary-tree-preorder-traversal/ -Generate Parentheses|Medium|2019-10-23|||||https://leetcode.com/problems/generate-parentheses/ -Invert Binary Tree|Easy|2019-10-23|||||https://leetcode.com/problems/invert-binary-tree/ -Validate Binary Search Tree|Medium|2019-10-24|||||https://leetcode.com/problems/validate-binary-search-tree/ -Maximum Depth of Binary Tree|Easy|2019-10-24|||||https://leetcode.com/problems/maximum-depth-of-binary-tree/ -Minimum Depth of Binary Tree|Easy|2019-10-24|||||https://leetcode.com/problems/minimum-depth-of-binary-tree/ +Valid Anagram|Easy|2019-10-23|2019-11-07||||https://leetcode.com/problems/valid-anagram/ +Group Anagrams|Medium|2019-10-23|2019-11-07||||https://leetcode.com/problems/group-anagrams/ +Binary Tree Inorder Traversal|Medium|2019-10-23|2019-11-07||||https://leetcode.com/problems/binary-tree-inorder-traversal/ +Binary Tree Preorder Traversal|Medium|2019-10-23|2019-11-08||||https://leetcode.com/problems/binary-tree-preorder-traversal/ +N-ary Tree Postorder Traversal|Easy|2019-10-23|2019-11-08||||https://leetcode.com/problems/n-ary-tree-postorder-traversal/ +N-ary Tree Preorder Traversal|Easy|2019-10-23|2019-11-08||||https://leetcode.com/problems/n-ary-tree-preorder-traversal/ +Generate Parentheses|Medium|2019-10-23|2019-10-31|2019-11-08|||https://leetcode.com/problems/generate-parentheses/ +Invert Binary Tree|Easy|2019-10-23|2019-11-08||||https://leetcode.com/problems/invert-binary-tree/ +Validate Binary Search Tree|Medium|2019-10-24|2019-11-08||||https://leetcode.com/problems/validate-binary-search-tree/ +Maximum Depth of Binary Tree|Easy|2019-10-24|2019-11-08||||https://leetcode.com/problems/maximum-depth-of-binary-tree/ +Minimum Depth of Binary Tree|Easy|2019-10-24|2019-11-08||||https://leetcode.com/problems/minimum-depth-of-binary-tree/ Serialize and Deserialize Binary Tree|Hard|2019-10-25|||||https://leetcode.com/problems/serialize-and-deserialize-binary-tree/ Lowest Common Ancestor of a Binary Tree|Medium|2019-10-25|||||https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/ Construct Binary Tree from Preorder and Inorder Traversal|Medium|2019-10-25|||||https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ - - - - -## 时间复杂度空间复杂度表 - -**数据结构操作** - -数据结构|访问(平均)|搜索(平均)|插入(平均)|删除(平均)|访问(最差)|搜索(最差)|插入(最差)|删除(最差)|空间复杂度 -:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| -Array|O(1)|O(n)|O(n)|O(n)|O(1)|O(n)|O(n)|O(n)|O(n) -Singly-Linked List|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) -Doubly-Linked List|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) -Skip List|O(log(n))|O(log(n))|O(log(n))|O(log(n))|O(n)|O(n)|O(n)|O(n)|O(nlog(n)) -Stack|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) \ No newline at end of file +Permutations|Medium|2019-10-27|||||https://leetcode.com/problems/permutations/ +Majority Element|Easy|2019-10-27|2019-11-06||||https://leetcode.com/problems/majority-element/description/ +Letter Combinations of a Phone Number|Medium|2019-10-27|2019-11-06||||https://leetcode.com/problems/letter-combinations-of-a-phone-number/ +Pow(x, n)|Medium|2019-11-06|||||https://leetcode.com/problems/powx-n/ +Subsets|Medium|2019-11-06|||||https://leetcode.com/problems/subsets/ +N-Queens|Hard|2019-11-06|||||https://leetcode.com/problems/n-queens/ \ No newline at end of file diff --git a/Week 02/id_511/LeetCode_242_511.java b/Week 02/id_511/LeetCode_242_511.java new file mode 100644 index 000000000..91e606138 --- /dev/null +++ b/Week 02/id_511/LeetCode_242_511.java @@ -0,0 +1,48 @@ +package id_511; + +import java.util.Arrays; + +/** + * @version 1.0 + * @Description: 有效的字母异位词(异位词是指字母出现的频率相同但是顺序不同) + * @author: bingyu + * @date: 2019/10/30 20:43 + */ +public class LeetCode_242_511 { + + + + //方法一:将字符串按照字母排序,再看是否相等即可 + public static boolean isAnagram(String s, String t) { + char[] a = s.toCharArray(); + char[] b = t.toCharArray(); + Arrays.sort(a); + Arrays.sort(b); + return Arrays.equals(a,b); + } + + //方法二:使用散列表的思想将字符串的每个字符散列到数组里,并计数 + public static boolean isAnagram2(String s, String t) { + if (s.length() != t.length()) { //字符串长度是否相同,不相等肯定不是异位词 + return false; + } + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i) - 'a']++; //因为字母a在ascii码是97,a在哈希表counter位置是下标0,其它字母的对应的下标就是s.charAt(i) - 'a'; + counter[t.charAt(i) - 'a']--; //一个加,一个减,如果两个字母是异位词的话,最终数组counter里应该都只有0,否则就不是异位词 + } + for (int count : counter) { + if (count != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + String s = "fsdfsd"; + String t = "vnvnsj"; + boolean f = isAnagram2(s, t); + System.out.println(f); + } +} diff --git a/Week 02/id_511/LeetCode_49_511.java b/Week 02/id_511/LeetCode_49_511.java new file mode 100644 index 000000000..fb47c3f51 --- /dev/null +++ b/Week 02/id_511/LeetCode_49_511.java @@ -0,0 +1,36 @@ +package id_511; + +import java.util.*; + +/** + * @version 1.0 + * @Description: 字母异位词分组 + * @author: bingyu + * @date: 2019/10/30 21:23 + */ +public class LeetCode_49_511 { + + + //使用hash表,将排序后的字符串作为key,每一个key对应一个List。list里就是存放排序前的字符串即可 + public static List> groupAnagrams(String[] strs) { + if (strs.length == 0) return new ArrayList(); + Map map = new HashMap<>(); + for (String str : strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String key = String.valueOf(chars); //获得排序后的字符串 + if (!map.containsKey(key)) { //每一个排序的key对应一个List,list里存放原来的字符串 + map.put(key, new ArrayList()); + } + map.get(key).add(str); + } + return new ArrayList(map.values()); + } + + + public static void main(String[] args) { + String[] ar = {"eat", "tea", "tan", "ate", "nat", "bat"}; + List> lists = groupAnagrams(ar); + System.out.println(lists); + } +} diff --git a/Week 02/id_511/LeetCode_94_511.java b/Week 02/id_511/LeetCode_94_511.java new file mode 100644 index 000000000..8b691d8fe --- /dev/null +++ b/Week 02/id_511/LeetCode_94_511.java @@ -0,0 +1,123 @@ +package id_511; + +import javax.swing.tree.TreeNode; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @version 1.0 + * @Description: 二叉树的中序遍历 + * @author: bingyu + * @date: 2019/10/30 23:23 + */ +public class LeetCode_94_511 { + + public static class TreeNode{ + public int val; + public TreeNode left,right; + + public TreeNode(int val){ + this.val = val; + this.left = null; + this.right = null; + } + } + + public List inorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + inOrder(root,list); + return list; + } + + //方法一:递归 + //前序遍历 + public void preOrder(TreeNode root, List list){ + if (root != null) { //如果根结点不为空 + list.add(root.val); + if (root.left != null) { //如果左结点不为null,则将该左结点作为根结点继续遍历它的左结点 + preOrder(root.left,list); + } + //开始遍历右结点 + if (root.right != null) { + preOrder(root.right,list); + } + } + } + + //中序遍历 + public void inOrder(TreeNode root, List list){ + if (root != null) { //如果根结点不为空 + if (root.left != null) { //如果左结点不为null,则将该左结点作为根结点继续遍历它的左结点 + inOrder(root.left,list); + } + //执行到这里说明root.left==null,即左节点已遍历完成 + list.add(root.val); + //开始遍历右结点 + if (root.right != null) { + inOrder(root.right,list); + } + } + } + + //后序遍历 + public void postOrder(TreeNode root, List list){ + if (root != null) { //如果根结点不为空 + if (root.left != null) { //如果左结点不为null,则将该左结点作为根结点继续遍历它的左结点 + postOrder(root.left,list); + } + //开始遍历右结点 + if (root.right != null) { + postOrder(root.right,list); + } + list.add(root.val); + } + } + + //方法二:使用栈来模拟递归 + public static List inorderTraversal2(TreeNode root) { + List res = new ArrayList <> (); + Stack stack = new Stack <> (); + TreeNode curr = root; + while (curr != null || !stack.isEmpty()) { //这里外层的循环条件中的curr!=null是判断当前节点是否存在右子树,下面内存循环的curr!=null是判断当前节点是否存在左子树 + while (curr != null) { //首先在这里第一次循环是将根结点的所有左子树结点放入栈中,第一次内层while循环完后,cur就是整个树最左边的叶子结点 + stack.push(curr); + curr = curr.left; + } + curr = stack.pop(); //执行到这里说明curr是某个结点的左叶子结点(即左边没有子元素了),下面可以开始遍历其右子树 + res.add(curr.val); + curr = curr.right; //遍历右子树 + } + return res; + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(10); + TreeNode a = new TreeNode(9); + TreeNode b = new TreeNode(8); + TreeNode c = new TreeNode(7); + TreeNode d = new TreeNode(6); + TreeNode e = new TreeNode(5); + TreeNode f = new TreeNode(4); + TreeNode g = new TreeNode(3); + TreeNode h = new TreeNode(2); + TreeNode i = new TreeNode(1); + TreeNode j = new TreeNode(0); + TreeNode k = new TreeNode(-1); + TreeNode l = new TreeNode(11); + root.left = a; + root.left.right = b; + root.left.left = c; + root.left.left.left = d; + root.left.left.right = e; + root.left.right.left = f; + root.left.right.right = g; + root.right = h; + root.right.left = i; + root.right.right = j; + root.right.right.left = k; + root.left.left.left.right = l; + List list = inorderTraversal2(root); + System.out.println(list); + } +} diff --git a/Week 02/id_511/NOTE.md b/Week 02/id_511/NOTE.md index a6321d6e2..08b8d6420 100644 --- a/Week 02/id_511/NOTE.md +++ b/Week 02/id_511/NOTE.md @@ -1,4 +1,16 @@ -# NOTE - - - +# 第二这周总结 +###(第二周由于在忙于完成专升本的作业,因此第二周的作业放在第三周周四完成,第三周我会在这周周末准时完成) +### 在第二周的学习中,主要是学习了树的遍历以及写递归的代码的一些技巧。 +    我总结一下自己现在理解的树,我把树看成是一个拥有多个后继结点的链表,由于链表查找元素时间复杂度较高 +0(n),所以衍生出了树这种结构,为0(logn),树又分为很多种类型比如二叉树、二叉搜索树、红黑树、平衡二叉树等等 +,其实现实生活中,树其实是有很多分叉的,我们在程序里通常处理的都是只有两只分叉的二叉树,这是因为二叉树分支只有两个 +,更方便处理,这其实有一个将普通的树转化为二叉树的过程,它的转化规则这边用一个口诀概括起来: +兄弟相连留长子。另一个就是二叉树的结构其实就是一个递归的结构,因此关于二叉树的遍历都可以用递归来 +解决。 +    另一个就是关于hashMap的源码·分析了,hashMap的源码里含有的内容包含很多,在jdk1.8中 +HashMap中的重点用到了链表和红黑树,其中链表和红黑树的转化是重点,这里因为时间关系我就附上一个链接:HashMap源码分析 + + + + + diff --git a/Week 02/id_531/leetCode_145_531.go b/Week 02/id_531/leetCode_145_531.go new file mode 100644 index 000000000..4e0eb4c76 --- /dev/null +++ b/Week 02/id_531/leetCode_145_531.go @@ -0,0 +1,23 @@ +package id_531 + +//PostOrderTraversal 二叉树后续遍历 +func PostOrderTraversal(root *TreeNode) []int { + + var res []int + helper2(root, &res) + return res + +} + +func helper2(root *TreeNode, res *[]int) { + //terminal + if root != nil { + if root.Left != nil { + helper(root.Left, res) + } + if root.Right != nil { + helper(root.Right, res) + } + *res = append(*res, root.Val) + } +} diff --git a/Week 02/id_531/leetCode_242_531.go b/Week 02/id_531/leetCode_242_531.go new file mode 100644 index 000000000..c2768cda1 --- /dev/null +++ b/Week 02/id_531/leetCode_242_531.go @@ -0,0 +1,21 @@ +package id_531 + +//IsAnagram t是否s是字母异位词 +func IsAnagram(s string, t string) bool { + if len(s) != len(t) { + return false + } + sr := []rune(s) + tr := []rune(t) + m := make(map[rune]int, 0) + for i := range sr { + m[sr[i]]++ + m[tr[i]]-- + } + for _, v := range m { + if v != 0 { + return false + } + } + return true +} diff --git a/Week 02/id_531/leetCode_94_531.go b/Week 02/id_531/leetCode_94_531.go new file mode 100644 index 000000000..0301dfb82 --- /dev/null +++ b/Week 02/id_531/leetCode_94_531.go @@ -0,0 +1,25 @@ +package id_531 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func InOrderTraversal(root *TreeNode) []int { + var res []int + helper(root, &res) + return res +} + +func helper(root *TreeNode, res *[]int) { + if root != nil { + if root.Left != nil { + helper(root.Left, res) + } + *res = append(*res, root.Val) + if root.Right != nil { + helper(root.Right, res) + } + } +} diff --git a/Week 02/id_541/LeetCode_236_541.java b/Week 02/id_541/LeetCode_236_541.java new file mode 100644 index 000000000..4ebda2cb5 --- /dev/null +++ b/Week 02/id_541/LeetCode_236_541.java @@ -0,0 +1,96 @@ +//给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 +// +// 百度百科中最近公共祖先的定义为:“对于有根树 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 树 + +package leetcode.editor.cn; + +import java.lang.reflect.Array; + +//Java:二叉树的最近公共祖先 +public class LeetCode_236_541{ + public static void main(String[] args) { + Solution solution = new LeetCode_236_541().new Solution(); + // TO TEST + } + + +//leetcode submit region begin(Prohibit modification and deletion) +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + // root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 +class Solution { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + + } + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + // TreeNode + // n = 1 ,3 , left = n+1 = 5,right = n+2 = 1 . + // n = 2, 5 , left = n+2 = 6 ,right = n+3 = 2 . + // n = 3, 1 , left = n+3 = 0 ,right = n+4 = 8 . + // + // n = n ,2n,2n+1 + + //解法1:1.root 先序遍历->数组,2.在数组里面找最近p,q,然后逆向求解出其根节点,将根节点存放在list里面,找最近公共节点 + //优化:可以用栈来替代1步骤。 + + //解法2:递归+回溯 + + 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; + + } + + +} +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 02/id_541/LeetCode_590_541.java b/Week 02/id_541/LeetCode_590_541.java new file mode 100644 index 000000000..256e2ca69 --- /dev/null +++ b/Week 02/id_541/LeetCode_590_541.java @@ -0,0 +1,129 @@ +//给定一个 N 叉树,返回其节点值的后序遍历。 +// +// 例如,给定一个 3叉树 : +// +// +// +// +// +// +// +// 返回其后序遍历: [5,6,3,2,4,1]. +// +// +// +// 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 + +package leetcode.editor.cn; + +import java.util.*; + +//Java:N叉树的后序遍历 +public class P590NAryTreePostorderTraversal{ + public static void main(String[] args) { + Solution solution = new P590NAryTreePostorderTraversal().new Solution(); + // TO TEST + + } + + +//leetcode submit region begin(Prohibit modification and deletion) + +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val,List _children) { + val = _val; + children = _children; + } +}; + + //{"$id":"1", + // "children":[{"$id":"2","children":[{"$id":"5","children":[],"val":5},{"$id":"6","children":[],"val":6}],"val":3}, + // {"$id":"3","children":[],"val":2},{"$id":"4","children":[],"val":4}],"val":1} +//后序遍历 +class Solution { + //递归 +// public List postorder(Node root) { +// +// List result = new ArrayList(); +// if (root == null) return result; +// List childrenList = root.children; +// if (childrenList != null){ +// searchAndPut(root,result); +// } +// return result; +// } +// +// +// private void searchAndPut(Node root, List result ){ +// if (root == null) return ; +// if (root.children == null) return; +// for (Node node : root.children) { //栈的深入 +// searchAndPut(node,result); +// } +// result.add(root.val); //出栈 +// } + + //迭代 +//public List postorder(Node root) { +// +// List ans = new LinkedList<>(); +// Stack s1 = new Stack<>(); +// Stack s2 = new Stack<>(); //用一个辅助栈记录当前节点已经访问到其第几个孩子了 +// Node node = root; +// while (node != null || !s1.isEmpty()) { +// while (node != null) { +// s1.push(node); //s1放了整棵树 +// s2.push(1); //s2存放访问记录。当前节点第一个孩子(内层循环遍历完成,s2存放所有左子树) +// if (node.children != null && node.children.size() > 0) { //判断当前节点存在孩子节点 +// node = node.children.get(0); //将左子树赋给当前节点。 +// } else { //否则,跳出内层循环。(左子树到底) +// node = null; +// } +// } +// node = s1.peek(); //取出第栈顶第一个节点。 s2.peek() 该节点在其树中的位置 +// //如果已经访问到最后一个孩子了,那么就该访问当前节点了。 +// if (node.children == null || s2.peek() >= node.children.size()) { //当前节点(左子树节点)无叶子节点,或者 s2.peek() >= node.children.size() 判断是否存在右子节点。 +// ans.add(node.val); //当前node满足条件,加到结果。 满足条件--左右中, +// s1.pop(); +// s2.pop(); +// node = null; +// } else { //否则继续遍历 +// node = node.children.get(s2.peek()); // +// s2.push(s2.pop() + 1); +// } +// } +// +// //难点: 怎么判断是右子树 +// return ans; +//} +// https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/submissions/ + //更为简洁的写法。这种解法的思想是先序遍历的变形,先序遍历是“根->左->右”,后序遍历是“左->右->根”,那么把先序遍历改成“根->右->左”,再逆序一下就是后序遍历。 + //逆序一下,改造后的先序遍历 + public List postorder(Node root) { + List ans = new LinkedList<>(); // + if (root == null) return ans; + Stack stack = new Stack(); //stack:右比左先出 ans:右比左先插(头插法)-> 左在右前门 + stack.push(root); + while (!stack.empty()){ + root = stack.pop(); + ans.add(0,root.val); //头插 + if (root.children !=null){ + for (Node child : root.children) { + stack.push(child); //左右进,左右出 + } + } + } + return ans; + } + + + +} + +} \ No newline at end of file diff --git a/Week 02/id_571/leetcode_17_571.js b/Week 02/id_571/leetcode_17_571.js new file mode 100644 index 000000000..e3778170c --- /dev/null +++ b/Week 02/id_571/leetcode_17_571.js @@ -0,0 +1,31 @@ +/** + * @param {string} digits + * @return {string[]} + */ +var letterCombinations = function(digits) { + let res = []; + if (digits === "") return res; + let map = { + "2": "abc", + "3": "def", + "4": "ghi", + "5": "jkl", + "6": "mno", + "7": "pqrs", + "8": "tuv", + "9": "wxyz" + }; + helper(res, digits, 0, "", map); + return res; +}; + +var helper = function(arr, digits, index, str, map) { + if (digits.length === index) { + arr.push(str); + return; + } + let letters = map[digits[index]]; + for (let s of letters) { + helper(arr, digits, index + 1, str.concat(s), map); + } +}; diff --git a/Week 02/id_571/leetcode_51_571.js b/Week 02/id_571/leetcode_51_571.js new file mode 100644 index 000000000..3c40b3505 --- /dev/null +++ b/Week 02/id_571/leetcode_51_571.js @@ -0,0 +1,40 @@ +/** + * @param {number} n + * @return {string[][]} + */ +var solveNQueens = function(n) { + let memo = []; + helper(0, n, [], [], [], [], memo); + return format(memo); +}; + +var helper = function(row, n, cols, left, right, state, memo) { + if (row >= n) { + memo.push(state); + return; + } + for (let col = 0; col < n; col++) { + if (cols[col] || left[row + col] || right[row - col]) continue; + cols[col] = true; + left[row + col] = true; + right[row - col] = true; + helper(row + 1, n, cols, left, right, state.concat([col]), memo); + cols[col] = false; + left[row + col] = false; + right[row - col] = false; + } +}; + +var format = function(memo) { + let result = []; + for (let arr of memo) { + let ele = []; + for (let pos of arr) { + ele.push(".".repeat(pos) + "Q" + ".".repeat(arr.length - pos - 1)); + } + result.push(ele); + } + return result; +}; + +solveNQueens(4); diff --git a/Week 02/id_616/NOTE.md b/Week 02/id_616/NOTE.md index a6321d6e2..0450f77c0 100644 --- a/Week 02/id_616/NOTE.md +++ b/Week 02/id_616/NOTE.md @@ -1,4 +1,53 @@ # NOTE - +## 哈希表、映射、集合 +### 散列函数 + +通过把 Key(关键码值)​映射到表中的一个位置来访问,以加快查找的速度。这个映射函数叫做散列函数(Hash Function)​​,存放记录的数组叫做哈希表(散列表) + +### 散列冲突 + +- 开放寻址法 +- 拉链式解决冲突法 + +## 树、二叉树、二叉搜索树 + +### 树 + +链表是特殊化的树,树是特殊化的图。 + +### 二叉树 + +前序遍历: 根->左->右 +中序遍历: 左->根->右 +后序遍历: 左->右->根 + +### 二叉搜索树 + +左子树都小于根节点,右子树都大于根节点 + +## 泛型递归、树的递归 + +### 递归模板 + +1. 终止条件 +2. 处理当前层逻辑 +3. 下探到下一层 +4. 如有需要,清理当前层状态 + +### 要点 + +- 不要人肉进行递归(最大误区) +- 找到最近最简方法,将其拆解成可重复解决的问题(重复子问题) +- 数学归纳法 + +## 分治、回溯 + +### 分治模板 + +1. 终止条件 +2. 准备数据 +3. 拆解子问题 +4. 组合最终结果 +5. 如有需要,清理当前层状态 diff --git a/Week 02/id_636/LeetCode_22_636.py b/Week 02/id_636/LeetCode_22_636.py new file mode 100644 index 000000000..6adf07cbf --- /dev/null +++ b/Week 02/id_636/LeetCode_22_636.py @@ -0,0 +1,48 @@ +''' + # 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + # + # 例如,给出 n = 3,生成结果为: + # + # [ + # "((()))", + # "(()())", + # "(())()", + # "()(())", + # "()()()" + # ] + # + # 链接:https://leetcode-cn.com/problems/generate-parentheses +''' +class List(list): + pass + +class Solution: + def generateParenthesis(self, n: int) -> List: + # init res + res = [] + levelS = "" + + def generator(left: int, right: int, n: int, s: str): + # terminator + if left == n and right == n: + res.append(s) + return + + # cache + # s1 = s + "(" + # s2 = s + ")" + + # process + if left < n: + generator(left + 1, right, n, s + "(") + + if left > right and right < n: + generator(left, right + 1 , n, s + ")") + + generator(0, 0, n, levelS) + + return res + +if __name__ == '__main__': + s = Solution() + print("res: ", s.generateParenthesis(3)) \ No newline at end of file diff --git a/Week 02/id_636/LeetCode_242_636.py b/Week 02/id_636/LeetCode_242_636.py index 881b8f60f..4844eec47 100644 --- a/Week 02/id_636/LeetCode_242_636.py +++ b/Week 02/id_636/LeetCode_242_636.py @@ -47,6 +47,45 @@ def isAngramMap(self, s: str, t: str) -> bool: return sDict == tDict + def isAngramMapUpdate(self, s: str, t: str) -> bool: + + # check length + if len(s) != len(t): + return False + # new dict + sDict = dict() + tDict = dict() + + for index in range(len(s)): + sDict.update({ + s[index]: sDict.setdefault(s[index], 0) + 1 + }) + + tDict.update({ + t[index]: tDict.setdefault(t[index], 0) + 1 + }) + + return sDict == tDict + + def isAngramMapDefault(self, s: str, t: str) -> bool: + # check length + if len(s) != len(t): + return False + + from collections import defaultdict + + # new dict + sDict = defaultdict(lambda: 0) + tDict = defaultdict(lambda: 0) + + for index in range(len(s)): + sDict[s[index]] += 1 + tDict[t[index]] += 1 + + print(sDict, tDict) + + return sDict == tDict + def isAngramCollections(self, s: str, t: str) -> bool: import collections return collections.Counter(s) == collections.Counter(t) @@ -54,7 +93,7 @@ def isAngramCollections(self, s: str, t: str) -> bool: if __name__ == '__main__': s = Solution() - str1 = "aaaaaab" - str2 = "baaaaaa" + str1 = "a" + str2 = "b" - print(s.isAngramCollections(str1, str2)) + print(s.isAngramMapDefault(str1, str2)) diff --git a/Week 02/id_636/LeetCode_589_636.py b/Week 02/id_636/LeetCode_589_636.py new file mode 100644 index 000000000..5b7f08a45 --- /dev/null +++ b/Week 02/id_636/LeetCode_589_636.py @@ -0,0 +1,51 @@ +''' +给定一个 N 叉树,返回其节点值的前序遍历。 + +例如,给定一个 3叉树 : + 1 + 👆 👆 + 3 2 4 + 👆👆 +5 6 + +返回其前序遍历: [1,3,5,6,2,4]。 +''' + +class List(list): + pass + +# Definition for a Node. +class Node: + def __init__(self, val, children): + self.val = val + self.children = children + +class Solution: + def preorder(self, root: 'Node') -> List[int]: + ''' + :param root: Node + :return: list + 遍历 root 中所有的 children + ''' + # init res + res = [] + + if not root: + return res + + res += [root.val] + + # for loop + for child in root.children: + res += self.preorder(child) + # return res + return res + + def preOrder(self, root: 'Node') -> List[int]: + ''' + :param root: Node + :return: Lisr + 使用 stack 的方法 + ''' + + diff --git a/Week 02/id_636/LeetCode_590_636.py b/Week 02/id_636/LeetCode_590_636.py new file mode 100644 index 000000000..5406a9a8c --- /dev/null +++ b/Week 02/id_636/LeetCode_590_636.py @@ -0,0 +1,51 @@ +""" +给定一个 N 叉树,返回其节点值的后序遍历。 + +例如,给定一个 3 叉树: + 1 + 👆 👆 + 3 2 4 + 👆👆 +5 6 + +返回其后序遍历: [5,6,3,2,4,1] +""" + +class Node: + def __init__(self, val, children): + self.val = val + self.children = children + +class Solution: + def postOrder(self, root: 'Node') -> list: + ''' + :param root: Node + :return: list + 1:本方案使用的是递归的方法 + ''' + # init res + res = [] + # if not root, return current res + if not root: + return res + + for child in root.children: + res += self.postOrder(child) + res += [root.val] + + return res + + def postOrder(self, root: 'Node') -> list: + + ''' + :param root: + :return: list + 2:stack 的方案 + ''' + # init res + res = [] + + + + + diff --git a/Week 02/id_636/LeetCode_70_636.py b/Week 02/id_636/LeetCode_70_636.py new file mode 100644 index 000000000..4b0b6ca09 --- /dev/null +++ b/Week 02/id_636/LeetCode_70_636.py @@ -0,0 +1,44 @@ +''' + 假设你正在爬楼梯。需要 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 阶 + + 链接:https://leetcode-cn.com/problems/climbing-stairs +''' + + +class Solution: + def climbStairs(self, n: int) -> int: + # check the n + if n <= 2: + return n + + num1, num2, num3 = 1, 2, 0 + for index in range(3, n + 1): + num3 = num1 + num2 + num1 = num2 + num2 = num3 + + return num3 + +if __name__ == '__main__': + s = Solution() + print("res: ", s.climbStairs(5)) \ No newline at end of file diff --git a/Week 02/id_636/LeetCode_94_636.py b/Week 02/id_636/LeetCode_94_636.py index 216fc7eb9..e574a470f 100644 --- a/Week 02/id_636/LeetCode_94_636.py +++ b/Week 02/id_636/LeetCode_94_636.py @@ -12,4 +12,15 @@ def inorderTraversal(self, root: TreeNode) -> List[int]: ''' # init result = [] - stack = [(1, root)] + + def loop(root: TreeNode): + if not root: + return + + loop(root.left) + result.append(root.val) + loop(root.right) + + loop(root) + + return result diff --git a/Week 02/id_716/LeetCode_22_716.java b/Week 02/id_716/LeetCode_22_716.java new file mode 100644 index 000000000..519c60100 --- /dev/null +++ b/Week 02/id_716/LeetCode_22_716.java @@ -0,0 +1,40 @@ +import java.util.ArrayList; +import java.util.List; + +// https://leetcode-cn.com/problems/generate-parentheses +// 括号生成 + +public class LeetCode_22_716 { + // 1. 递归解法 + public List generateParenthesis(int n) { + List res = new ArrayList<>(); + _generate(0, 0, n, "", res); + return res; + } + + // 一定是先放左括号,再放右括号,不然不合法 + // 左括号的个数 == 右括号的个数 == n + // 在添加括号的过程中:左括号个数 >= 右括号个数,只有当左括号个数大于右括号个数时才可以添加右括号 + // 只有当左括号个数小于n时才可以添加左括号 + // left: 表示添加的左括号个数;right: 表示添加的右括号个数 + // s: 表示已经生成的字符串 + private void _generate(int left, int right, int n, String s, List res) { + // terminator:左右括号个数都等于n时,生成完毕 + if (left == n && right == n) { + res.add(s); + return; + } + // process current logic: add left or add right + + // drill down + if (left < n) { + _generate(left + 1, right, n, s + "(", res); + } + + if (left > right) { + _generate(left, right + 1, n, s + ")", res); + } + + // revert status + } +} \ No newline at end of file diff --git a/Week 02/id_716/LeetCode_98_716.java b/Week 02/id_716/LeetCode_98_716.java new file mode 100644 index 000000000..010515591 --- /dev/null +++ b/Week 02/id_716/LeetCode_98_716.java @@ -0,0 +1,123 @@ + +// https://leetcode-cn.com/problems/validate-binary-search-tree +// 验证二叉搜索树 + +public class LeetCode_98_716 { + + // 1. 递归实现 + // 重复子问题:当前节点的值是其左子树的上限,是其右子树的下限 + public boolean isValidBST11(TreeNode root) { + return isValid(root, null, null); + } + + // low 表示右子树的下限,不能比他小 + // high 表示左子树的上限,不能比他大 + private boolean isValid(TreeNode node, Integer low, Integer high) { + // terminator + if (node == null) return true; + + // process current logic + int val = node.val; + // 在右子树中每个节点都要大于low,出现小于low的就返回false + if (low != null && val <= low) return false; + // 在左子树中每个节点都要小于high,出现大于high的就返回false + if (high != null && val >= high) return false; + + // drill down + // 陷入下一层,进入的是左子树,如果下一层直接返回了不合法,就提前终止递归,返回不合法 + if (!isValid(node.left, low, val)) return false; + // 陷入下一层,进入的是右子树,如果下一层直接返回了不合法,就提前终止递归,返回不合法 + if (!isValid(node.right, val, high)) return false; + + // default terminator,正常返回合法 + return true; + } + + // 1.2 更加优雅的写法, 简洁一些 + public boolean isValidBST12(TreeNode root) { + return validBSTHelper(root, null, null); + } + + private boolean validBSTHelper(TreeNode node, TreeNode low, TreeNode high) { + // terminator + if (node == null) return true; + // process current logic + if ((low != null && node.val <= low.val) || (high != null && node.val >= high.val)) return false; + // drill down + return validBSTHelper(node.left, low, node) && validBSTHelper(node.right, node, high); + } + + // 2. 利用中序遍历二叉树输出有序序列的特性 + // 这种方式肯定不如直接递归法 + public boolean isValidBST21(TreeNode root) { + List res = new ArrayList<>(); + inorder(root, res); + + // 要保证顺序性 + for (int i = 0; i < res.size() - 1; i++) { + if (res.get(i) >= res.get(i + 1)) { + return false; + } + } + return true; + } + + private void inorder(TreeNode node, List res) { + if (node != null) { + // 加上 if (node.left != null) 的判断,少一层递归 + inorder(node.left, res); + res.add(node.val); + inorder(node.right, res); + } + } + + // 2.2 使用另外一种优化的做法 + // 用 BST 的中序遍历保证前一个节点都小于当前节点 + public boolean isValidBST22(TreeNode root) { + LinkedList stack = new LinkedList<>(); + TreeNode prev = null; + TreeNode curr = root; + while (curr != null || !stack.isEmpty()) { + // 左子树 + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + // 当前节点 + curr = stack.pop(); + if (prev != null && curr.val <= prev.val) + return false; + prev = curr; + // 右节点 + curr = curr.right; + } + + return true; + } + + // 2.3 中序递归的写法 + private TreeNode prev; + public boolean isValidBST23(TreeNode root) { + // terminator + if (root == null) return true; + + // drill down, to left + if (!isValidBST23(root.left)) return false; + + // process current logic + if (prev != null && root.val <= prev.val) return false; + prev = root; + + // drill down, to right + if (!isValidBST23(root.right)) return false; + + // terminator + return true; + } + + // 3. 迭代法, 将递归的实现使用loop的方式进行实现 + public boolean isValidBST3(TreeNode root) { + // todo + return false; + } +} \ No newline at end of file diff --git a/Week 02/id_716/NOTE.md b/Week 02/id_716/NOTE.md index 7049939a3..d597a3213 100644 --- a/Week 02/id_716/NOTE.md +++ b/Week 02/id_716/NOTE.md @@ -2,13 +2,14 @@ ## 关键部分笔记 -#### 哈希表、映射、集合 +### 哈希表、映射、集合 - Java 中HashMap、Set的实现分析 - 讲解题目:242,49 -1. https://leetcode-cn.com/problems/valid-anagram/description/ (done) -2. https://leetcode-cn.com/problems/group-anagrams/ (done) -3. https://leetcode-cn.com/problems/two-sum/description/ (done) + +1. (done) +2. (done) +3. (done) #### 树、二叉树、二叉搜索树 @@ -18,63 +19,70 @@ - 二叉搜索树及操作,查找、插入、删除 - 树的面试题解法一般都是递归,为什么? - 讲解题目:树的遍历 -1. https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ (done) -2. https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ (done) -3. https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ (done) -4. https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ (done) -5. https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ (done) + +1. (done) +2. (done) +3. (done) +4. (done) +5. (done) -#### 范型递归、递归树 +### 范型递归、递归树 - 递归 + 1. 递归的本质是循环,在汇编层是没有循环的,只能通过不停调用重复代码来实现循环的效果 2. 递归是重复性的进行,在现实中也会有体现 3. 可以借鉴电影盗梦空间来理解递归(向下进入到不同层,向上又回到原来的一层;返回上一层可以携带返回值,来改变上一层的状态;每一层都是新的拷贝,每一层可以修改状态,然后返回) 归去来兮,剥洋葱的感觉 -- 递归代码模版:https://shimo.im/docs/DjqqGCT3xqDYwPyY/read +- 递归代码模版: + 1. 先写递归终止条件 2. 当前层的逻辑处理 3. 陷入到下一层 4. 清理当前层 - 递归的难点和误区 + 1. 不要人肉递归(最大误区) 2. 找到最近最简方法,将其拆解成可重复解决的问题(重复子问题) 3. 数学归纳法思维 - 讲解题目:70,22 -1. https://leetcode-cn.com/problems/climbing-stairs/ (done) -2. https://leetcode-cn.com/problems/generate-parentheses/ -3. https://leetcode-cn.com/problems/invert-binary-tree/description/ (done) -4. https://leetcode-cn.com/problems/validate-binary-search-tree -5. https://leetcode-cn.com/problems/maximum-depth-of-binary-tree -6. https://leetcode-cn.com/problems/minimum-depth-of-binary-tree -7. https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ -8. https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ -9. https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal -10. https://leetcode-cn.com/problems/combinations/ -11. https://leetcode-cn.com/problems/permutations/ -12. https://leetcode-cn.com/problems/permutations-ii/ - -#### 分治、回溯 + +1. (done) +2. +3. (done) +4. (done) +5. +6. +7. +8. +9. +10. +11. +12. + +### 分治、回溯 - 一种特殊的递归 - 分治:将一个大问题分解为多个子问题,然后merge子问题 - 分治模版 -1. 终止条件 -2. 准备数据,拆分子问题 -3. 处理子问题,处理、合并生成最终结果 -4. 清理状态 - -- 讲解题目: -1. https://leetcode-cn.com/problems/powx-n/ -2. https://leetcode-cn.com/problems/subsets/ -3. https://leetcode-cn.com/problems/majority-element/description/ (简单、但是高频) -4. https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ -5. https://leetcode-cn.com/problems/n-queens/ + +1. 终止条件 terminator +2. 准备数据,拆分子问题 process current logic, split your big problem +3. 处理子问题,处理、合并生成最终结果 drill down -> sub problems & merge result +4. 清理状态 revert state + +- 讲解题目 + +1. (done) +2. (done) +3. (简单、但是高频) (done) +4. (done) +5. (done) --- @@ -86,7 +94,7 @@ 为什么需要树?当在面临大量的输入数据时,线性表的访问时间就变的很慢了,有没有一种数据结构可以加速访问呢,树就是其中一种,树可以将大部分的操作都优化到 O(logn) 的时间复杂度,可以大大提升效率;此外,我们在日常生活中无时无刻不在使用树,比如想中午吃什么的时候,我们不自觉的构建了一颗决策树,操作系统的文件系统等;(在这篇总结中,不再罗列概念) -##### 树的数学性质 +#### 树的数学性质 有时候了解更多关于树的数学性质有助于解决很多问题,所有的数学性质是直接可以使用的 @@ -103,7 +111,7 @@ 11. 完全二叉树通过本结点的编号可以快速得到父结点、左右孩子的编号;编号为i的父节点为 `i/2`, 左子节点为 `2*i`, 右子节点为 `2*i + 1`(这个性质在堆中得到了很好的应用) 12. etc. -##### 为什么会有那么多特殊化的树 +#### 为什么会有那么多特殊化的树 这是本次总结想要好好分析的。 @@ -119,7 +127,7 @@ 为什么二叉查找树的查找效率高?我们首先来分析一颗完全二叉查找树,这是一种比较理想的状态,因为树的高度是 logn, 也是二叉查找树所有形态中高度最小的树;我们试着来分析一下: -``` +```text // 对于一颗包含 n 个节点完全二叉树 // 1. 除了最后一层外,每一层的节点是上一层节点个数的2倍; 一般的,第一层是1个节点,第二层是2个节点,第三层是4个节点,以此类推 // 2. 最后一层节点的个数在 1 ~ 2^(L-1), 其中 L 表示最大层数 @@ -129,6 +137,7 @@ n >= 1 + 2 + 4 + ... + 2^(L-2) + 1 => log(n+1) <= L <= log(n) + 1 ``` + 可知,L 的最大值是 log(n) + 1, 高度h最大是 log(n); 所以在查找某个元素时,最大查找次数是 log(n), 故而时间复杂度是 O(logn), 很高效;同理,插入、删除操作时间复杂度也是 O(logn) 上面我们说了是一种理想状态,因为数据特点的不同,我们构造出来的二叉查找树可能会退化成链表结构,比如每次都一直插入左子树或一直插入右子树,这个时候查找时间复杂度就是 O(n), 这是不可接受的。那怎么办呢? @@ -150,6 +159,7 @@ AVL的实现有很多,如红黑树,伸展树,AA树,treap 树等,这些 - B+Tree:由二叉查找树演变而来的多叉索引树 有这样一个实际应用,我们需要一个数据库,要将数据持久化存储在磁盘上,并且支持: + 1. 根据某个值快速查找数据 2. 根据某个区间值来查找数据 3. 希望能够按顺序输出某个区间内的数据,升序和降序 @@ -164,9 +174,9 @@ AVL的实现有很多,如红黑树,伸展树,AA树,treap 树等,这些 通过分析各种类型的树及其操作,很清楚的知道了他们的由来、特性、适用的场景以及它能解决的问题,而这个也是我们学习数据结构和算法最核心的地方;在理解了这些的基础上,然后用代码去实现出来并不断优化工程代码。 ---- +--- -// todo 位运算的常用操作 https://www.zhihu.com/question/38206659 +// todo 位运算的常用操作 ### HashMap 总结 @@ -292,7 +302,7 @@ final Node[] resize() { } } } -} +} // 启动扩容的地方,当元素个数大于阈值的时候会触发 // 其中 threshold = Capacity * 装载因子,一切就联系起来了 @@ -301,6 +311,7 @@ if (++size > threshold) ``` 从源代码分析可见,工业级散列表的实现还是比较复杂的,但是原理和思想才是最重要的: + 1. 首先分配一个初始容量,当然也可以通过构造函数来指定,固定一个装载因子,计算出触发扩容的阈值 2. 在每次插入时,判断元素数量是否到达阈值,到了就触发扩容策略 3. 扩容策略是在原来的基础上double,如果没有指定或者为0就使用默认初始容量16 @@ -335,7 +346,7 @@ static class Node implements Map.Entry { ``` 盗用一张图,就是这样的 -![](https://img-blog.csdn.net/20170317181650025?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVzdGxvdmV5b3Vf/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) +![hashmap](https://img-blog.csdn.net/20170317181650025?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVzdGxvdmV5b3Vf/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 但是,当某个位置的链表过长时,会造成查找和插入的时间复杂度增加,HashMap 在这里做了一个优化,当链表长度超过某个值时,就将链表转换成红黑树,当红黑树的元素个数小于某个值时,会转成链表. diff --git a/Week 03/id_006/LeetCode_102_006.java b/Week 03/id_006/LeetCode_102_006.java new file mode 100644 index 000000000..c101457cf --- /dev/null +++ b/Week 03/id_006/LeetCode_102_006.java @@ -0,0 +1,72 @@ +package com.mrglint.leetcode.week03.solution102; + +import com.mrglint.leetcode.TreeNode; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-10-30 22:26 + */ +public class Solution { + /** + * 广度优先遍历 + * @param root + * @return + */ + public List> levelOrder1(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + List subResult = new ArrayList<>(); + while (size-- > 0) { + TreeNode queueHead = queue.poll(); + if (Objects.nonNull(queueHead)) { + subResult.add(queueHead.val); + if (queueHead.left != null) { + queue.offer(queueHead.left); + } + if (queueHead.right != null) { + queue.offer(queueHead.right); + } + } + } + result.add(subResult); + } + return result; + } + + /** + * 深度优先遍历 + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + levelOrder(root, 0, result); + return result; + } + + private void levelOrder(TreeNode node, int level, List> result) { + if (result.size() == level) { + result.add(new ArrayList<>()); + } + result.get(level).add(node.val); + if (Objects.nonNull(node.left)) { + levelOrder(node.left, level + 1, result); + } + if (Objects.nonNull(node.right)) { + levelOrder(node.right, level + 1, result); + } + } +} + diff --git a/Week 03/id_006/LeetCode_126_006.java b/Week 03/id_006/LeetCode_126_006.java new file mode 100644 index 000000000..10f717a39 --- /dev/null +++ b/Week 03/id_006/LeetCode_126_006.java @@ -0,0 +1,130 @@ +package com.mrglint.leetcode.week03.solution126; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-11-01 08:26 + */ +public class Solution { + /** + * 字典 + */ + private char[] initialTable = {'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z'}; + + public List> findLadders(String beginWord, String endWord, List wordList) { + /** + * 使用hashset提供O(1)的时间复杂度的读取操作 + */ + Set dictionary = new HashSet<>(wordList); + + List> result = new ArrayList<>(); + if (!dictionary.contains(endWord)) { + return result; + } + + Map distance = getDistance(beginWord, endWord, new HashSet<>(dictionary)); + + List subResult = new LinkedList<>(); + subResult.add(beginWord); + findLadders(beginWord, endWord, dictionary, distance, subResult, result); + return result; + } + + /** + * 广度优先搜索,获取到最短路径上,字符串所在节点的深度 + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + private Map getDistance(String beginWord, String endWord, Set wordList) { + Map distance = new HashMap<>(); + + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + int level = 0; + boolean found = false; + while (!queue.isEmpty()) { + int size = queue.size(); + + // 同一层遍历完毕 + while (size-- > 0) { + String queueHead = queue.poll(); + if (!distance.containsKey(queueHead)) { + distance.put(queueHead, level); + } + if (Objects.equals(queueHead, endWord)) { + found = true; + } + for (int i = 0; i < queueHead.length(); i++) { + char[] chars = queueHead.toCharArray(); + for (char c : initialTable) { + char temp = chars[i]; + if (c != chars[i]) { + chars[i] = c; + String newString = new String(chars); + if (wordList.contains(newString)) { + wordList.remove(newString); + queue.offer(newString); + } + } + chars[i] = temp; + } + } + } + level++; + if (found) { + break; + } + } + return distance; + } + + /** + * 深度优先搜索,计算最短路径。 + * 借助 + * @param beginWord + * @param endWord + * @param dictionary + * @param subResult + * @param result + */ + private void findLadders(String beginWord, String endWord, Set dictionary, Map distance, List subResult, List> result) { + // terminator + if (Objects.equals(beginWord, endWord)) { + result.add(subResult); + return; + } + + // process current level logic + for (int i = 0; i < beginWord.length(); i++) { + char[] chars = beginWord.toCharArray(); + for (char c : initialTable) { + if (chars[i] != c) { + char temp = chars[i]; + chars[i] = c; + String newString = new String(chars); + if (dictionary.contains(newString)) { + // drill down + subResult.add(newString); + dictionary.remove(newString); + // 1. 获取不到距离的,说明该字符串所在路径非最短路径 + // 2. 如果当前字符串的距离 + 1 == 下一个节点字符串的距离 说明这两个字符串所在路径为最短路径上的节点 + if (Objects.nonNull(distance.get(beginWord)) && Objects.nonNull(distance.get(newString)) && distance.get(beginWord) + 1 == distance.get(newString)) { + findLadders(newString, endWord, dictionary, distance, new ArrayList<>(subResult), result); + } + + // restore state + subResult.remove(subResult.size() - 1); + dictionary.add(newString); + } + chars[i] = temp; + } + } + } + } +} + diff --git a/Week 03/id_006/LeetCode_127_006.java b/Week 03/id_006/LeetCode_127_006.java new file mode 100644 index 000000000..6bcca011f --- /dev/null +++ b/Week 03/id_006/LeetCode_127_006.java @@ -0,0 +1,55 @@ +package com.mrglint.leetcode.week03.solution127; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-11-01 07:09 + */ +public class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + char[] initialTable = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z'}; + // 使用map作为去重判断,不然会超时 + Map map = new HashMap<>(wordList.size()); + for (String s : wordList) { + map.put(s, true); + } + + if (!map.containsKey(endWord)) { + return 0; + } + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + map.remove(beginWord); + int transformationCount = 1; + while (!queue.isEmpty()) { + int size = queue.size(); + + while (size-- > 0) { + String queueHead = queue.poll(); + if (Objects.equals(queueHead, endWord)) { + return transformationCount; + } + for (int i = 0; i < beginWord.length(); i++) { + for (char c : initialTable) { + char[] chars = queueHead.toCharArray(); + if (chars[i] != c) { + chars[i] = c; + String variant = new String(chars); + + if (map.containsKey(variant)) { + map.remove(variant); + queue.offer(variant); + } + } + } + } + } + transformationCount++; + } + return 0; + } +} + diff --git a/Week 03/id_006/LeetCode_200_006.java b/Week 03/id_006/LeetCode_200_006.java new file mode 100644 index 000000000..ab8c142cb --- /dev/null +++ b/Week 03/id_006/LeetCode_200_006.java @@ -0,0 +1,72 @@ +package com.mrglint.leetcode.week03.solution200; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author luhuancheng + * @since 2019-11-03 07:50 + */ +public class BfsSolution { + + /** + * 声明坐标位上「上、左、下、右」四个位置的偏移量 + */ + private int[][] directions = new int[][]{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + + /** + * 全局变量 存储结果 + */ + private int count = 0; + + public int numIslands(char[][] grid) { + /* + 数组为空 + */ + if (grid.length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + + /* + 标记坐标被访问的辅助数组 + */ + boolean[][] visited = new boolean[rows][cols]; + + /* + 广度优先遍历 + */ + Queue queue = new LinkedList<>(); + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + if (!visited[row][col] && grid[row][col] == '1') { + // 以char[row][col]作为根开始进行广度优先遍历,每个根记为一个岛屿 + count++; + visited[row][col] = true; + queue.offer(new int[]{row, col}); + while (!queue.isEmpty()) { + int[] queueHead = queue.poll(); + int queueRow = queueHead[0]; + int queueCol = queueHead[1]; + for (int i = 0; i < directions.length; i++) { + int newRow = queueRow + directions[i][0]; + int newCol = queueCol + directions[i][1]; + if (inArea(newRow, newCol, rows, cols) && !visited[newRow][newCol] && grid[newRow][newCol] == '1') { + visited[newRow][newCol] = true; + queue.offer(new int[]{newRow, newCol}); + } + } + } + } + } + } + return count; + } + + private boolean inArea(int row, int col, int rows, int cols) { + return row >= 0 && row < rows && col >= 0 && col < cols; + } +} + diff --git a/Week 03/id_006/LeetCode_322_006.java b/Week 03/id_006/LeetCode_322_006.java new file mode 100644 index 000000000..ea671b8f8 --- /dev/null +++ b/Week 03/id_006/LeetCode_322_006.java @@ -0,0 +1,77 @@ +package com.mrglint.leetcode.week03.solution322; + +import java.util.HashMap; +import java.util.Map; + +/** + * 贪心法无法求解该问题 + * + * @author luhuancheng + * @since 2019-11-03 16:40 + */ +public class Solution { + /** + * 分治、回溯角度思考:假设硬币为[10, 9, 1],兑换总额为18,那么问题可以转换为f(18) = min(f(18 - 10), f(18 - 9), f(18 - 1)) 直到硬币兑换成功 + * 傻递归,leetcode 超时 + * @param coins + * @param amount + * @return + */ + public int coinChange1(int[] coins, int amount) { + if (amount == 0) { + return 0; + } + int count = Integer.MAX_VALUE; + for (int coin : coins) { + if (amount - coin < 0) { + continue; + } + // 分解为子问题 + int subProb = coinChange1(coins, amount - coin); + // 子问题无解,回溯上层 + if (subProb == -1) { + continue; + } + count = Math.min(count, subProb + 1); + } + return count == Integer.MAX_VALUE ? -1 : count; + } + + /** + * 加缓存递归 + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + Map cache = new HashMap<>(); + return coinChange(coins, amount, cache); + } + + private int coinChange(int[] coins, int amount, Map cache) { + if (amount == 0) { + return 0; + } + // 从缓存中获取结果 + if (cache.containsKey(amount)) { + return cache.get(amount); + } + // 计算f(amount) : 将问题转换为f(amount) = min(f(amount - coin1), f(amount - coin2)) + int count = Integer.MAX_VALUE; + for (int coin : coins) { + if (amount - coin < 0) { + continue; + } + int subProb = coinChange(coins, amount - coin, cache); + if (subProb == -1) { + continue; + } + count = Math.min(count, subProb + 1); + } + // 计算结果放入缓存 + cache.put(amount, count == Integer.MAX_VALUE ? - 1 : count); + return cache.get(amount); + } + +} + diff --git a/Week 03/id_006/LeetCode_433_006.java b/Week 03/id_006/LeetCode_433_006.java new file mode 100644 index 000000000..3af36d402 --- /dev/null +++ b/Week 03/id_006/LeetCode_433_006.java @@ -0,0 +1,61 @@ +package com.mrglint.leetcode.week03.solution433; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-10-31 08:37 + */ +public class Solution { + public int minMutation(String start, String end, String[] bank) { + // 建立基因字典 ["A", "C", "G", "T"] + char[] mutationMeta = new char[]{'A', 'C', 'G', 'T'}; + // 建立基因库映射,方便查看变异基因是否存在于基因库 + Map geneMap = new HashMap<>(bank.length); + for (String s : bank) { + geneMap.put(s, true); + } + Set known = new HashSet<>(); + + int mutationCount = 0; + Queue queue = new LinkedList<>(); + queue.offer(start); + known.add(start); + while (!queue.isEmpty()) { + int size = queue.size(); + while (size-- > 0) { + String queueHead = queue.poll(); + if (Objects.equals(queueHead, end)) { + return mutationCount; + } + // 进行变异 + for (int i = 0; i < queueHead.length(); i++) { + for (char c : mutationMeta) { + char[] chars = queueHead.toCharArray(); + if (chars[i] != c) { + chars[i] = c; + String mutationGene = new String(chars); + if (geneMap.containsKey(mutationGene) && !known.contains(mutationGene)) { + queue.offer(mutationGene); + known.add(mutationGene); + } + } + } + } + } + mutationCount++; + } + return -1; + } + + public static void main(String[] args) { + /** + * "AACCGGTT" + * "AACCGCTA" + * ["AACCGGTA","AACCGCTA","AAACGGTA"] + */ + Solution solution = new Solution(); + System.out.println(solution.minMutation("AACCGGTT", "AACCGCTA", new String[]{"AACCGGTA","AACCGCTA","AAACGGTA"})); + } +} + diff --git a/Week 03/id_006/LeetCode_455_006.java b/Week 03/id_006/LeetCode_455_006.java new file mode 100644 index 000000000..d416a86c8 --- /dev/null +++ b/Week 03/id_006/LeetCode_455_006.java @@ -0,0 +1,33 @@ +package com.mrglint.leetcode.week03.solution455; + +import java.util.Arrays; + +/** + * @author luhuancheng + * @since 2019-11-03 22:17 + */ +public class Solution { + public int findContentChildren(int[] g, int[] s) { + if (g.length == 0 || s.length == 0) { + return 0; + } + // 从小到大排序 + Arrays.sort(g); + Arrays.sort(s); + + int count = 0; + int childrenIndex = 0; + int cookieIndex = 0; + while (childrenIndex < g.length && cookieIndex < s.length) { + if (s[cookieIndex] < g[childrenIndex]) { + cookieIndex++; + } else { + cookieIndex++; + childrenIndex++; + count++; + } + } + return count; + } +} + diff --git a/Week 03/id_006/LeetCode_515_006.java b/Week 03/id_006/LeetCode_515_006.java new file mode 100644 index 000000000..ba4c80009 --- /dev/null +++ b/Week 03/id_006/LeetCode_515_006.java @@ -0,0 +1,41 @@ +package com.mrglint.leetcode.week03.solution515; + +import com.mrglint.leetcode.TreeNode; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-10-31 22:11 + */ +public class Solution { + + public List largestValues(TreeNode root) { + List result = new ArrayList<>(); + if (Objects.isNull(root)) { + return result; + } + + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + int max = Integer.MIN_VALUE; + while (size-- > 0) { + TreeNode queueHead = queue.poll(); + if (Objects.nonNull(queueHead)) { + max = Math.max(max, queueHead.val); + if (Objects.nonNull(queueHead.left)) { + queue.offer(queueHead.left); + } + if (Objects.nonNull(queueHead.right)) { + queue.offer(queueHead.right); + } + } + } + result.add(max); + } + return result; + } +} + diff --git a/Week 03/id_006/LeetCode_529_006.java b/Week 03/id_006/LeetCode_529_006.java new file mode 100644 index 000000000..9bed39af5 --- /dev/null +++ b/Week 03/id_006/LeetCode_529_006.java @@ -0,0 +1,119 @@ +package com.mrglint.leetcode.week03.solution529; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author luhuancheng + * @since 2019-11-03 14:10 + */ +public class Solution { + + /** + * 未挖出炸弹 + */ + private static final char BOMBSHELL = 'M'; + + /** + * 未挖出空地 + */ + private static final char NOT_TO_DIG_BLACK = 'E'; + + /** + * 安全区域 + */ + private static final char SAFE_AREA = 'B'; + + /** + * 爆炸区域 + */ + private static final char EXPLODE_AREA = 'X'; + + /** + * 周围八个位置的坐标偏移 + */ + private static final int[][] DIRECTIONS = new int[][]{{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}}; + + /** + * 思路:广度优先搜索 + * 要点:当周围没有炸弹,则遍历周围节点;否则获取周围炸点节点,标记为数字 + * + * @param board + * @param click + * @return + */ + public char[][] updateBoard(char[][] board, int[] click) { + int clickRow = click[0]; + int clickCol = click[1]; + + int rows = board.length; + int cols = board[0].length; + + // 标记节点是否被访问 + boolean[][] visited = new boolean[rows][cols]; + + // 点击到炸弹 + if (board[clickRow][clickCol] == BOMBSHELL) { + board[clickRow][clickCol] = EXPLODE_AREA; + return board; + } + + Queue queue = new LinkedList<>(); + queue.offer(click); + visited[clickRow][clickCol] = true; + while (!queue.isEmpty()) { + int[] queueHead = queue.poll(); + int row = queueHead[0]; + int col = queueHead[1]; + + int number = getBombShellNumber(row, col, rows, cols, board); + if (number == 0) { + // 周围没有炸弹,标记为 'B' + board[row][col] = SAFE_AREA; + // 遍历八个相连节点 + for (int i = 0; i < DIRECTIONS.length; i++) { + int newRow = row + DIRECTIONS[i][0]; + int newCol = col + DIRECTIONS[i][1]; + // 不越界 && 未访问过 && 未被翻过 + if (inArea(newRow, newCol, rows, cols) && !visited[newRow][newCol] && board[newRow][newCol] == NOT_TO_DIG_BLACK) { + visited[newRow][newCol] = true; + queue.offer(new int[]{newRow, newCol}); + } + } + } else { + // Character.forDigit(number, 10) 转为10进制的 char 类型标识 + board[row][col] = Character.forDigit(number, 10); + } + } + return board; + } + + private int getBombShellNumber(int clickRow, int clickCol, int rows, int cols, char[][] board) { + int result = 0; + for (int i = 0; i < DIRECTIONS.length; i++) { + int newRow = clickRow + DIRECTIONS[i][0]; + int newCol = clickCol + DIRECTIONS[i][1]; + + if (inArea(newRow, newCol, rows, cols) && board[newRow][newCol] == BOMBSHELL) { + result++; + } + } + return result; + } + + private boolean inArea(int row, int col, int rows, int cols) { + return row >= 0 && row < rows && col >= 0 && col < cols; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + char[][] board = new char[][]{{'E', 'E', 'E', 'E', 'E'}, {'E', 'E', 'M', 'E', 'E'}, {'E', 'E', 'E', 'E', 'E'}, {'E', 'E', 'E', 'E', 'E'}}; + int[] click = new int[]{3, 0}; + char[][] result = solution.updateBoard(board, click); + for (char[] ca : result) { + System.out.println(Arrays.toString(ca)); + } + } +} + diff --git a/Week 03/id_006/LeetCode_860_006.java b/Week 03/id_006/LeetCode_860_006.java new file mode 100644 index 000000000..62036da84 --- /dev/null +++ b/Week 03/id_006/LeetCode_860_006.java @@ -0,0 +1,38 @@ +package com.mrglint.leetcode.week03.solution860; + +/** + * @author luhuancheng + * @since 2019-11-03 21:55 + */ +public class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + + for (int i : bills) { + if (i == 5) { + five++; + } else if (i == 10) { + if (five > 0) { + five--; + ten++; + } else { + return false; + } + } else if (i == 20) { + if (ten > 0 && five > 0) { + ten--; + five--; + } else { + if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + } + return true; + } +} + diff --git a/Week 03/id_006/NOTE.md b/Week 03/id_006/NOTE.md index a6321d6e2..9602f4e57 100644 --- a/Week 03/id_006/NOTE.md +++ b/Week 03/id_006/NOTE.md @@ -1,4 +1,33 @@ -# NOTE +## 学习总结 +### 本周学习收获 +- 深度、广度优先搜索 +- 贪心法:应用时需要能证明应用贪心法可以求的最优解,比如「兑换硬币」这个问题就无法使用贪心法求解 +- 二分查找:基于有序、可通过索引直接访问的数据,可以利用二分法一次排除掉一半的备选项,加快搜索速度 - +### 代码技巧 +- 二维数组坐标周围的八个节点偏移变换:new int[][]{{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}},可以利用当前坐标加上该二维数组中的偏移量来获得周边节点 +### 二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 +```java +public class FindNotOrderIndex { + public int notOrderIndex(int[] data) { + int lo = 0; + int hi = data.length - 1; + while (lo < hi) { + int mid = lo + (hi - lo) / 2; + // 中间元素大于最后一个元素,说明[mid, data.length)是有序的,排除掉 + if (data[mid] < data[data.length - 1]) { + hi = mid; + } else { + lo = mid + 1; + } + } + return lo; + } + + public static void main(String[] args) { + FindNotOrderIndex findNotOrderIndex = new FindNotOrderIndex(); + System.out.println(findNotOrderIndex.notOrderIndex(new int[]{4, 5, 6, 7, 0, 1, 2})); + } +} +``` diff --git a/Week 03/id_011/assign-cookies.go b/Week 03/id_011/assign-cookies.go new file mode 100644 index 000000000..75d74c703 --- /dev/null +++ b/Week 03/id_011/assign-cookies.go @@ -0,0 +1,21 @@ +package algorithm00401 + +import "sort" + +func findContentChildren(g []int, s []int) int { + sort.Sort(sort.Reverse(sort.IntSlice(g))) + sort.Sort(sort.Reverse(sort.IntSlice(s))) + + var res int + gi, si := 0, 0 + for gi < len(g) && si < len(s) { + if s[si] >= g[gi] { + res++ + gi++ + si++ + } else { + gi++ + } + } + return res +} diff --git a/Week 03/id_011/best-time-to-buy-annd-sell-stock-ii.go b/Week 03/id_011/best-time-to-buy-annd-sell-stock-ii.go new file mode 100644 index 000000000..631489016 --- /dev/null +++ b/Week 03/id_011/best-time-to-buy-annd-sell-stock-ii.go @@ -0,0 +1,11 @@ +package algorithm00401 + +func maxProfit(prices []int) int { + profit := 0 + for i := 1; i < len(prices); i++ { + if prices[i] > prices[i-1] { + profit += prices[i] - prices[i-1] + } + } + return profit +} diff --git a/Week 03/id_011/best-time-to-buy-annd-sell-stock.go b/Week 03/id_011/best-time-to-buy-annd-sell-stock.go new file mode 100644 index 000000000..e3a72e59e --- /dev/null +++ b/Week 03/id_011/best-time-to-buy-annd-sell-stock.go @@ -0,0 +1,14 @@ +package algorithm00401 + +func maxProfit(prices []int) int { + minProfit := 1 << 31 + maxProfit := 0 + for i := 0; i < len(prices); i++ { + if prices[i] < minProfit { + minProfit = prices[i] + } else if prices[i]-minProfit > maxProfit { + maxProfit = prices[i] - minProfit + } + } + return maxProfit +} diff --git a/Week 03/id_011/binary-tree-level-order-traversal.go b/Week 03/id_011/binary-tree-level-order-traversal.go new file mode 100644 index 000000000..092e3b31d --- /dev/null +++ b/Week 03/id_011/binary-tree-level-order-traversal.go @@ -0,0 +1,35 @@ +package algorithm00401 + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +var ans [][]int + +func levelOrder(root *TreeNode) [][]int { + ans = make([][]int, 0) + dfs(root, 0) + return ans +} + +func dfs(root *TreeNode, level int) { + // recursion terminator + if root == nil { + retrun + } + + // process logic in current level + if level >= len(ans) { + ans = append(ans, make([]int, 0)) + } + ans[level] = append(ans[level], root.Val) + + // drill down + dfs(root.Left, level+1) + dfs(root.Right, level+1) +} diff --git a/Week 03/id_011/find-minimum-in-rotated-sorted-array.go b/Week 03/id_011/find-minimum-in-rotated-sorted-array.go new file mode 100644 index 000000000..42bfcc9c2 --- /dev/null +++ b/Week 03/id_011/find-minimum-in-rotated-sorted-array.go @@ -0,0 +1,18 @@ +package algorithm00401 + +func findMin(nums []int) int { + l, r := 0, len(nums)-1 + for l < r { + mid := l + (r-l)/2 + if nums[l] >= nums[mid] && nums[mid] >= nums[r] { + return nums[r] + } else if nums[mid] > nums[r] { + l = mid + 1 + } else if nums[l] > nums[mid] { + r = mid + } else { + return nums[l] + } + } + return nums[l] +} diff --git a/Week 03/id_011/jump-game-ii.go b/Week 03/id_011/jump-game-ii.go new file mode 100644 index 000000000..ecbd20923 --- /dev/null +++ b/Week 03/id_011/jump-game-ii.go @@ -0,0 +1,17 @@ +package algorithm00401 + +func jump(nums []int) int { + step := 0 + + position := len(nums) - 1 + for position != 0 { + for i := 0; i < position; i++ { + if nums[i] >= position-i { + position = i + step++ + break + } + } + } + return step +} diff --git a/Week 03/id_011/jump-game.go b/Week 03/id_011/jump-game.go new file mode 100644 index 000000000..1c70a7d8b --- /dev/null +++ b/Week 03/id_011/jump-game.go @@ -0,0 +1,11 @@ +package algorithm00401 + +func canJump(nums []int) bool { + last := len(nums) - 1 + for i := len(nums) - 1; i >= 0; i-- { + if i+nums[i] >= last { + last = i + } + } + return last == 0 +} diff --git a/Week 03/id_011/lemonade-change.go b/Week 03/id_011/lemonade-change.go new file mode 100644 index 000000000..28e44e8b6 --- /dev/null +++ b/Week 03/id_011/lemonade-change.go @@ -0,0 +1,26 @@ +package algorithm00401 + +func lemonadeChange(bills []int) bool { + five, ten := 0, 0 + for i := 0; i < len(bills); i++ { + if bills[i] == 5 { + five++ + } else if bills[i] == 10 { + if five == 0 { + return false + } + five-- + ten++ + } else { + if five > 0 && ten > 0 { + ten-- + five++ + } else if five > 3 { + five -= 3 + } else { + return false + } + } + } + return true +} diff --git a/Week 03/id_011/number-of-islands.go b/Week 03/id_011/number-of-islands.go new file mode 100644 index 000000000..482dd2763 --- /dev/null +++ b/Week 03/id_011/number-of-islands.go @@ -0,0 +1,31 @@ +package algorithm00401 + +func numIslands(grid [][]byte) int { + if len(grid) == 0 { + return 0 + } + res := 0 + + n := len(grid) + m := len(grid[0]) + for i := 0; i < n; i++ { + for j := 0; j < m; j++ { + if grid[i][j] == '1' { + res++ + inflect(grid, i, j, n, m) + } + } + } + return res +} + +func inflect(grid [][]byte, i, j, n, m int) { + if i < 0 || i >= n || j < 0 || j >= m || grid[i][j] != '1' { + return + } + grid[i][j] = '2' + inflect(grid, i+1, j, n, m) + inflect(grid, i-1, j, n, m) + inflect(grid, i, j+1, n, m) + inflect(grid, i, j-1, n, m) +} diff --git a/Week 03/id_011/search-in-rotated-sorted-array.go b/Week 03/id_011/search-in-rotated-sorted-array.go new file mode 100644 index 000000000..87a6cbc52 --- /dev/null +++ b/Week 03/id_011/search-in-rotated-sorted-array.go @@ -0,0 +1,29 @@ +package algorithm00401 + +func search(nums []int, target int) int { + l, r := 0, len(nums) + for l < r { + mid := l + (r-l)/2 + if nums[mid] == target { + return mid + } else if nums[l] == target { + return l + } else if nums[r-1] == target { + return r - 1 + } + if nums[l] < nums[mid] { + if target > nums[mid] || nums[l] > target { + l = mid + 1 + } else { + r = mid + } + } else { + if nums[mid] > target || target > nums[r-1] { + r = mid + } else { + l = mid + 1 + } + } + } + return -1 +} diff --git a/Week 03/id_011/word-ladder.go b/Week 03/id_011/word-ladder.go new file mode 100644 index 000000000..5f155c6ff --- /dev/null +++ b/Week 03/id_011/word-ladder.go @@ -0,0 +1,40 @@ +package algorithm00401 + +func ladderLength(beginWord string, endWord string, wordList []string) int { + dict := make(map[string]bool) + for _, word := range wordList { + dict[word] = true + } + if !dict[endWord] { + return 0 + } + step := 0 + q1 := map[string]bool{beginWord: true} + q2 := map[string]bool{endWord: true} + for len(q1) > 0 && len(q2) > 0 { + step++ + if len(q1) > len(q2) { + q1, q2 = q2, q1 + } + q := make(map[string]bool) + for w, _ := range q1 { + for i := 0; i < len(beginWord); i++ { + chars := []rune(w) + for j := 'a'; j <= 'z'; j++ { + chars[i] = j + newWord := string(chars) + if q2[newWord] { + return step + 1 + } + if !dict[newWord] { + continue + } + delete(dict, newWord) + q[newWord] = true + } + } + } + q1, q = q, q1 + } + return 0 +} diff --git a/Week 03/id_016/LeetCode_102_016.js b/Week 03/id_016/LeetCode_102_016.js new file mode 100644 index 000000000..364dac767 --- /dev/null +++ b/Week 03/id_016/LeetCode_102_016.js @@ -0,0 +1,76 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-11-02 19:58:19 + * @LastEditTime: 2019-11-02 19:59:03 + */ +/* + * @lc app=leetcode id=102 lang=javascript + * + * [102] Binary Tree Level Order Traversal + * + * https://leetcode.com/problems/binary-tree-level-order-traversal/description/ + * + * algorithms + * Medium (50.41%) + * Likes: 1907 + * Dislikes: 48 + * Total Accepted: 456.1K + * Total Submissions: 899K + * Testcase Example: '[3,9,20,null,null,15,7]' + * + * Given a binary tree, return the level order traversal of its nodes' values. + * (ie, from left to right, level by level). + * + * + * For example: + * Given binary tree [3,9,20,null,null,15,7], + * + * ⁠ 3 + * ⁠ / \ + * ⁠ 9 20 + * ⁠ / \ + * ⁠ 15 7 + * + * + * + * return its level order traversal as: + * + * [ + * ⁠ [3], + * ⁠ [9,20], + * ⁠ [15,7] + * ] + * + * + 1. DFS 传入level层级 + 2. BFS + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +var levelOrder = function(root) { + let res = []; + let deal = (node, level) => { + if (!node) return; + if (!res[level - 1]) res[level - 1] = []; + res[level - 1].push(node.val); + deal(node.left, level + 1); + deal(node.right, level + 1); + }; + deal(root, 1); + return res; +}; +// @lc code=end + diff --git a/Week 03/id_016/LeetCode_153_016.js b/Week 03/id_016/LeetCode_153_016.js new file mode 100644 index 000000000..85f7c8bfe --- /dev/null +++ b/Week 03/id_016/LeetCode_153_016.js @@ -0,0 +1,82 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-30 22:23:09 + * @LastEditTime: 2019-10-31 23:18:23 + */ +/* + * @lc app=leetcode id=153 lang=javascript + * + * [153] Find Minimum in Rotated Sorted Array + * + * https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/ + * + * algorithms + * Medium (43.67%) + * Likes: 1313 + * Dislikes: 187 + * Total Accepted: 336.2K + * Total Submissions: 767.9K + * Testcase Example: '[3,4,5,1,2]' + * + * Suppose an array sorted in ascending order is rotated at some pivot unknown + * to you beforehand. + * + * (i.e.,  [0,1,2,4,5,6,7] might become  [4,5,6,7,0,1,2]). + * + * Find the minimum element. + * + * You may assume no duplicate exists in the array. + * + * Example 1: + * + * + * Input: [3,4,5,1,2] + * Output: 1 + * + * + * Example 2: + * + * + * Input: [4,5,6,7,0,1,2] + * Output: 0 + * + * + 1.全部暴力, 查找最小值 + 2.暴力循环 找无序 时间O(n) + 3.二分法 时间O(logn)) + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +// var findMin = function(nums) { +// let res = nums[0]; +// for (let i = 0; i < nums.length - 1; i++) { +// if (nums[i] > nums[i + 1]) { +// res = nums[i + 1]; +// break; +// } +// } +// return res; +// }; + +var findMin = function(nums) { + if (nums[0] < nums[nums.length - 1]) return nums[0]; + let right = nums.length - 1; + let left = 0; + while (left < right) { + let mid = left + Math.floor((right - left) / 2); + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + right = mid; + } + } + return nums[left]; +}; +// @lc code=end +console.log(findMin([3, 1, 2])); diff --git a/Week 03/id_016/LeetCode_22_016.js b/Week 03/id_016/LeetCode_22_016.js new file mode 100644 index 000000000..0d4352c95 --- /dev/null +++ b/Week 03/id_016/LeetCode_22_016.js @@ -0,0 +1,62 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-26 15:45:05 + * @LastEditTime: 2019-10-26 16:04:44 + */ +/* + * @lc app=leetcode id=22 lang=javascript + * + * [22] Generate Parentheses + * + * https://leetcode.com/problems/generate-parentheses/description/ + * + * algorithms + * Medium (57.41%) + * Likes: 3475 + * Dislikes: 206 + * Total Accepted: 411.4K + * Total Submissions: 712.8K + * Testcase Example: '3' + * + * + * Given n pairs of parentheses, write a function to generate all combinations + * of well-formed parentheses. + * + * + * + * For example, given n = 3, a solution set is: + * + * + * [ + * ⁠ "((()))", + * ⁠ "(()())", + * ⁠ "(())()", + * ⁠ "()(())", + * ⁠ "()()()" + * ] + * + */ + +// @lc code=start +/** + * @param {number} n + * @return {string[]} + */ +var generateParenthesis = function(n) { + let res = []; + let deal = (left = n, right = n, str = '') => { + if (str.length === n * 2) { + res.push(str); + return; + } + if (left > 0) deal(left - 1, right, str + '('); + // 注意括号的规则就可以:放置右括号前必须保证左括号的数量多于右括号 + if (right > 0 && left < right) deal(left, right - 1, str + ')'); + }; + deal(); + return res; +}; +// @lc code=end +console.log(generateParenthesis(3)); diff --git a/Week 03/id_016/LeetCode_55_016.js b/Week 03/id_016/LeetCode_55_016.js new file mode 100644 index 000000000..ac4630a51 --- /dev/null +++ b/Week 03/id_016/LeetCode_55_016.js @@ -0,0 +1,68 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-30 22:00:00 + * @LastEditTime: 2019-10-30 22:00:36 + */ +/* + * @lc app=leetcode id=55 lang=javascript + * + * [55] Jump Game + * + * https://leetcode.com/problems/jump-game/description/ + * + * algorithms + * Medium (32.67%) + * Likes: 2544 + * Dislikes: 241 + * Total Accepted: 321.1K + * Total Submissions: 980.4K + * Testcase Example: '[2,3,1,1,4]' + * + * Given an array of non-negative integers, you are initially positioned at the + * first index of the array. + * + * Each element in the array represents your maximum jump length at that + * position. + * + * Determine if you are able to reach the last index. + * + * Example 1: + * + * + * Input: [2,3,1,1,4] + * Output: true + * Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last + * index. + * + * + * Example 2: + * + * + * Input: [3,2,1,0,4] + * Output: false + * Explanation: You will always arrive at index 3 no matter what. Its + * maximum + * jump length is 0, which makes it impossible to reach the last index. + * + * + + 1. 贪心算法,从后往前贪心 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function(nums) { + let last = nums.length - 1; + for (let i = last - 1; i >= 0; i--) { + if (nums[i] + i >= last) { + last = i; + } + } + return last === 0; +}; +// @lc code=end diff --git a/Week 03/id_016/LeetCode_69_016.js b/Week 03/id_016/LeetCode_69_016.js new file mode 100644 index 000000000..e70e14d49 --- /dev/null +++ b/Week 03/id_016/LeetCode_69_016.js @@ -0,0 +1,72 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-31 08:54:26 + * @LastEditTime: 2019-10-31 08:55:22 + */ +/* + * @lc app=leetcode id=69 lang=javascript + * + * [69] Sqrt(x) + * + * https://leetcode.com/problems/sqrtx/description/ + * + * algorithms + * Easy (32.22%) + * Likes: 932 + * Dislikes: 1568 + * Total Accepted: 434.6K + * Total Submissions: 1.3M + * Testcase Example: '4' + * + * Implement int sqrt(int x). + * + * Compute and return the square root of x, where x is guaranteed to be a + * non-negative integer. + * + * Since the return type is an integer, the decimal digits are truncated and + * only the integer part of the result is returned. + * + * Example 1: + * + * + * Input: 4 + * Output: 2 + * + * + * Example 2: + * + * + * Input: 8 + * Output: 2 + * Explanation: The square root of 8 is 2.82842..., and since + * the decimal part is truncated, 2 is returned. + * + * + 1. 二分法解决,边界情况考虑 + 2. 牛顿迭代 + */ + +// @lc code=start +/** + * @param {number} x + * @return {number} + */ +var mySqrt = function(x) { + if (x === 0 || x === 1) return x; + let left = 0, + right = x; + let mid = null; + while (left <= right) { + mid = Math.ceil((left + right) / 2); + if (mid * mid == x) return mid; + if (x < mid * mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return Math.floor(right); +}; +// @lc code=end diff --git a/Week 03/id_016/NOTE.md b/Week 03/id_016/NOTE.md index a6321d6e2..faa4ba693 100644 --- a/Week 03/id_016/NOTE.md +++ b/Week 03/id_016/NOTE.md @@ -1,4 +1,33 @@ # NOTE - +二分查找特征: +1. 目标函数是单调的(单调递增,或者递减) +2. 存在上下界(bounded) +3. 能够通过索引访问(index accessible) + +# 二分法 - 代码模版 +```javascript +function main(arr, target) { + // 1.定义左右边界 + let left = 0, + right = arr.length - 1; + let res = null; + // 2.循环,当左小于右的时候 + while (left < right) { + // 3.获取中间值下边 + let mid = Math.floor((left + right) / 2); + // 4.中间值和目标值进行比较 + if (target === arr[mid]) { + res = mid; + break; + // 目标值大于中间值,说明目标值在mid右侧 + } else if (target > arr[mid]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return res; +} +``` diff --git a/Week 03/id_021/algorithm.zip b/Week 03/id_021/algorithm.zip new file mode 100644 index 000000000..3203d91ba Binary files /dev/null and b/Week 03/id_021/algorithm.zip differ diff --git a/Week 03/id_026/FindMin.java b/Week 03/id_026/FindMin.java new file mode 100644 index 000000000..8dc0dab54 --- /dev/null +++ b/Week 03/id_026/FindMin.java @@ -0,0 +1,30 @@ +package com.abc.week03; + +public class FindMin { + public int findMin(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + int left = 0, right = nums.length - 1; + if (nums[right] > nums[0]) { + return nums[0]; + } + while (right >= left) { + int mid = left + (right - left) / 2; + if (nums[mid] > nums[mid + 1]) { + return nums[mid + 1]; + } + + if (nums[mid - 1] > nums[mid]) { + return nums[mid]; + } + + if (nums[mid] > nums[0]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return -1; + } +} diff --git a/Week 03/id_026/MaxProfit.java b/Week 03/id_026/MaxProfit.java new file mode 100644 index 000000000..fa24f140b --- /dev/null +++ b/Week 03/id_026/MaxProfit.java @@ -0,0 +1,14 @@ +package com.abc.week03; + +public class MaxProfit { + public int maxProfit(int[] prices) { + int maxProfit = 0; + for (int i = 0; i < prices.length; i++) { + if (prices[i + 1] > prices[i]) { + int temp = prices[i + 1] - prices[i]; + maxProfit += temp; + } + } + return maxProfit; + } +} diff --git a/Week 03/id_036/LeetCode_860 b/Week 03/id_036/LeetCode_860 new file mode 100644 index 000000000..a978d4957 --- /dev/null +++ b/Week 03/id_036/LeetCode_860 @@ -0,0 +1,27 @@ +public class LeetCode_860 { + + + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for (int i : bills) { + if (i == 5) { + five++; + } else if (i == 10) { + if (five == 0) return false; + five--; + ten++; + } else if (i == 20) { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five = five - 3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/Week 03/id_036/Leetcode_455.java b/Week 03/id_036/Leetcode_455.java new file mode 100644 index 000000000..05fe29370 --- /dev/null +++ b/Week 03/id_036/Leetcode_455.java @@ -0,0 +1,23 @@ +package com.sslz.leetcode.Week3; + +import java.util.Arrays; + +public class Leetcode_455 { + + public int findContentChildren(int[] g, int[] s) { + if (g == null || s == null) { + return 0; + } + Arrays.sort(g); + Arrays.sort(s); + int gi = 0; + int si = 0; + while (gi < g.length && si < s.length) { + if (g[gi] <= s[si]) { + gi++; + } + si++; + } + return gi; + } +} diff --git a/Week 03/id_036/Leetcode_69.java b/Week 03/id_036/Leetcode_69.java new file mode 100644 index 000000000..3b5faa8d8 --- /dev/null +++ b/Week 03/id_036/Leetcode_69.java @@ -0,0 +1,36 @@ +package com.sslz.leetcode.Week3; + +public class Leetcode_69 { + + public int mySqrt(int x) { + if (x == 0 || x == 1) { + return x; + } + long left = 0; + //最大边界问题 + long right = Integer.MAX_VALUE; + while (left < right) { + + // 这里因为是正整数 所以采用的 >>> 或 >> 是一样的性质 如果包含负数则 大不一样 + //(left + right + 1) >> 1 而不是(left + right) >> 1 这里的 1 是干嘛的 + long mid = (left + right + 1) >> 1; + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid; + } + } + return (int) right; + } + + // 牛顿法 + public int mySqrt01(int a) { + long x = a; + while (x * x > a) { + x = (x + a / x) / 2; + } + return (int) x; + } + + +} diff --git a/Week 03/id_041/Search_a_2d_matrix.java b/Week 03/id_041/Search_a_2d_matrix.java new file mode 100644 index 000000000..30a27e97f --- /dev/null +++ b/Week 03/id_041/Search_a_2d_matrix.java @@ -0,0 +1,93 @@ +package search_a_2d_matrix; + +import org.junit.Test; + +class Solution { + /** + * 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: + + 每行中的整数从左到右按升序排列。 + 每行的第一个整数大于前一行的最后一个整数。 + + 输入: + matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] + ] + target = 3 + 输出: true + + + * */ + static int row = 0; + static int leftR = 0; + public static boolean searchMatrix(int[][] matrix, int target) { + /** + * 自己的实现:先用二分搜索判断元素的范围在那个一行(数组)里;再二分搜索改行; + * */ + if(matrix.length == 0) return false; + leftR = 0; + row = matrix.length-1; + if(matrix[row].length==0) return false; + int cols = matrix[row].length-1; + if(matrix[row][cols] < target || matrix[0][0] > target ) return false; + while (leftR <= row ){ + int mid = ( leftR + row )/2; + if (matrix[mid][0] > target){ + row = mid - 1; + }else if(matrix[mid][0] < target){ + leftR = mid + 1; + }else { + return true; + } + } + int left = 0; int right = matrix[leftR-1].length-1; + boolean result = false; + while (left <= right){ + + int mid = ( left + right )/2; + if(matrix[leftR-1][mid] == target){ + return true; + }else if(matrix[leftR-1][mid] < target){ + left = mid + 1; + }else { + right = mid - 1; + } + + } + return result; + + } + public static boolean searchMatrix2(int[][] matrix, int target) { + /** + * 官方题解:将二维数组视为一个有序的m * n个一维数组 + * */ + int m = matrix.length; + if(m == 0) return false; + int n = matrix[0].length; + int left = 0; int right = m * n -1; + while (left <= right){ + int mid = (left + right)/2; + int elm = matrix[mid / n][mid % n]; + if(elm == target) { + return true; + }else { + if(elm < target){ + left = mid + 1; + }else { + right = mid - 1; + } + } + } + return false; + } + + public static void main(String[] args){ +// int[][] matrix = {{1,3,5,6,7},{9,11,12,15,16},{18,20,22,23,25}}; + int[][] matrix = {{}}; + boolean result = searchMatrix(matrix,3); + System.out.println("row = " + row + " leftR= " + leftR + " result = " + result); + } + +} \ No newline at end of file diff --git a/Week 03/id_041/Search_in_rotated_sorted_array.java b/Week 03/id_041/Search_in_rotated_sorted_array.java new file mode 100644 index 000000000..c58976807 --- /dev/null +++ b/Week 03/id_041/Search_in_rotated_sorted_array.java @@ -0,0 +1,53 @@ +package search_in_rotated_sorted_array; + +class Solution { + /** + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + + ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + + 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + + 你可以假设数组中不存在重复的元素。 + + 你的算法时间复杂度必须是 O(log n) 级别。 + + 示例 1: + + 输入: nums = [4,5,6,7,0,1,2], target = 0 + 输出: 4 + 示例 2: + + 输入: nums = [4,5,6,7,0,1,2], target = 3 + 输出: -1 + + * */ + public int search(int[] nums, int target) { + /** + *将数组一分为二,分别对两边进行区间二分 + * */ + int left = 0; + int rigth = nums.length-1; + while (left <= rigth){ + int mid = (left + rigth)/2; + if(nums[mid] == target) return mid; + //当左半天有序时 + if(nums[left] <= nums[mid]){ + if(target >= nums[left] && target < nums[mid] ){ + rigth = mid -1; + }else { + left = mid + 1; + } + }else {//当右半边有序时 + if(target > nums[mid] && target <= nums[rigth]){ + left = mid + 1; + }else { + rigth = mid -1; + } + } + } + + return -1; + } + +} \ No newline at end of file diff --git a/Week 03/id_046/LeetCode_33_046.java b/Week 03/id_046/LeetCode_33_046.java new file mode 100644 index 000000000..08b3709f1 --- /dev/null +++ b/Week 03/id_046/LeetCode_33_046.java @@ -0,0 +1,24 @@ +class Solution { + public int search(int[] nums, int target) { + if (nums.length == 0) return -1; + int low = 0; + int high = nums.length - 1; + while(low < high){ + int mid = (high + low)/2; + if (nums[mid] == target) return mid; + if(nums[low] <= nums[mid]){ + if(nums[low] <= target && nums[mid] > target) + high = mid -1; + else low = mid + 1; + }else{ + if (target > nums[mid] && target <= nums[high]) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + } + return nums[low] == target ? low : -1; + } +} \ No newline at end of file diff --git a/Week 03/id_046/LeetCode_515_046.java b/Week 03/id_046/LeetCode_515_046.java new file mode 100755 index 000000000..c6e0c0e8a --- /dev/null +++ b/Week 03/id_046/LeetCode_515_046.java @@ -0,0 +1,30 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + List res = new ArrayList<>(); + + public List largestValues(TreeNode root) { + getRowNums(root,0); + return res; + } + + private void getRowNums(TreeNode node, int rowLevel){ + if(node != null){ + if(res.size() == rowLevel){ + res.add(node.val); + } else { + // 改善:保持每个深度放入的元素为当前遍历中最大 + res.set(rowLevel,Math.max(res.get(rowLevel),node.val)); + } + if(node.left != null) getRowNums(node.left,rowLevel+1); + if(node.right != null) getRowNums(node.right,rowLevel+1); + } + } +} \ No newline at end of file diff --git a/Week 03/id_046/LeetCode_860_046.java b/Week 03/id_046/LeetCode_860_046.java new file mode 100755 index 000000000..2665ad180 --- /dev/null +++ b/Week 03/id_046/LeetCode_860_046.java @@ -0,0 +1,38 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for(int i : bills){ + if(i==5) five++; + if(i==10){ + if(five == 0) return false; + else { + five--; + ten++; + } + } + if(i==20){ + if(ten > 0 && five > 0 ){ + ten--; + five--; + }else if(five >2){ + five = five -3; + }else return false; + } + } + return true; + } + + // 更简洁的逻辑,前面的处理保证了不会有负数的10,只需根据5的计数判断是否有足够零钱 + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) {five--; ten++;} + else if (ten > 0) {ten--; five--;} + else five -= 3; + if (five < 0) return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week 03/id_071/LeetCode_122_071.go b/Week 03/id_071/LeetCode_122_071.go new file mode 100644 index 000000000..0094f57c0 --- /dev/null +++ b/Week 03/id_071/LeetCode_122_071.go @@ -0,0 +1,39 @@ +package week03 + +//2.2 https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ +func maxProfit1s(prices []int) int { + max := 0 + for i := 0; i < len(prices)-1; i++ { + for j := i; j < len(prices); j++ { + profit := prices[j] - prices[i] + if profit > max { + max = profit + } + } + } + return max +} + +func maxProfit1(prices []int) int { + max, min := 0, 126 + for i := 0; i < len(prices); i++ { + if prices[i] < min { + min = prices[i] + }else if prices[i] - min > max { + max = prices[i] - min + } + } + return max +} + +// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ +func maxProfit2(prices []int) int { + max := 0 + for i := 1; i < len(prices); i++ { + if prices[i] > prices[i - 1]{ + max += prices[i]-prices[i - 1] + } + } + + return max +} \ No newline at end of file diff --git a/Week 03/id_071/LeetCode_127_071.go b/Week 03/id_071/LeetCode_127_071.go new file mode 100644 index 000000000..63ae146b0 --- /dev/null +++ b/Week 03/id_071/LeetCode_127_071.go @@ -0,0 +1,66 @@ +package week03 + +//1.1 https://leetcode-cn.com/problems/word-ladder/ +func ladderLength(beginWord string, endWord string, wordList []string) int { + wordMap := getWordMap(wordList, beginWord) + que := []string{beginWord} + depth := 0 + for len(que) > 0 { + depth++ + + qlen := len(que) + for i := 0; i < qlen; i++ { + word := que[0] + que = que[1:] + + candidates := getCandidates(word) + for _, candidate := range candidates { + if _, ok := wordMap[candidate]; ok { + if candidate == endWord { + return depth + 1 + } + + delete(wordMap, candidate) + que = append(que, candidate) + } + } + } + } + return 0 +} + +func getWordMap (wordList []string, beginWord string) map[string]int{ + + wordMap := make(map[string]int) + for i, word := range wordList { + if _, ok := wordMap[word]; !ok { + if word != beginWord { + wordMap[word] = i + } + } + } + + return wordMap +} + +func getCandidates(word string) []string { + + var res []string + for i := 0; i < 26; i++ { + for j := 0; j < len(word); j++ { + if word[j] != byte(int('a')+i) { + res = append(res, word[ :j] + string(int('a') + i) + word[j+1: ]) + } + } + } + + return res +} + + + + +// 529 https://leetcode-cn.com/problems/minesweeper/description/ +// func updateBoard(board [][]byte, click []int) [][]byte { + +// } \ No newline at end of file diff --git a/Week 03/id_071/LeetCode_153_071.go b/Week 03/id_071/LeetCode_153_071.go new file mode 100644 index 000000000..35c7d0b6d --- /dev/null +++ b/Week 03/id_071/LeetCode_153_071.go @@ -0,0 +1,32 @@ +package week03 + +// 3.3 https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ +func findMin(nums []int) int { + + if len(nums) == 1 { + return nums[0] + } + + low, high := 0,len(nums)-1 + + if nums[high] > nums[0]{ + return nums[0] + } + + for low <= high { + mid := low + (high-low)/2 + if nums[mid] > nums[mid + 1] { + return nums[mid + 1] + } + if nums[mid] < nums[mid - 1]{ + return nums[mid] + } + + if nums[mid] > nums[0] { + low = mid + 1 + }else{ + high = mid - 1 + } + } + return -1 +} \ No newline at end of file diff --git a/Week 03/id_071/LeetCode_200_071.go b/Week 03/id_071/LeetCode_200_071.go new file mode 100644 index 000000000..85968b983 --- /dev/null +++ b/Week 03/id_071/LeetCode_200_071.go @@ -0,0 +1,74 @@ +package week03 + +import ( + "container/list" +) + +//1.2 https://leetcode-cn.com/problems/number-of-islands/ +func numIslands(grid [][]byte) int { + + if grid == nil || len(grid) == 0 { + return 0 + } + + dx := len(grid) + dy := len(grid[0]) + num := 0 + for i := 0; i < dx; i++ { + for j := 0; j < dy; j++ { + if grid[i][j] == '1' { + num++ + dfs(grid, i, j) + } + } + } + + return num +} + +func dfs(grid [][]byte, i int, j int) { + dx := len(grid) + dy := len(grid[0]) + if i < 0 || j < 0 || i >= dx || j >= dy || grid[i][j] == '0' { + return + } + + grid[i][j] = '0' + + dfs(grid, i - 1, j) + dfs(grid, i + 1, j) + dfs(grid, i, j - 1) + dfs(grid, i, j + 1) +} + +//queue +func numIslandes (grid [][]byte) int { + if grid == nil || len(grid) == 0 { + return 0 + } + + dx := len(grid) + dy := len(grid[0]) + num := 0 + for i := 0; i < dx; i++ { + for j := 0; i < dy; j++ { + if grid[i][j] == '1' { + num++ + bfs(grid, i, j) + } + } + } + + return num +} + +func bfs(grid [][]byte, i int, j int){ + grid[i][j] = '0' + dx := len(grid) + dy := len(grid[0]) + q := list.New() + + for q.Len() { + + } +} \ No newline at end of file diff --git a/Week 03/id_071/LeetCode_860_071.go b/Week 03/id_071/LeetCode_860_071.go new file mode 100644 index 000000000..094c23b36 --- /dev/null +++ b/Week 03/id_071/LeetCode_860_071.go @@ -0,0 +1,32 @@ +package week03 + +// 2.1 https://leetcode-cn.com/problems/lemonade-change/description/ +func lemonadeChange(bills []int) bool { + + var ( + five, ten int = 0, 0 + ) + for _, v := range bills { + if v == 5 { + five++ + }else if v == 10 { + if five > 0 { + five-- + ten++ + }else{ + return false + } + }else{ + if five > 0 && ten > 0 { + five-- + ten-- + }else if five >= 3 { + five = five - 3 + }else{ + return false + } + } + } + + return true +} \ No newline at end of file diff --git a/Week 03/id_071/NOTE.md b/Week 03/id_071/NOTE.md index a6321d6e2..5183f2519 100644 --- a/Week 03/id_071/NOTE.md +++ b/Week 03/id_071/NOTE.md @@ -1,4 +1,136 @@ -# NOTE +> 深度优先搜索(dfs) 广度优先搜索(bfs) - + +##### dfs 深度优先遍历 + + //递归、栈的方式 + func dfs(node []int) { + visited := []int{} + //node in visited + if _, ok := visited[]; ok { + return + } + visited = append(visited,node) + + dfs(node[left]) + dfs(node[right]) + } + + // + visited := []int{} + func dfs(node []int{}, visted []int){ + visited = append(visited,node) + for k, v := range node['children'] { + //next_node in visited + if _, ok :range visited[next_node]; ok { + dfs(next_node, visited) + } + } + } + +##### bfs 广度优先遍历(层级遍历) + + //对列 queue + func bfs(graph []int, start in, end int){ + visited := []int{} + queue := []int{} + queue = append(queue,graph[start]) + visited = append(visited,start) + for len(queue) > 0 { + + } + + } + + +*** + + +> 贪心算法 + +##### 贪心算法 每一步选择中都采取当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的算法 + + 常用语 哈夫曼编码、最小生成树 + 1、贪心 得到全局最优解 + 2、贪心的角度 从前往后 或 从后往前 + +##### 步骤 + + 1、定义了期望值 和 限制值 + 2、尝试看下贪心算法能否解决问题 每次选择当前情况下,在对限制值同等贡献量的情况下,对期望值贡献最大的数据 + 3、举例看下贪心算法啊产生的结果是否是最优解 + +##### 贪心、回溯、动态规划 + + 贪心 寻找局部最优解 + 回溯 + 动态规划 + + +*** + + +> 二分查找 + +##### 简单的二分查找 就是 有序数组中不存在重复元素 + + 1. 循环退出条件 left <= right + + 2. mid 的取值 left+(right-left)/2 or left+((right-left)>>1) + + 3. left 和 right 的更新 left = mid + 1 or right = mid - 1 + +##### 变体的二分查找 + + 变体一:查找第一个值等于给定值的元素 + 变体二:查找最后一个值等于给定值的元素 + 变体三:查找第一个大于等于给定值的元素 + 变体四:查找最后一个小于等于给定值的元素 + +##### 条件 + + 单调性 有序 + 上下界 有边界 (bounded) + 索引访问 数组 (index accessible) + + 连续内存空间 + + 对比 二叉搜索树 + +##### 代码模板 + + //循环 + left,right := 0, len(nums) + for left <= right { + mid := (left+right)/2 + + if target == nums[mid] { + return mid + }else if target > nums[mid]{ + left = mid + 1 + }else{ + right = mid - 1 + } + } + + + //递归 + func binary (nums []int, val int ) int { + l := len(nums) + return binarysearch(nums, val, 0, l) + } + + func binarySearch(nums []int, val int, low int, high int){ + if low > high { + return -1 + } + mid := low+((high-low)>>1) + if val == nums[mid] { + return mid + } else val > nums[mid] { + return binarySearch(nums, val, mid + 1, high) + }else{ + return bunarySearch(nums, val, low, mid + 1) + } + } diff --git a/Week 03/id_071/leetCode_033_071.go b/Week 03/id_071/leetCode_033_071.go new file mode 100644 index 000000000..d5b7c5006 --- /dev/null +++ b/Week 03/id_071/leetCode_033_071.go @@ -0,0 +1,30 @@ +package week03 + +import "fmt" + +// 3.1 https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ +func search(nums []int, target int) int { + low, high := 0, len(nums) - 1 + for low <= high { + mid := low + (high - low)/2 + fmt.Print(mid, "\n") + if nums[0] > target || nums[0] > nums[mid] || target > nums[mid] { + low = mid + 1 + } else { + high = mid + } + fmt.Print(low, high, "\n") + } + + if low == high && nums[low] == target { + return low + } + + return -1 +} + +// 3.2 https://leetcode-cn.com/problems/search-a-2d-matrix/ +func searchMatrix(matrix [][]int, target int) bool { + + return false +} \ No newline at end of file diff --git a/Week 03/id_071/week03_test.go b/Week 03/id_071/week03_test.go new file mode 100644 index 000000000..965914764 --- /dev/null +++ b/Week 03/id_071/week03_test.go @@ -0,0 +1,37 @@ +package week03 + +import "testing" + +func TestMySqrt(t *testing.T) { + s := mySqrt(25) + t.Log(s) +} + +func TestIsPerfectSquare(t *testing.T) { + s := isPerfectSquare(15) + t.Log(s) +} + +func TestSearch(t *testing.T) { + arr := []int{4, 5, 6, 7, 0, 1, 2} + s := search(arr, 6) + t.Log(s) +} + +func TestFindMin(t *testing.T) { + arr := []int{4, 5, 6, 7, 8, 2, 3} + s := findMin(arr) + t.Log(s) +} + +func TestLemonadeChange(t *testing.T) { + arr := []int{5, 10, 5, 10, 20} + s := lemonadeChange(arr) + t.Log(s) +} + +func TestMaxProfit(t *testing.T) { + arr := []int{7, 1, 5, 3, 6, 4} + s := maxProfit1(arr) + t.Log(s) +} diff --git a/Week 03/id_076/LeetCode_102_076.java b/Week 03/id_076/LeetCode_102_076.java new file mode 100644 index 000000000..587a1c559 --- /dev/null +++ b/Week 03/id_076/LeetCode_102_076.java @@ -0,0 +1,93 @@ +package week3; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * 采用BFS 广度优先算法遍历二叉树 + * 本题听了视频,有使用队列解题思路,但还是没有写对 + * 处理层级时没有处理好,还需努力。。。 + * + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * + * @author tangzhenhua + * @date 2019/11/03 20:00 + */ +public class LeetCode_102_076 { + + + public List> levelOrder(TreeNode root) { + + List> results = new ArrayList<>(); + + if(root == null) return results; + + Queue queue = new LinkedList<>(); + queue.add(root); + + int level = 0; + + while (!queue.isEmpty()) { + + results.add(new ArrayList<>()); + List list = results.get(level); + int currLevel = queue.size(); + + for(int i = 0; i < currLevel; i++) { + + TreeNode treeNode = queue.remove(); + list.add(treeNode.val); + + if(treeNode.left != null){ + queue.add(treeNode.left); + } + + if(treeNode.right != null) { + queue.add(treeNode.right); + } + } + + level++; + + } + + return results; + } + + public static void main(String[] args) { + + TreeNode root = new TreeNode(3); + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20); + TreeNode left2 = new TreeNode(15); + TreeNode right2 = new TreeNode(7); + + root.left = left; + root.right = right; + + right.left = left2; + right.right = right2; + + LeetCode_102_076 leet = new LeetCode_102_076(); + List list = leet.levelOrder(root); + System.out.println(list); + } + +} + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/Week 03/id_076/LeetCode_74_076.java b/Week 03/id_076/LeetCode_74_076.java new file mode 100644 index 000000000..9a4aa622c --- /dev/null +++ b/Week 03/id_076/LeetCode_74_076.java @@ -0,0 +1,43 @@ +package week3; + +/** + * 采二分查找搜索二维矩阵 + * 解题思路: + * 1. 采用暴力方法 + * 2. 转换为有序数组之后,进行二分查找 + * 3. 由于该矩阵正好符合有序数组,可以直接转换为虚数组进行查询,节省空间 + * 4. 采用行首或行尾进行匹配,确认数据可能在哪一行,之后再进行行内进行轮询或二分查找 + * + * 本题采用虚拟数组方式进行解题 + * + * @author tangzhenhua + * @date 2019/11/03 20:00 + */ +public class LeetCode_74_076 { + + public boolean searchMatrix(int[][] matrix, int target) { + + int row = matrix.length; + int col = matrix[0].length; + + int left = 0; + int right = row * col - 1; + + while (left <= right){ + int idx = (left + right)/2; + int result = matrix[idx / row][idx % row]; + if(target == result){ + return true; + } else if(target < result){ + right = idx - 1; + } else { + left = idx + 1; + } + } + return false; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/Week 03/id_076/LeetCode_860_076.java b/Week 03/id_076/LeetCode_860_076.java new file mode 100644 index 000000000..c932f137b --- /dev/null +++ b/Week 03/id_076/LeetCode_860_076.java @@ -0,0 +1,45 @@ +package week3; + +/** + * 采用贪心算法解题,没次都采用最优进行选择,没有最优办法采用次优进行处理。 + * + * @author tangzhenhua + * @date 2019/11/03 20:00 + */ +public class LeetCode_860_076 { + + public boolean lemonadeChange(int[] bills) { + + int five = 0; + int ten = 0; + + for(int i = 0; i < bills.length; i++) { + if(bills[i] == 5) { + five++; + + } else if(bills[i] == 10) { + if(five == 0) { + return false; + } + five--; + ten++; + } else { + if(ten > 0 && five > 0){ + five--; + ten--; + } else if(five >= 3){ + five -= 3; + } else { + return false; + } + } + } + return true; + } + + public static void main(String[] args) { + int[] bills = {5,5,5,10,20}; + LeetCode_860_076 leet = new LeetCode_860_076(); + System.out.println(leet.lemonadeChange(bills)); + } +} \ No newline at end of file diff --git a/Week 03/id_076/NOTE.md b/Week 03/id_076/NOTE.md index a6321d6e2..51420d5e0 100644 --- a/Week 03/id_076/NOTE.md +++ b/Week 03/id_076/NOTE.md @@ -1,4 +1,29 @@ -# NOTE - - - +# NOTE + +本周 学习内容 + +## 广度优先搜索 BFS,深度优先搜索 DFS +## 贪心算法 +## 二分法查找 + +通过练习,了解到二维数组,部分问题可转换为二叉树搜索方式进行解题 +也可以转换为有序数组,进行二分法进行处理 +其中搜索算法,需要多加练习 + + +## Flood fill 算法 +- Flood fill 算法是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典 算法。 +- 因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名。在 GNU Go 和 扫雷 中, +- Flood Fill算法被用来计算需要被清除的区域。 + +## 广度优先搜索 BFS +按层进行遍历 + +## 深度优先搜索 DFS +按照深度进行遍历,根据二叉树遍历,可分三种遍历顺序:前、中、后 + + + + + + diff --git a/Week 03/id_081/AssignCookies.java b/Week 03/id_081/AssignCookies.java new file mode 100644 index 000000000..ee042cd19 --- /dev/null +++ b/Week 03/id_081/AssignCookies.java @@ -0,0 +1,23 @@ +/** + * AssignCookies + */ +public class AssignCookies { + + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int count = 0; + + int gIndex = 0; + int sIndex = 0; + + while (gIndex < g.length && sIndex < s.length) { + if (g[gIndex] <= s[sIndex]) { + count++; + gIndex++; + } + sIndex++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 03/id_081/BestTimeToBuyAndSellStockII.java b/Week 03/id_081/BestTimeToBuyAndSellStockII.java new file mode 100644 index 000000000..c5cfe9837 --- /dev/null +++ b/Week 03/id_081/BestTimeToBuyAndSellStockII.java @@ -0,0 +1,13 @@ +/** + * BestTimeToBuyAndSellStockII + */ +public class BestTimeToBuyAndSellStockII { + + public int maxProfit(int[] prices) { + int total = 0; + for(int i = 0; i < prices.length -1; i++){ + if(prices[i] < prices[i + 1]) total+= (prices[i + 1] - prices[i]); + } + return total; + } +} \ No newline at end of file diff --git a/Week 03/id_081/JumpGame.java b/Week 03/id_081/JumpGame.java new file mode 100644 index 000000000..6ee395092 --- /dev/null +++ b/Week 03/id_081/JumpGame.java @@ -0,0 +1,16 @@ +/** + * JumpGame + */ +public class JumpGame { + + public boolean canJump(int[] nums) { + if(nums == null) return true; + + int jumpEnd = nums.length -1; + for(int i = jumpEnd; i >= 0; i--){ + if(nums[i] + i >= jumpEnd) + jumpEnd = i; + } + return jumpEnd == 0; + } +} \ No newline at end of file diff --git a/Week 03/id_081/LemonadeChange.java b/Week 03/id_081/LemonadeChange.java new file mode 100644 index 000000000..602484ab8 --- /dev/null +++ b/Week 03/id_081/LemonadeChange.java @@ -0,0 +1,23 @@ +/** + * LemonadeChange + */ +public class LemonadeChange { + + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for(int i : bills){ + if(i == 5) + five++; + else if(i == 10) { + five--; + ten++; + }else if(ten > 0){ + ten--; + five--; + }else five -= 3; + + if(five < 0) return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week 03/id_081/NOTE.md b/Week 03/id_081/NOTE.md old mode 100644 new mode 100755 diff --git a/Week 03/id_081/SearchInRotatedSortedArray.java b/Week 03/id_081/SearchInRotatedSortedArray.java new file mode 100644 index 000000000..e94f35fa3 --- /dev/null +++ b/Week 03/id_081/SearchInRotatedSortedArray.java @@ -0,0 +1,24 @@ +/** + * SearchInRotatedSortedArray + */ +public class SearchInRotatedSortedArray { + + public int search(int[] nums, int target) { + int lo = 0; + int hi = nums.length - 1; + + while (lo < hi) { + int mid = (lo + hi) / 2; + // 当[0,mid]有序时,向后规约条件 + if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + lo = mid + 1; + // 当[0,mid]发生旋转时,向后规约条件 + } else if (nums[0] > nums[mid] && target > nums[mid] && target < nums[0]) { + lo = mid + 1; + } else { + hi = mid; + } + } + return lo == hi && nums[lo] == target ? lo : -1; + } +} \ No newline at end of file diff --git a/Week 03/id_081/Sqrt.java b/Week 03/id_081/Sqrt.java new file mode 100644 index 000000000..915beb8c5 --- /dev/null +++ b/Week 03/id_081/Sqrt.java @@ -0,0 +1,19 @@ +/** + * Sqrt + */ +public class Sqrt { + + public int mySqrt(int x) { + long left = 0; + long right = x; + while (left < right) { + long mid = (left + right + 1) >>> 1; + long square = mid * mid; + if (square > x) + right = mid - 1; + else + left = mid; + } + return (int) right; + } +} \ No newline at end of file diff --git a/Week 03/id_081/ValidPerfectSquare.java b/Week 03/id_081/ValidPerfectSquare.java new file mode 100644 index 000000000..dd896ebaf --- /dev/null +++ b/Week 03/id_081/ValidPerfectSquare.java @@ -0,0 +1,25 @@ +/** + * ValidPerfectSquare + */ +public class ValidPerfectSquare { + + public boolean isPerfectSquare(int num) { + if(num == 0) return true; + + long left = 1; + long right = num; + + while(left <= right) { + long mid = (left + right) >>> 1; + long square = mid * mid; + if(square == num) + return true; + else if(square < num) + left = mid + 1; + else + right = mid - 1; + + } + return false; + } +} \ No newline at end of file diff --git a/Week 03/id_086/LeetCode_122_086.java b/Week 03/id_086/LeetCode_122_086.java new file mode 100644 index 000000000..08224ef0d --- /dev/null +++ b/Week 03/id_086/LeetCode_122_086.java @@ -0,0 +1,15 @@ +# 122 买卖股票的最佳时机 +# 循环遍历,算出元素之间差最大(后一个减前一个元素的差,累计最大值),每一个元素差只能计算一次, + +class Solution { + public int maxProfit(int[] prices) { + int countProfit = 0; + for (int i = 1; i < prices.length; i++) { + int tmpProfit = prices[i] - prices[i - 1]; + if (tmpProfit > 0) { + countProfit += tmpProfit; + } + } + return countProfit; + } +} \ No newline at end of file diff --git a/Week 03/id_086/LeetCode_455_086.java b/Week 03/id_086/LeetCode_455_086.java new file mode 100644 index 000000000..07fce016a --- /dev/null +++ b/Week 03/id_086/LeetCode_455_086.java @@ -0,0 +1,18 @@ +# 455 分发饼干 +# 寻找两个数组中想匹配的元素并返回 + +class Solution { + public int findContentChildren(int[] g, int[] s) { + int child = 0; + int biscuit = 0; + Arrays.sort(g); + Arrays.sort(s); + while (child < g.length && biscuit < s.length) { + if (g[child] <= s[biscuit]) { + child ++; + } + biscuit ++; + } + return child; + } +} \ No newline at end of file diff --git a/Week 03/id_086/LeetCode_860_086.java b/Week 03/id_086/LeetCode_860_086.java new file mode 100644 index 000000000..a53ee5fab --- /dev/null +++ b/Week 03/id_086/LeetCode_860_086.java @@ -0,0 +1,33 @@ +# 柠檬水找零 +# 1、先判断数组中的第一个、第二个元素,如果第一个元素不是 5 直接返回false,如果第二个元素是 20 ,直接返回 false, +# 2、之后再循环判断数组中的元素,记录出现 5、10 元素的次数,循环累计,后续出现的元素与累计的 5、10 元素去做比较,如果不能找零,则返回 false 注:元素只能是为 5、10、20 + + +class Solution { + public boolean lemonadeChange(int[] bills) { + int countFive = 0; + int countTen = 0; + for (int bill : bills) { + if ( bill == 5) { + countFive ++; + }else if( bill == 10) { + if ( countFive == 0) { + return false; + } + countFive --; + countTen ++; + }else { + if (countFive > 0 && countTen > 0) { + countFive--; + countTen--; + } else if (countFive >= 3) { + countFive -= 3; + } else { + return false; + } + } + } + return true; + } +} + diff --git a/Week 03/id_091/Leetcode_122_091.py b/Week 03/id_091/Leetcode_122_091.py new file mode 100644 index 000000000..205694753 --- /dev/null +++ b/Week 03/id_091/Leetcode_122_091.py @@ -0,0 +1,18 @@ +from typing import List + + +class Solution: + #只要第二天的利润大于第一天就买进 + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(0, len(prices)-1): + tmp = prices[i+1] - prices[i] + if tmp > 0: profit += tmp + return profit + + +if __name__ == '__main__': + solution = Solution() + priceList = [7,1,5,3,6,4,8] + res = solution.maxProfit(priceList) + print(res) diff --git a/Week 03/id_091/Leetcode_127_091.py b/Week 03/id_091/Leetcode_127_091.py new file mode 100644 index 000000000..58b44e5c4 --- /dev/null +++ b/Week 03/id_091/Leetcode_127_091.py @@ -0,0 +1,36 @@ +from typing import List + + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if endWord not in wordList: + return 0 + wordict = set(wordList) + s1 = {beginWord} + s2 = {endWord} + n = len(beginWord) + step = 0 + wordict.remove(endWord) + while s1 and s2: + step += 1 + if len(s1) > len(s2): s1, s2 = s2, s1 + s = set() + for word in s1: + nextword = [word[:i] + chr(j) + word[i + 1:] for j in range(97, 123) for i in range(n)] + for w in nextword: + if w in s2: + return step + 1 + if w not in wordict: continue + wordict.remove(w) + s.add(w) + s1 = s + return 0 + + +if __name__ == '__main__': + solution = Solution() + beginWord = "hit" + endWord = "cog" + wordList = ["hot", "dot", "dog", "lot", "log", "cog"] + res = solution.ladderLength(beginWord, endWord, wordList) + print(res) diff --git a/Week 03/id_091/Leetcode_200_091.py b/Week 03/id_091/Leetcode_200_091.py new file mode 100644 index 000000000..e51d17c98 --- /dev/null +++ b/Week 03/id_091/Leetcode_200_091.py @@ -0,0 +1,71 @@ +from collections import deque +from typing import List + + +class Solution: + # x-1,y + # x,y-1 x,y x,y+1 + # x+1,y + # 方向数组,表示相对于当前位置的 4 个方向的横、纵坐标的偏移量 + directions = [(-1, 0), (0, -1), (1, 0), (0, 1)] + + def numIslands(self, grid: List[List[str]]) -> int: + m = len(grid) + if m == 0: + return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + for i in range(m): + for j in range(n): + # 只要是陆地,且没有被访问过的,就可以使用 DFS 发现与之相连的陆地,并进行标记 + if not marked[i][j] and grid[i][j] == '1': + count += 1 + self.__dfs(grid, i, j, m, n, marked) + return count + + def __dfs(self, grid, i, j, m, n, marked): + marked[i][j] = True + for direction in self.directions: + new_i = i + direction[0] + new_j = j + direction[1] + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + self.__dfs(grid, new_i, new_j, m, n, marked) + + def numIslands2(self, grid: List[List[str]]) -> int: + m = len(grid) + if m == 0: + return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + for i in range(m): + for j in range(n): + # 只要是陆地,且没有被访问过的,就可以使用 BFS 发现与之相连的陆地,并进行标记 + if not marked[i][j] and grid[i][j] == '1': + count += 1 + queue = deque() + queue.append((i, j)) + # 已经访问过 + marked[i][j] = True + while queue: + cur_x, cur_y = queue.popleft() + # 得到 4 个方向的坐标 + for direction in self.directions: + new_i = cur_x + direction[0] + new_j = cur_y + direction[1] + # 如果不越界、没有被访问过、并且还要是陆地,就继续放入队列,放入队列的同时,标记已经访问过 + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][ + new_j] == '1': + queue.append((new_i, new_j)) + return count + + +if __name__ == '__main__': + grid = [['1', '1', '1', '1', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '0']] + solution = Solution() + result = solution.numIslands2(grid) + print(result) diff --git a/Week 03/id_101/[122]Best Time to Buy and Sell Stock II.py b/Week 03/id_101/[122]Best Time to Buy and Sell Stock II.py new file mode 100644 index 000000000..0e5f17fca --- /dev/null +++ b/Week 03/id_101/[122]Best Time to Buy and Sell Stock II.py @@ -0,0 +1,50 @@ +#Say you have an array for which the ith element is the price of a given stock on day i. +# +# Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times). +# +# Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). +# +# Example 1: +# +# +#Input: [7,1,5,3,6,4] +#Output: 7 +#Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. +#  Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. +# +# +# Example 2: +# +# +#Input: [1,2,3,4,5] +#Output: 4 +#Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. +#  Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are +#  engaging multiple transactions at the same time. You must sell before buying again. +# +# +# Example 3: +# +# +#Input: [7,6,4,3,1] +#Output: 0 +#Explanation: In this case, no transaction is done, i.e. max profit = 0. +# Related Topics Array Greedy + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + max_profit = 0 + for i in range(1, len(prices)): + diff = prices[i] - prices[i-1] + if diff > 0: + max_profit += diff + return max_profit + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[126]Word Ladder II.py b/Week 03/id_101/[126]Word Ladder II.py new file mode 100644 index 000000000..1ef782874 --- /dev/null +++ b/Week 03/id_101/[126]Word Ladder II.py @@ -0,0 +1,141 @@ +#Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that: +# +# +# Only one letter can be changed at a time +# Each transformed word must exist in the word list. Note that beginWord is not a transformed word. +# +# +# Note: +# +# +# Return an empty list if there is no such transformation sequence. +# All words have the same length. +# All words contain only lowercase alphabetic characters. +# You may assume no duplicates in the word list. +# You may assume beginWord and endWord are non-empty and are not the same. +# +# +# Example 1: +# +# +#Input: +#beginWord = "hit", +#endWord = "cog", +#wordList = ["hot","dot","dog","lot","log","cog"] +# +#Output: +#[ +# ["hit","hot","dot","dog","cog"], +#  ["hit","hot","lot","log","cog"] +#] +# +# +# Example 2: +# +# +#Input: +#beginWord = "hit" +#endWord = "cog" +#wordList = ["hot","dot","dog","lot","log"] +# +#Output: [] +# +#Explanation: The endWord "cog" is not in wordList, therefore no possible transformation. +# +# +# +# +# Related Topics Array String Backtracking Breadth-first Search + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + ''' + maintain a dict which has: + key -> word can be transformed from words in value + value -> set of curr words which can transform to + + example: 'cog' : set('dog', 'log') + both 'dog' and 'log' can be transformed to 'cog' + ''' + + def findLadders(self, beginWord, endWord, dic): + words = set(dic) + if endWord not in words: + return [] + parents = collections.defaultdict(set) + forward, backward = {beginWord}, {endWord} + direction = 1 + while forward and backward: + if len(forward) > len(backward): + forward, backward = backward, forward + direction *= -1 + + next_forward = set() + words -= forward + for word in forward: + self._build_next(next_forward, word, words, parents, direction) + forward = next_forward + if next_forward & backward: + res = [] + path = [endWord] + res = self.dfs(res, path, endWord, beginWord, parents) + return res + return [] + + def dfs(self, res, path, curr_word, dest_word, parents): + if curr_word == dest_word: + res.append(path[::-1]) + return res + for word in parents[curr_word]: + path.append(word) + self.dfs(res, path, word, dest_word, parents) + path.pop() + return res + + def _build_next(self, next_forward, word, words, parents, direction): + for i in range(len(word)): + left, right = word[:i], word[i + 1:] + for c in string.ascii_lowercase: + new_word = left + c + right + if new_word not in words: + continue + next_forward.add(new_word) + if direction == 1: + parents[new_word].add(word) + else: + parents[word].add(new_word) + + def findLaddersII(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: List[List[str]] + """ + dic = set(wordList) + if endWord not in dic: + return [] + fathers_dict = collections.defaultdict(set) + curr_from = {beginWord} # or {beginWord} + while curr_from and endWord not in fathers_dict: + derive_from = collections.defaultdict(set) + for word in curr_from: + self._build_children(derive_from, word, dic, fathers_dict) + curr_from = derive_from # move to next level + fathers_dict.update(derive_from) + res = [[endWord]] + # build result from end to begin, backward + while res and res[0][0] != beginWord: + res = [[p] + row for row in res for p in fathers_dict[row[0]]] + return res + + def _build_children(self, derive_from, word, word_dict, fathers_dict): + for i in range(len(word)): + for c in string.ascii_lowercase: + derive = word[:i] + c + word[i+1:] + if derive in word_dict and derive not in fathers_dict: + derive_from[derive].add(word) + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[153]Find Minimum in Rotated Sorted Array.py b/Week 03/id_101/[153]Find Minimum in Rotated Sorted Array.py new file mode 100644 index 000000000..02ee89792 --- /dev/null +++ b/Week 03/id_101/[153]Find Minimum in Rotated Sorted Array.py @@ -0,0 +1,48 @@ +#Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. +# +# (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). +# +# Find the minimum element. +# +# You may assume no duplicate exists in the array. +# +# Example 1: +# +# +#Input: [3,4,5,1,2] +#Output: 1 +# +# +# Example 2: +# +# +#Input: [4,5,6,7,0,1,2] +#Output: 0 +# +# Related Topics Array Binary Search + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + ''' + The proof that the loop will exit: after each iteration either the 'end' decreases + or the 'start' increases, so the interval [start, end] will always shrink. + ''' + start, end = 0, len(nums) - 1 + while start < end: + mid = start + (end - start) // 2 + if nums[mid] < nums[end]: + # minimum in left part + end = mid + elif nums[mid] > nums[end]: + # minimum in right part + start = mid+1 + return nums[start] + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[200]Number of Islands.py b/Week 03/id_101/[200]Number of Islands.py new file mode 100644 index 000000000..7466f5ab2 --- /dev/null +++ b/Week 03/id_101/[200]Number of Islands.py @@ -0,0 +1,60 @@ +#Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. +# +# Example 1: +# +# +#Input: +#11110 +#11010 +#11000 +#00000 +# +#Output: 1 +# +# +# Example 2: +# +# +#Input: +#11000 +#11000 +#00100 +#00011 +# +#Output: 3 +# Related Topics Depth-first Search Breadth-first Search Union Find + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + dx = [1, 0, -1, 0] + dy = [0, 1, 0, -1] + + def numIslands(self, grid): + m = len(grid) + if m == 0: + return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + for i in range(m): + for j in range(n): + if not marked[i][j] and grid[i][j] == '1': + count += 1 + self._dfs(grid, i, j, m, n, marked) + + return count + + def _dfs(self, grid, i, j, m, n, marked): + marked[i][j] = True + for k in range(4): + ni = i + self.dx[k] + nj = j + self.dy[k] + if 0 <= ni < m and 0 <= nj < n and not marked[ni][nj] and grid[ni][nj] == '1': + marked[ni][nj] = True + self._dfs(grid, ni, nj, m, n, marked) + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[33]Search in Rotated Sorted Array.py b/Week 03/id_101/[33]Search in Rotated Sorted Array.py new file mode 100644 index 000000000..394220916 --- /dev/null +++ b/Week 03/id_101/[33]Search in Rotated Sorted Array.py @@ -0,0 +1,54 @@ +#Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. +# +# (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). +# +# You are given a target value to search. If found in the array return its index, otherwise return -1. +# +# You may assume no duplicate exists in the array. +# +# Your algorithm's runtime complexity must be in the order of O(log n). +# +# Example 1: +# +# +#Input: nums = [4,5,6,7,0,1,2], target = 0 +#Output: 4 +# +# +# Example 2: +# +# +#Input: nums = [4,5,6,7,0,1,2], target = 3 +#Output: -1 +# Related Topics Array Binary Search + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + start, end = 0, len(nums) - 1 + while start <= end: + mid = start + (end - start) // 2 + if nums[mid] == target: + return mid + elif nums[mid] >= nums[start]: + if nums[start] <= target < nums[mid]: + end = mid-1 + else: + start = mid+1 + else: + # exclude mid and include end + if nums[mid] < target <= nums[end]: + start = mid+1 + else: + end = mid-1 + return -1 + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[455]Assign Cookies.py b/Week 03/id_101/[455]Assign Cookies.py new file mode 100644 index 000000000..826d6e5f9 --- /dev/null +++ b/Week 03/id_101/[455]Assign Cookies.py @@ -0,0 +1,57 @@ +# +#Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number. +# +# +# Note: +#You may assume the greed factor is always positive. +#You cannot assign more than one cookie to one child. +# +# +# Example 1: +# +#Input: [1,2,3], [1,1] +# +#Output: 1 +# +#Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3. +#And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content. +#You need to output 1. +# +# +# +# Example 2: +# +#Input: [1,2], [1,2,3] +# +#Output: 2 +# +#Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2. +#You have 3 cookies and their sizes are big enough to gratify all of the children, +#You need to output 2. +# +# Related Topics Greedy + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + # greedy algo + # sort grid and size array separately + # find right size cookie to child need small size cookie first + g.sort() + s.sort() + m, n = len(g), len(s) + i, j = 0, 0 + while i < m and j < n: + if g[i] <= s[j]: + i += 1 + j += 1 + return i + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[45]Jump Game II.py b/Week 03/id_101/[45]Jump Game II.py new file mode 100644 index 000000000..0d64a65d9 --- /dev/null +++ b/Week 03/id_101/[45]Jump Game II.py @@ -0,0 +1,43 @@ +#Given an array of non-negative integers, you are initially positioned at the first index of the array. +# +# Each element in the array represents your maximum jump length at that position. +# +# Your goal is to reach the last index in the minimum number of jumps. +# +# Example: +# +# +#Input: [2,3,1,1,4] +#Output: 2 +#Explanation: The minimum number of jumps to reach the last index is 2. +# Jump 1 step from index 0 to 1, then 3 steps to the last index. +# +# Note: +# +# You can assume that you can always reach the last index. +# Related Topics Array Greedy + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + + # so far jump max len + # track curr jump max len from each pos + # record previous jump max len + # only update step when curr pos == prev jump max len + # should not consider last item in array + step, jump_max, prev_jump_max = 0, 0, 0 + for i in range(len(nums)-1): + jump_max = max(jump_max, nums[i] + i) + if i == prev_jump_max: + prev_jump_max = jump_max + step += 1 + return step + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[529]Minesweeper.py b/Week 03/id_101/[529]Minesweeper.py new file mode 100644 index 000000000..fd618ff6b --- /dev/null +++ b/Week 03/id_101/[529]Minesweeper.py @@ -0,0 +1,127 @@ +#Let's play the minesweeper game (Wikipedia, online game)! +# +# You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine. +# +# Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules: +# +# +# If a mine ('M') is revealed, then the game is over - change it to 'X'. +# If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively. +# If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines. +# Return the board when no more squares will be revealed. +# +# +# +# +# Example 1: +# +# +#Input: +# +#[['E', 'E', 'E', 'E', 'E'], +# ['E', 'E', 'M', 'E', 'E'], +# ['E', 'E', 'E', 'E', 'E'], +# ['E', 'E', 'E', 'E', 'E']] +# +#Click : [3,0] +# +#Output: +# +#[['B', '1', 'E', '1', 'B'], +# ['B', '1', 'M', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +#Explanation: +# +# +# +# Example 2: +# +# +#Input: +# +#[['B', '1', 'E', '1', 'B'], +# ['B', '1', 'M', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +#Click : [1,2] +# +#Output: +# +#[['B', '1', 'E', '1', 'B'], +# ['B', '1', 'X', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +#Explanation: +# +# +# +# +# +# Note: +# +# +# The range of the input matrix's height and width is [1,50]. +# The click position will only be an unrevealed square ('M' or 'E'), which also means the input board contains at least one clickable square. +# The input board won't be a stage when game is over (some mines have been revealed). +# For simplicity, not mentioned rules should be ignored in this problem. For example, you don't need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares. +# +# Related Topics Depth-first Search Breadth-first Search + + + +#leetcode submit region begin(Prohibit modification and deletion) +import collections + +class Solution(object): + # total 8 directions including corners + + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + NUM = "B123456789" + dx = [1, 0, -1, 0, 1, 1, -1, -1] + dy = [0, 1, 0, -1, 1, -1, 1, -1] + queue = collections.deque([click]) + m, n = len(board), len(board[0]) + # symbols = set(["M", 'E']) + while queue: + i, j = queue.popleft() + if board[i][j] == "B": # if it is already revealed + continue + if board[i][j] == "M": # if click on mine + board[i][j] = "X" + break + mine_cnt = 0 + neighbors = [] + for k in range(8): + ni, nj = i + dx[k], j + dy[k] + if 0<=ni 0 and five > 0: + ten -= 1 + five -= 1 + elif five >= 3: # otherwise three fives + five -= 3 + else: + return False + return True + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_101/[874]Walking Robot Simulation.py b/Week 03/id_101/[874]Walking Robot Simulation.py new file mode 100644 index 000000000..7e1b66fbb --- /dev/null +++ b/Week 03/id_101/[874]Walking Robot Simulation.py @@ -0,0 +1,103 @@ +#A robot on an infinite grid starts at point (0, 0) and faces north. The robot can receive one of three possible types of commands: +# +# +# -2: turn left 90 degrees +# -1: turn right 90 degrees +# 1 <= x <= 9: move forward x units +# +# +# Some of the grid squares are obstacles. +# +# The i-th obstacle is at grid point (obstacles[i][0], obstacles[i][1]) +# +# If the robot would try to move onto them, the robot stays on the previous grid square instead (but still continues following the rest of the route.) +# +# Return the square of the maximum Euclidean distance that the robot will be from the origin. +# +# +# +# Example 1: +# +# +#Input: commands = [4,-1,3], obstacles = [] +#Output: 25 +#Explanation: robot will go to (3, 4) +# +# +# +# Example 2: +# +# +#Input: commands = [4,-1,4,-2,4], obstacles = [[2,4]] +#Output: 65 +#Explanation: robot will be stuck at (1, 4) before turning left and going to (1, 8) +# +# +# +# +# +# Note: +# +# +# 0 <= commands.length <= 10000 +# 0 <= obstacles.length <= 10000 +# -30000 <= obstacle[i][0] <= 30000 +# -30000 <= obstacle[i][1] <= 30000 +# The answer is guaranteed to be less than 2 ^ 31. +# +# Related Topics Greedy + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def robotSim(self, commands, obstacles): + """ + :type commands: List[int] + :type obstacles: List[List[int]] + :rtype: int + """ + # facing north first + dx = [0, 1, 0, -1] + dy = [1, 0, -1, 0] + ''' + x,y+1 (1) + x-1,y (4)<- x,y -> x+1,y (2) + x,y-1 (3) + ''' + obstacles_set = set(map(tuple, obstacles)) + res = 0 + x, y, d = 0, 0, 0 + for cmd in commands: + if cmd == -2: # left is (idx-1) where idx is direction index + d = (d-1) % 4 + elif cmd == -1: # right is (idx+1) + d = (d+1) % 4 + else: + while cmd > 0 and (x+dx[d], y+dy[d]) not in obstacles_set: + x, y = x+dx[d], y+dy[d] + cmd -= 1 + res = max(res, x**2 + y**2) + return res + + + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + x, y = 0, 0 # pos + dx, dy = 0, 1 # direction (north) + obstacles = set(map(tuple, obstacles)) + res = 0 + for cmd in commands: + if cmd == -2: + dx, dy = -dy, dx # left + elif cmd == -1: + dx, dy = dy, -dx # right + else: + for _ in range(cmd): + if (x+dx, y+dy) in obstacles: + break + x += dx + y += dy + res = max(res, x**2 + y**2) + return res + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_106/529.minesweeper.java b/Week 03/id_106/529.minesweeper.java new file mode 100644 index 000000000..e535e1474 --- /dev/null +++ b/Week 03/id_106/529.minesweeper.java @@ -0,0 +1,147 @@ +/* + * @lc app=leetcode id=529 lang=java + * + * [529] Minesweeper + * + * https://leetcode.com/problems/minesweeper/description/ + * + * algorithms + * Medium (54.79%) + * Likes: 396 + * Dislikes: 379 + * Total Accepted: 42.6K + * Total Submissions: 77.4K + * Testcase Example: '[["E","E","E","E","E"],["E","E","M","E","E"],["E","E","E","E","E"],["E","E","E","E","E"]]\n[3,0]' + * + * Let's play the minesweeper game (Wikipedia, online game)! + * + * You are given a 2D char matrix representing the game board. 'M' represents + * an unrevealed mine, 'E' represents an unrevealed empty square, 'B' + * represents a revealed blank square that has no adjacent (above, below, left, + * right, and all 4 diagonals) mines, digit ('1' to '8') represents how many + * mines are adjacent to this revealed square, and finally 'X' represents a + * revealed mine. + * + * Now given the next click position (row and column indices) among all the + * unrevealed squares ('M' or 'E'), return the board after revealing this + * position according to the following rules: + * + * + * If a mine ('M') is revealed, then the game is over - change it to 'X'. + * If an empty square ('E') with no adjacent mines is revealed, then change it + * to revealed blank ('B') and all of its adjacent unrevealed squares should be + * revealed recursively. + * If an empty square ('E') with at least one adjacent mine is revealed, then + * change it to a digit ('1' to '8') representing the number of adjacent + * mines. + * Return the board when no more squares will be revealed. + * + * + * + * + * Example 1: + * + * + * Input: + * + * [['E', 'E', 'E', 'E', 'E'], + * ⁠['E', 'E', 'M', 'E', 'E'], + * ⁠['E', 'E', 'E', 'E', 'E'], + * ⁠['E', 'E', 'E', 'E', 'E']] + * + * Click : [3,0] + * + * Output: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'M', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * Explanation: + * + * + * + * Example 2: + * + * + * Input: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'M', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * Click : [1,2] + * + * Output: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'X', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * Explanation: + * + * + * + * + * + * Note: + * + * + * The range of the input matrix's height and width is [1,50]. + * The click position will only be an unrevealed square ('M' or 'E'), which + * also means the input board contains at least one clickable square. + * The input board won't be a stage when game is over (some mines have been + * revealed). + * For simplicity, not mentioned rules should be ignored in this problem. For + * example, you don't need to reveal all the unrevealed mines when the game is + * over, consider any cases that you will win the game or flag any squares. + * + * + */ + +// @lc code=start +class Solution { + public char[][] updateBoard(char[][] board, int[] click) { + int m = board.length, n = board[0].length; + int row = click[0], col = click[1]; + + if (board[row][col] == 'M') { // Mine + board[row][col] = 'X'; + } + else { // Empty + // Get number of mines first. + int count = 0; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + + if (count > 0) { // If it is not a 'B', stop further DFS. + board[row][col] = (char)(count + '0'); + } + else { // Continue DFS to adjacent cells. + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'E') updateBoard(board, new int[] {r, c}); + } + } + } + } + + return board; + } +} +// @lc code=end +//DFS 解法,也可使用BFS解法 + diff --git a/Week 03/id_106/74.search-a-2-d-matrix.java b/Week 03/id_106/74.search-a-2-d-matrix.java new file mode 100644 index 000000000..d925a6b7d --- /dev/null +++ b/Week 03/id_106/74.search-a-2-d-matrix.java @@ -0,0 +1,75 @@ +/* + * @lc app=leetcode id=74 lang=java + * + * [74] Search a 2D Matrix + * + * https://leetcode.com/problems/search-a-2d-matrix/description/ + * + * algorithms + * Medium (35.37%) + * Likes: 1086 + * Dislikes: 126 + * Total Accepted: 258.3K + * Total Submissions: 729.1K + * Testcase Example: '[[1,3,5,7],[10,11,16,20],[23,30,34,50]]\n3' + * + * Write an efficient algorithm that searches for a value in an m x n matrix. + * This matrix has the following properties: + * + * + * Integers in each row are sorted from left to right. + * The first integer of each row is greater than the last integer of the + * previous row. + * + * + * Example 1: + * + * + * Input: + * matrix = [ + * ⁠ [1, 3, 5, 7], + * ⁠ [10, 11, 16, 20], + * ⁠ [23, 30, 34, 50] + * ] + * target = 3 + * Output: true + * + * + * Example 2: + * + * + * Input: + * matrix = [ + * ⁠ [1, 3, 5, 7], + * ⁠ [10, 11, 16, 20], + * ⁠ [23, 30, 34, 50] + * ] + * target = 13 + * Output: false + * + */ + +// @lc code=start +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + + // 二分查找 + int left = 0, right = m * n - 1; + int pivotIdx, pivotElement; + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if (target == pivotElement) return true; + else { + if (target < pivotElement) right = pivotIdx - 1; + else left = pivotIdx + 1; + } + } + return false; + } +} +// @lc code=end + diff --git a/Week 03/id_106/860.lemonade-change.java b/Week 03/id_106/860.lemonade-change.java new file mode 100644 index 000000000..11a0abb25 --- /dev/null +++ b/Week 03/id_106/860.lemonade-change.java @@ -0,0 +1,118 @@ +/* + * @lc app=leetcode id=860 lang=java + * + * [860] Lemonade Change + * + * https://leetcode.com/problems/lemonade-change/description/ + * + * algorithms + * Easy (50.78%) + * Likes: 368 + * Dislikes: 63 + * Total Accepted: 35.3K + * Total Submissions: 69.4K + * Testcase Example: '[5,5,5,10,20]' + * + * At a lemonade stand, each lemonade costs $5.  + * + * Customers are standing in a queue to buy from you, and order one at a time + * (in the order specified by bills). + * + * Each customer will only buy one lemonade and pay with either a $5, $10, or + * $20 bill.  You must provide the correct change to each customer, so that the + * net transaction is that the customer pays $5. + * + * Note that you don't have any change in hand at first. + * + * Return true if and only if you can provide every customer with correct + * change. + * + * + * + * + * Example 1: + * + * + * Input: [5,5,5,10,20] + * Output: true + * Explanation: + * From the first 3 customers, we collect three $5 bills in order. + * From the fourth customer, we collect a $10 bill and give back a $5. + * From the fifth customer, we give a $10 bill and a $5 bill. + * Since all customers got correct change, we output true. + * + * + * + * Example 2: + * + * + * Input: [5,5,10] + * Output: true + * + * + * + * Example 3: + * + * + * Input: [10,10] + * Output: false + * + * + * + * Example 4: + * + * + * Input: [5,5,10,10,20] + * Output: false + * Explanation: + * From the first two customers in order, we collect two $5 bills. + * For the next two customers in order, we collect a $10 bill and give back a + * $5 bill. + * For the last customer, we can't give change of $15 back because we only have + * two $10 bills. + * Since not every customer received correct change, the answer is false. + * + * + * + * + * Note: + * + * + * 0 <= bills.length <= 10000 + * bills[i] will be either 5, 10, or 20. + * + * + * + * + * + * + */ + +// @lc code=start +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; + } +} +// @lc code=end + diff --git a/Week 03/id_111/NOTE.md b/Week 03/id_111/NOTE.md index a6321d6e2..e1dacd234 100644 --- a/Week 03/id_111/NOTE.md +++ b/Week 03/id_111/NOTE.md @@ -1,4 +1,89 @@ -# NOTE +# 九、十、十一课(DFS BFS |Greedy |Binary search) +--- +## 深度优先搜索、广度优先搜索(第九课) +### 定义 + 实现遍历,需保证每个节点都要访问且仅访问一次 +### 深度优先搜索(DFS) +**示例代码** + 1. 递归,遍历顺序 +- 根节点起始,选一个方向走到底 +- 返回查看是否有子节点 + 2. 非递归写法 +- 手动维护栈: +- 代码示例 +### 广度优先(BFS) + 发散方式 + 本身使用 queque 和一个循环进行实现 + 队列形式 +- VIUALGO.NET +### 实战题目 +- 102 Binary Tree Level Order Tracersal 二叉树的层次遍历 + - 思路一 BFS 即广度优先模式 + 标识每一层的结束 + - DFS 标记访问目标的层,最后进行加和 + 访问结点时有深度信息 + - 迭代 (实际也为广度优先搜索 +- 433 最小基因变化 minimum genetic mutation + BFS 即可解决 +- 22 括号生成 + - 递归 + - DFS + 左右括号可以出来一个递归的状态树 + - 作业:此题使用BFS 进行解答 +### HOME_WORK +word-ladder/description +word-ladder-ii 高频 +- 220 岛屿数量 +二维矩阵判定网格岛屿数量 +DFS +遇岛夷地(floodfill) +BFS扩散 +并查集 +## 贪心算法Greedy(第十课) +### 定义拆解 +- 当下每一步做出最优选择且不会回退(动态规划会保存每一步选择,可回退 +- 可解决最优化问题 + 图中最小生成树 + 求哈夫曼编码 +- 可用作辅助算法/作辅助算法,解决对结果精确要求不高的问题 +### Coin Change +- 按面值大小降序,依次算对应的硬币可以用多少个【备选硬币与目标数据存在整除关系时,贪心算法易于得到最优解 +### 可用贪心算法的情况 +- 可分解为子问题,且子问题最优解能地推到最终问题的最优解 +## 二分查找 +### **前提** +1. 目标函数具有单调性(单调递增或单调递减) +2. 存在上下界(bounded) +3. 能通过索引访问(index accessible) +### 代码模板 +> left,right = 0,len(array) - 1 +while left <= right: + mid = (left+ right)​/2 + if array[mid] == target: + ​​#find the target + ​​break or return result + elif array[mid] < target: + ​​ ​​left = mid +1 + else: + right = mid -1​​ +### 代码题解 +- 实现 int sqrt(int x) +二分法 +牛顿迭代法(现实中反而用的多) +r = (r+x/r)/2 +python :r = xwhile r*r >x: r = (r+x/r)/2 while r*r >xreturn r​​​​ +- leetcode 367 +- homework 1 题 + +###五毒神掌:四步做题法 +1. 审题 。细节 边界 输入输出范围 +2. 所有解法思考一遍,关于时间空间复杂度列出,探讨最优解法。 +- 暴力:还原 -> 变成严格升序数组 -> 二分法:O(logN) +- 正解:二分查找 +a. 单调 +b. 边界 +3. 写代码 +4. 测试 diff --git a/Week 03/id_111/leetcode_127_111.py b/Week 03/id_111/leetcode_127_111.py new file mode 100644 index 000000000..5d17bdf70 --- /dev/null +++ b/Week 03/id_111/leetcode_127_111.py @@ -0,0 +1,78 @@ +# 127 单词接龙 +"""给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。 +转换需遵循如下规则: +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 + +说明: +如果不存在这样的转换序列,返回 0。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +""" +#广度优先 BFS 代码模板: +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) +#代码解决:(实在写不出来抄了一遍) +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + + if endWord not in wordList: + return 0 + # 前提:单词字典中所有单词长度一致 + L = len(beginWord) + + # Dictionary to hold combination of words that can be formed, + # from any given word. By changing one letter at a time. + all_combo_dict = defaultdict(list) + for word in wordList: + for i in range(L): + # Key is the generic word + # Value is a list of words which have the same intermediate generic word. + all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + + + # 建立 BFS 队列 + queue = collections.deque([(beginWord, 1)]) + # 建立是否访问 避免重复访问 + visited = {beginWord: True} + while queue: + current_word, level = queue.popleft() + for i in range(L): + # Intermediate words for current word + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + + # Next states are all the words which share the same intermediate state. + for word in all_combo_dict[intermediate_word]: + # If at any point if we find what we are looking for + # i.e. the end word - we can return with the answer. + if word == endWord: + return level + 1 + # Otherwise, add it to the BFS Queue. Also mark it visited + if word not in visited: + visited[word] = True + queue.append((word, level + 1)) + all_combo_dict[intermediate_word] = [] + return 0 + + # queue = set() + # visited = set() + # visitied.add(beginWord) + + # word_len = len(beginWord) + # res = 1 + # #BFS + # while queue: + # node = queue + diff --git "a/Week 03/id_116/[200]\345\262\233\345\261\277\346\225\260\351\207\217.py" "b/Week 03/id_116/[200]\345\262\233\345\261\277\346\225\260\351\207\217.py" new file mode 100644 index 000000000..761cce706 --- /dev/null +++ "b/Week 03/id_116/[200]\345\262\233\345\261\277\346\225\260\351\207\217.py" @@ -0,0 +1,54 @@ +#给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 +# +# 示例 1: +# +# 输入: +#11110 +#11010 +#11000 +#00000 +# +#输出: 1 +# +# +# 示例 2: +# +# 输入: +#11000 +#11000 +#00100 +#00011 +# +#输出: 3 +# +# Related Topics 深度优先搜索 广度优先搜索 并查集 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + if not grid: + return 0 + + count = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + if grid[i][j] == '1': + self.dfs(grid, i, j) + count += 1 + return count + + def dfs(self, grid, i, j): + if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] != '1': + return + grid[i][j] = '#' + self.dfs(grid, i + 1, j) + self.dfs(grid, i - 1, j) + self.dfs(grid, i, j + 1) + self.dfs(grid, i, j - 1) +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 03/id_116/[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.py" "b/Week 03/id_116/[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.py" new file mode 100644 index 000000000..f09942c3c --- /dev/null +++ "b/Week 03/id_116/[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.py" @@ -0,0 +1,55 @@ +#假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +# +# ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +# +# 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +# +# 你可以假设数组中不存在重复的元素。 +# +# 你的算法时间复杂度必须是 O(log n) 级别。 +# +# 示例 1: +# +# 输入: nums = [4,5,6,7,0,1,2], target = 0 +#输出: 4 +# +# +# 示例 2: +# +# 输入: nums = [4,5,6,7,0,1,2], target = 3 +#输出: -1 +# Related Topics 数组 二分查找 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + if not nums: + return -1 + + low, high = 0, len(nums) - 1 + + while low <= high: + mid = (low + high) / 2 + if target == nums[mid]: + return mid + + if nums[low] <= nums[mid]: + if nums[low] <= target <= nums[mid]: + high = mid - 1 + else: + low = mid + 1 + else: + if nums[mid] <= target <= nums[high]: + low = mid + 1 + else: + high = mid - 1 + + return -1 +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 03/id_116/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" "b/Week 03/id_116/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" new file mode 100644 index 000000000..f2e2c0405 --- /dev/null +++ "b/Week 03/id_116/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" @@ -0,0 +1,73 @@ +#在柠檬水摊上,每一杯柠檬水的售价为 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 贪心算法 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def lemonadeChange(self, bills): + """ + :type bills: List[int] + :rtype: bool + """ + five = ten = 0 + for i in bills: + if i == 5: five += 1 + elif i == 10: five, ten = five - 1, ten + 1 + elif ten > 0: five, ten = five - 1, ten - 1 + else: five -= 3 + if five < 0: return False + return True + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_126/LeetCode_127_126.py b/Week 03/id_126/LeetCode_127_126.py new file mode 100644 index 000000000..edb05e31b --- /dev/null +++ b/Week 03/id_126/LeetCode_127_126.py @@ -0,0 +1,24 @@ +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if endWord not in wordList: + return 0 + wordict = set(wordList) + s1 = {beginWord} + s2 = {endWord} + n = len(beginWord) + step = 0 + wordict.remove(endWord) + while s1 and s2: + step += 1 + if len(s1) > len(s2): s1, s2 = s2, s1 + s = set() + for word in s1: + nextword = [word[:i] + chr(j) + word[i + 1:] for j in range(97, 123) for i in range(n)] + for w in nextword: + if w in s2: + return step + 1 + if w not in wordict: continue + wordict.remove(w) + s.add(w) + s1 = s + return 0 \ No newline at end of file diff --git a/Week 03/id_126/LeetCode_33_126.py b/Week 03/id_126/LeetCode_33_126.py new file mode 100644 index 000000000..7208f04a2 --- /dev/null +++ b/Week 03/id_126/LeetCode_33_126.py @@ -0,0 +1,25 @@ +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums:return -1 + n = len(nums) + left = 0 + right = len(nums) - 1 + while left < right: + mid = left + (right - left) //2 + if nums[mid] > nums[right]: + left = mid + 1 + else: + right = mid + t = left + left = 0 + right = len(nums) - 1 + while left <= right: + mid = (left + right) //2 + realmid = (mid + t) % n + if nums[realmid] == target: + return realmid + elif nums[realmid] > target: + right = mid - 1 + else: + left = mid + 1 + return -1 diff --git a/Week 03/id_131/LeetCode_122_131.java b/Week 03/id_131/LeetCode_122_131.java new file mode 100644 index 000000000..d794a855e --- /dev/null +++ b/Week 03/id_131/LeetCode_122_131.java @@ -0,0 +1,15 @@ +package com.lzhlyle.leetcode.self.no122; + +public class BestTimeToBuyAndSellStockII { + public int maxProfit(int[] prices) { + // base condition + if (prices == null || prices.length < 2) return 0; + + // greedy + int max = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) max = max + prices[i] - prices[i - 1]; + } + return max; + } +} diff --git a/Week 03/id_131/LeetCode_126_131.java b/Week 03/id_131/LeetCode_126_131.java new file mode 100644 index 000000000..8326a125a --- /dev/null +++ b/Week 03/id_131/LeetCode_126_131.java @@ -0,0 +1,103 @@ +package com.lzhlyle.leetcode.self.no126; + +import java.util.*; + +public class WordLadderII_2_1 { + // 18ms + public List> findLadders(String beginWord, String endWord, List wordList) { + // base condition + Set meets = new HashSet<>(wordList); + if (!meets.contains(endWord)) return Collections.emptyList(); + + // double end bfs + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + Map> neighborsMap = new HashMap<>(); + if (!this._doubleEndBfs(beginSet, endSet, neighborsMap, true, meets)) return Collections.emptyList(); + + // dfs + List> result = new ArrayList<>(); + this._dfs(beginWord, endWord, neighborsMap, new LinkedList<>(), result); + return result; + } + + private boolean _doubleEndBfs(Set beginSet, Set endSet, Map> neighborsMap, + boolean isFromBeginToEnd, Set meets) { + // terminator + if (beginSet.size() == 0) return false; + + // process + meets.removeAll(beginSet); + Set nextLevelSet = new HashSet<>(); + boolean isMeetInCurrLevel = false; + + // iterate: every word, every char, every possibility + for (String beginWord : beginSet) { + char[] chars = beginWord.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char stash = chars[i]; + + for (char c = 'a'; c <= 'z'; c++) { + chars[i] = c; + String newWord = String.valueOf(chars); + if (!meets.contains(newWord)) continue; + + if (endSet.contains(newWord)) isMeetInCurrLevel = true; + else nextLevelSet.add(newWord); + + // record into neighbors + String key = isFromBeginToEnd ? beginWord : newWord; + String neighbor = isFromBeginToEnd ? newWord : beginWord; + if (!neighborsMap.containsKey(key)) neighborsMap.put(key, new ArrayList<>()); + neighborsMap.get(key).add(neighbor); + } + + // back tracking + chars[i] = stash; + } + } + + if (isMeetInCurrLevel) return true; + + // drill down + // always from less to more + if (nextLevelSet.size() < endSet.size()) { + return this._doubleEndBfs(nextLevelSet, endSet, neighborsMap, isFromBeginToEnd, meets); + } + return this._doubleEndBfs(endSet, nextLevelSet, neighborsMap, !isFromBeginToEnd, meets); + + // reverse state + } + + private void _dfs(String beginWord, String endWord, Map> neighborsMap, + Deque path, List> result) { + // terminator + if (!result.isEmpty() && path.isEmpty()) return; + + // process + // append into path + path.addLast(beginWord); + + // complete a path + if (beginWord.equals(endWord)) result.add(new ArrayList<>(path)); + else if (neighborsMap.containsKey(beginWord)) { + // drill down + // has neighbors + // iterate every neighbor + for (String neighbor : neighborsMap.get(beginWord)) { + this._dfs(neighbor, endWord, neighborsMap, path, result); + } + } + + // back tracking + path.removeLast(); + + // reverse state + } + + public static void main(String[] args) { + Object res = new WordLadderII_2_1().findLadders("hit", "cog", + Arrays.asList("hit", "hot", "dot", "dog", "lot", "log", "cog")); + System.out.println(res); + } +} diff --git a/Week 03/id_131/LeetCode_127_131.java b/Week 03/id_131/LeetCode_127_131.java new file mode 100644 index 000000000..2525785b5 --- /dev/null +++ b/Week 03/id_131/LeetCode_127_131.java @@ -0,0 +1,59 @@ +package com.lzhlyle.leetcode.self.no127; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WordLadder_5 { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord)) return 2; + + Set meets = new HashSet<>(wordList); // O(n) + + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + + return this._search(1, beginSet, endSet, meets); + } + + private int _search(int level, Set beginSet, Set endSet, Set meets) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; + + // process + meets.removeAll(beginSet); + level++; + Set nextLevelSet = new HashSet<>(); + // iter every begin word + for (String beginWord : beginSet) { + char[] chars = beginWord.toCharArray(); + // iter for every char + for (int i = 0; i < chars.length; i++) { // O(k) + char temp = chars[i]; + // replace every letter + for (char ch = 'a'; ch < 'z'; ch++) { // O(1) 都是26遍 + chars[i] = ch; + String newWord = String.valueOf(chars); + if (!meets.contains(newWord)) continue; + if (endSet.contains(newWord)) return level; + nextLevelSet.add(newWord); + } + // reverse + chars[i] = temp; + } + } + + // drill down + // always from less to more + if (nextLevelSet.size() <= endSet.size()) { + beginSet = nextLevelSet; + } else { + beginSet = endSet; + endSet = nextLevelSet; + } + + return this._search(level, beginSet, endSet, meets); + } +} diff --git a/Week 03/id_131/LeetCode_153_131.java b/Week 03/id_131/LeetCode_153_131.java new file mode 100644 index 000000000..37e555d63 --- /dev/null +++ b/Week 03/id_131/LeetCode_153_131.java @@ -0,0 +1,18 @@ +package com.lzhlyle.leetcode.self.no153; + +public class FindMinimumInRotatedSortedArray_2 { + public int findMin(int[] nums) { + // base condition + if (nums == null || nums.length < 1) return -1; + if (nums.length == 1 || nums[0] < nums[nums.length - 1]) return nums[0]; + + // binary search: compare right + int left = 0, right = nums.length - 1; + while (left < right) { + int mid = left + (right - left) / 2; + if (nums[mid] < nums[right]) right = mid; + else left = mid + 1; + } + return nums[left]; + } +} diff --git a/Week 03/id_131/LeetCode_200_131.java b/Week 03/id_131/LeetCode_200_131.java new file mode 100644 index 000000000..93341b922 --- /dev/null +++ b/Week 03/id_131/LeetCode_200_131.java @@ -0,0 +1,51 @@ +package com.lzhlyle.leetcode.self.no200; + +public class NumberOfIslands_Short { + public int numIslands(char[][] grid) { + // base condition + if (grid.length <= 0 || grid[0].length <= 0) return 0; + + int count = 0; + + // traversal + for (int row = 0; row < grid.length; row++) { + for (int col = 0; col < grid[row].length; col++) { + if (grid[row][col] == '1') { + // dfs + count += this._sinkDown(grid, row, col); + } + } + } + + return count; + } + + private int _sinkDown(char[][] grid, int row, int col) { + // terminator + if (row < 0 || col < 0 || row >= grid.length || col >= grid[0].length || grid[row][col] == '0') return 0; + + // process + grid[row][col] = '0'; + + // drill down + this._sinkDown(grid, row, col + 1); // east + this._sinkDown(grid, row, col - 1); // west + this._sinkDown(grid, row + 1, col); // south + this._sinkDown(grid, row - 1, col); // north + + // reverse state + + return 1; + } + + public static void main(String[] args) { + char[][] grid = new char[][]{ + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '1'}, + {'0', '0', '1', '1', '0'} + }; + int res = new NumberOfIslands_Short().numIslands(grid); + System.out.println(res); + } +} diff --git a/Week 03/id_131/LeetCode_455_131.java b/Week 03/id_131/LeetCode_455_131.java new file mode 100644 index 000000000..95204c70e --- /dev/null +++ b/Week 03/id_131/LeetCode_455_131.java @@ -0,0 +1,20 @@ +package com.lzhlyle.leetcode.self.no455; + +import java.util.Arrays; + +public class AssignCookies_3 { + public int findContentChildren(int[] g, int[] s) { + // base condition + if (g == null || s == null || g.length < 1 || s.length < 1) return 0; + + // greedy + Arrays.sort(g); + Arrays.sort(s); + + int count = 0; + for (int cookie = 0; cookie < s.length && count < g.length; cookie++) { + if (g[count] <= s[cookie]) count++; + } + return count; + } +} diff --git a/Week 03/id_131/LeetCode_55_131.java b/Week 03/id_131/LeetCode_55_131.java new file mode 100644 index 000000000..186b9f309 --- /dev/null +++ b/Week 03/id_131/LeetCode_55_131.java @@ -0,0 +1,23 @@ +package com.lzhlyle.leetcode.self.no55; + +public class JumpGame_2 { + // 1ms + public boolean canJump(int[] nums) { + // base condition + if (nums == null || nums.length < 1) return false; + if (nums.length == 1) return true; + + // greedy, backward + int last = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + if (i + nums[i] >= last) last = i; + } + return last == 0; + } + + public static void main(String[] args) { + int[] nums = new int[]{2, 0, 0}; + boolean can = new JumpGame_2().canJump(nums); + System.out.println(can); + } +} diff --git a/Week 03/id_136/LeetCode_127_136.java b/Week 03/id_136/LeetCode_127_136.java new file mode 100644 index 000000000..17decb047 --- /dev/null +++ b/Week 03/id_136/LeetCode_127_136.java @@ -0,0 +1,34 @@ +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class n0127 { + + public int ladderLength(String beginWord, String endWord, List wordList) { + Set wordSet=new HashSet<>(wordList); + Set reached=new HashSet<>(); + reached.add(beginWord); + wordSet.remove(beginWord); + int level=1; + while(!reached.isEmpty()) { + Set reachedNext=new HashSet<>(); + for(String s:reached) { + for(int i=0;i=0 && j>=0 && i prices[i - 1]) { + maxProfit += prices[i] - prices [i - 1]; + } + } + return maxProfit; + } +} \ No newline at end of file diff --git a/Week 03/id_141/LeeCode_33_141.java b/Week 03/id_141/LeeCode_33_141.java new file mode 100644 index 000000000..c1b13faac --- /dev/null +++ b/Week 03/id_141/LeeCode_33_141.java @@ -0,0 +1,44 @@ +package app; + +/** + * SearchInRotatedSortedArray + */ +public class SearchInRotatedSortedArray { + + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + + int start = 0; + int end = nums.length - 1; + + while(start + 1 < end){ + int mid = start + (end - start) / 2; + + if(nums[mid] == target){ + return mid; + } + if(nums[mid] > nums[start]){ + if(target >= nums[start] && target < nums[mid]){ + end = mid; + }else{ + start = mid; + } + }else if (nums[mid] < nums[end]){ + if(target <= nums[end] && target > nums[mid]){ + start = mid; + }else{ + end = mid; + } + } + } + + if(nums[start] == target){ + return start; + }else if (nums[end] == target){ + return end; + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_141/LeeCode_55_141.java b/Week 03/id_141/LeeCode_55_141.java new file mode 100644 index 000000000..46d1e007a --- /dev/null +++ b/Week 03/id_141/LeeCode_55_141.java @@ -0,0 +1,16 @@ +package app; + +/** + * JumpGame + */ +public class JumpGame { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + if (i + nums[i] >= lastPos) { + lastPos = i; + } + } + return lastPos == 0; + } +} \ No newline at end of file diff --git a/Week 03/id_151/LeetCode_122_151.cpp b/Week 03/id_151/LeetCode_122_151.cpp new file mode 100644 index 000000000..1a5f80001 --- /dev/null +++ b/Week 03/id_151/LeetCode_122_151.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + int maxProfit(vector& prices) { + if (prices.empty()) + return 0; + + int have = prices[0]; + int earn = 0; + for (int i = 1; i < prices.size(); ++i) { + if (prices[i] > have) { + earn += prices[i] - have; + } + have = prices[i]; + } + + return earn; + } +}; diff --git a/Week 03/id_151/LeetCode_126_151.cpp b/Week 03/id_151/LeetCode_126_151.cpp new file mode 100644 index 000000000..d007eea41 --- /dev/null +++ b/Week 03/id_151/LeetCode_126_151.cpp @@ -0,0 +1,58 @@ +class Solution { +public: + vector> findLadders(string beginWord, string endWord, vector& wordList) { + vector> ret; + // 用set大概率会超时 + unordered_set sw(wordList.begin(), wordList.end()); + queue> q; + q.push({beginWord}); + + set marker; + bool flag = false; + while (! q.empty()) { + int qs = q.size(); + + for (int i = 0; i < qs; ++i) { + vector cur = q.front(); + q.pop(); + + vector oneSteps = oneStepWord2(cur.back(), sw); + for (const auto& w : oneSteps) { + marker.insert(w); + vector newLine(cur.begin(), cur.end()); + newLine.push_back(w); + q.push(newLine); + + if (w == endWord) { + flag = true; + ret.push_back(newLine); + } + } + } + if (flag) + break; + + // 缩小候选集的个数, 能大大减少内存占用 + for (const auto& m : marker) sw.erase(m); + marker.clear(); + } + return ret; + } + + vector oneStepWord2(string& word, unordered_set& wordList) { + vector ret; + for (int i = 0; i < word.size(); ++i) { + char s = word[i]; + for (char c = 'a'; c <= 'z'; ++c) { + if (s == c) + continue; + + word[i] = c; + if (wordList.count(word)) + ret.push_back(word); + } + word[i] = s; + } + return ret; + } +}; diff --git a/Week 03/id_151/LeetCode_127_151.cpp b/Week 03/id_151/LeetCode_127_151.cpp new file mode 100644 index 000000000..64ae37324 --- /dev/null +++ b/Week 03/id_151/LeetCode_127_151.cpp @@ -0,0 +1,54 @@ +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + map> m; + bool found = false; + for (const auto& word : wordList) { + for (int i = 0; i < word.size(); ++i) { + string tmp = word; + tmp[i] = '*'; + m[tmp].insert(word); + } + if (word == endWord) + found = true; + } + + if (! found) + return 0; + + deque q; + q.push_back(beginWord); + + set marker; + + found = false; + int depth = 1; + while (! q.empty()) { + int nq = q.size(); + for (int n = 0; n < nq; ++n) { + string word = q.front(); + if (word == endWord) { + found = true; + return depth; + } + + + q.pop_front(); + for (int i = 0; i < word.size(); ++i) { + string tmp = word; + tmp[i] = '*'; + + for (const auto& w : m[tmp]) { + if (marker.count(w)) + continue; + marker.insert(w); + q.push_back(w); + } + } + } + + ++depth; + } + return found ? depth : 0; + } +}; diff --git a/Week 03/id_151/LeetCode_153_151.cpp b/Week 03/id_151/LeetCode_153_151.cpp new file mode 100644 index 000000000..f45837195 --- /dev/null +++ b/Week 03/id_151/LeetCode_153_151.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + int findMin(vector& nums) { + if (nums.empty()) + return -1; + + if (nums[0] < nums[nums.size() - 1]) + return nums[0]; + + int left = 0; + int right = nums.size() - 1; + + while (left < right) { + int mid = left + (right - left) / 2; + + if (nums[0] <= nums[mid]) { + left = mid + 1; + } else { + right = mid; + } + } + return nums[left]; + } +}; diff --git a/Week 03/id_151/LeetCode_200_151.cpp b/Week 03/id_151/LeetCode_200_151.cpp new file mode 100644 index 000000000..562a2c05f --- /dev/null +++ b/Week 03/id_151/LeetCode_200_151.cpp @@ -0,0 +1,35 @@ +class Solution { +public: + int numIslands(vector>& grid) { + int num = 0; + for (int y = 0; y < grid.size(); ++y) { + for (int x = 0; x < grid[y].size(); ++x) { + if (grid[y][x] == '1') { + num += bomb(grid, x, y); + } + } + } + return num; + } + + int bomb(vector>& grid, int x, int y) { + if (grid[y][x] == '0') + return 0; + + grid[y][x] = '0'; + + static int dx[4] = {1, -1, 0, 0}; + static int dy[4] = {0, 0, 1, -1}; + for (int i = 0; i < 4; ++i) { + int newx = x + dx[i]; + int newy = y + dy[i]; + + if (newy >= grid.size() || newx >= grid[newy].size()) + continue; + + bomb(grid, newx, newy); + } + + return 1; + } +}; diff --git a/Week 03/id_151/LeetCode_33_151.cpp b/Week 03/id_151/LeetCode_33_151.cpp new file mode 100644 index 000000000..fffbb96e0 --- /dev/null +++ b/Week 03/id_151/LeetCode_33_151.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int search(vector& nums, int target) { + int left = 0; + int right = nums.size() - 1; + int index = -1; + while (left < right) { + int mid = (left + right) / 2; + // 左半边有序 + if (nums[0] <= nums[mid]) { + if (target > nums[mid] || target < nums[0]) { + left = mid + 1; + } else { + right = mid; + } + } else { // 右半边有序 + if (target > nums[mid] && target < nums[0]) { + left = mid + 1; + } else { + right = mid; + } + } + } + + return left == right && nums[left] == target ? left : -1; + } +}; diff --git a/Week 03/id_151/LeetCode_45_151.cpp b/Week 03/id_151/LeetCode_45_151.cpp new file mode 100644 index 000000000..3e45633ee --- /dev/null +++ b/Week 03/id_151/LeetCode_45_151.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int jump(vector& nums) { + int start = 0; + int end = 0; + int step = 0; + + while (end < nums.size() - 1) { + ++step; + int maxEnd = end + 1; + for (int i = start; i <= end; ++i) { + maxEnd = max(i + nums[i], maxEnd); + if (maxEnd >= nums.size() - 1) { + return step; + } + } + + start = end + 1; + end = maxEnd; + } + return step; + } +}; diff --git a/Week 03/id_151/LeetCode_55_151.cpp b/Week 03/id_151/LeetCode_55_151.cpp new file mode 100644 index 000000000..ce4e71444 --- /dev/null +++ b/Week 03/id_151/LeetCode_55_151.cpp @@ -0,0 +1,15 @@ +class Solution { +public: + bool canJump(vector& nums) { + if (nums.empty()) + return true; + + int step = nums.size() - 1; + for (int i = nums.size() - 1; i >= 0; --i) { + if (nums[i] + i >= step) + step = i; + } + + return step == 0; + } +}; diff --git a/Week 03/id_151/LeetCode_74_151.cpp b/Week 03/id_151/LeetCode_74_151.cpp new file mode 100644 index 000000000..a9fb4eaab --- /dev/null +++ b/Week 03/id_151/LeetCode_74_151.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + if (matrix.empty()) + return false; + if (matrix[0].empty()) + return false; + + int left = 0; + int right = matrix.size() * matrix[0].size() - 1; + + while (left < right) { + int mid = left + (right - left) / 2; + + int row = mid / matrix[0].size(); + int col = mid % matrix[0].size(); + + if (matrix[row][col] < target) { + left = mid + 1; + } else { + right = mid; + } + } + return matrix[left / matrix[0].size()][left % matrix[0].size()] == target; + } +}; diff --git a/Week 03/id_151/LeetCode_860_151.cpp b/Week 03/id_151/LeetCode_860_151.cpp new file mode 100644 index 000000000..cd89eb6c9 --- /dev/null +++ b/Week 03/id_151/LeetCode_860_151.cpp @@ -0,0 +1,32 @@ +class Solution { +public: + bool lemonadeChange(vector& bills) { + int num5 = 0; + int num10 = 0; + int num20 = 0; + for (int i = 0; i < bills.size(); ++i) { + int cur = bills[i]; + if (cur == 5) ++num5; + if (cur == 10) ++num10; + if (cur == 20) ++num20; + int left = cur - 5; + while (left >= 20 && num20 > 0) { + left -= 20; + --num20; + } + while (left >= 10 && num10 > 0) { + left -= 10; + --num10; + } + while (left >= 5 && num5 > 0) { + left -= 5; + --num5; + } + + if (left > 0) + return false; + } + + return true; + } +}; diff --git a/Week 03/id_156/153_java.java b/Week 03/id_156/153_java.java new file mode 100644 index 000000000..89f0efdb9 --- /dev/null +++ b/Week 03/id_156/153_java.java @@ -0,0 +1,19 @@ +class Solution { + public int findMin(int[] nums) { + //取一个基准值,这里取最右边 + int left = 0; + int right = nums.length - 1; + int mid; + + while (left < right) { + mid = (left + right) / 2; + if (nums[mid] <= nums[right]) { + right = mid; + } else { + left = mid + 1; + } + } + + return nums[right]; + } +} diff --git a/Week 03/id_156/74_java.java b/Week 03/id_156/74_java.java new file mode 100644 index 000000000..1a99a0f48 --- /dev/null +++ b/Week 03/id_156/74_java.java @@ -0,0 +1,24 @@ + public static boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) {return false;} + int n = matrix[0].length; + + /*二分查找*/ + int left = 0; + int right = m * n -1; + int midIndex; + int midValue; + + while(left <= right) { + midIndex = (left + right) / 2; + midValue = matrix[midIndex / n][midIndex % n]; + if (midValue == target) { + return true; + } else if (midValue < target) { + left = midIndex + 1; + } else { + right = midIndex - 1; + } + } + return false; + } diff --git a/Week 03/id_156/860_java.java b/Week 03/id_156/860_java.java new file mode 100644 index 000000000..d625cae7c --- /dev/null +++ b/Week 03/id_156/860_java.java @@ -0,0 +1,30 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + int len = bills.length; + + for (int i = 0; i < len; i++) { + if (bills[i] == 5) { + five++; + } else if (bills[i] == 10) { + if (five == 0) { + return false; + }; + five--; + ten++; + } else if (bills[i] == 20) { + if (ten > 0 && five > 0) { + ten--; + five--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} + diff --git a/Week 03/id_161/BestTimeToSellAndBuy.java b/Week 03/id_161/BestTimeToSellAndBuy.java new file mode 100644 index 000000000..f81304b0a --- /dev/null +++ b/Week 03/id_161/BestTimeToSellAndBuy.java @@ -0,0 +1,18 @@ +class Solution { + public int maxProfit(int[] prices) { + int i = 0; + int valley = prices[0]; + int peak = prices[0]; + int maxprofit = 0; + while (i < prices.length - 1) { + while (i < prices.length - 1 && prices[i] >= prices[i + 1]) + i++; + valley = prices[i]; + while (i < prices.length - 1 && prices[i] <= prices[i + 1]) + i++; + peak = prices[i]; + maxprofit += peak - valley; + } + return maxprofit; + } +} \ No newline at end of file diff --git a/Week 03/id_161/LemonChange.java b/Week 03/id_161/LemonChange.java new file mode 100644 index 000000000..7000673ed --- /dev/null +++ b/Week 03/id_161/LemonChange.java @@ -0,0 +1,25 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int c5=0; + int c10=0; + for(int bill:bills){ + if(bill==5) + c5+=5; + else if(bill==10){ + if(c5!=0){ + c5-=5; + c10+=10; + }else return false; + + }else if(c10!=0){ + if(c5!=0){ + c5-=5; + c10-=10; + }else return false; + }else if(c5>=15) + c5-=15; + else return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week 03/id_161/islands.java b/Week 03/id_161/islands.java new file mode 100644 index 000000000..61a600d32 --- /dev/null +++ b/Week 03/id_161/islands.java @@ -0,0 +1,36 @@ +class Solution { + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } +} diff --git "a/Week 03/id_161/\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/Week 03/id_161/\345\255\246\344\271\240\346\200\273\347\273\223.md" new file mode 100644 index 000000000..62b7f3c9b --- /dev/null +++ "b/Week 03/id_161/\345\255\246\344\271\240\346\200\273\347\273\223.md" @@ -0,0 +1,100 @@ +# 第三周 + +## 遍历-搜索 + +### 深度优先搜索 +也是递归的一种 +```python +def dfs(node): + # terminator + if(node in visited) + #already visited + return + visited.add(node) + # proccess current node logic... + # drill down + dfs(node.left) + dfs(node.right) +``` + +```python +visited = set() +def dfs(node, visited): + visited.add(node) + for(child in node.children) + if(child not in visited) + dfs(child, visited) +``` + +### 广度优先搜索 +使用循环+队列实现 +```python +def bfs(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while(queue) + node = queue.pop() + visited.add(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + # other processing work + ... + +``` + +## 贪心算法 + +### 贪心算法 +贪心算法是一种在每一步选择中都采取当前状态下最好或最优的选择,从而希望导致结果是全局最优或最好的算法 + +贪心算法和动态规划的不同在于对它对每个子问题的解决方案都作出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能 + +#### 适合贪心算法的场景 +简单来说,问题能够分解成子问题来解决,子问题的最优解能递推出最终问题的最优解。这种子问题最优解称为最优子结构 + +## 二分查找 + +### 二分查找的先决条件 +- 目标函数的单调性(单调递增或递减) +- 存在上下界(bounded) +- 能够通过索引访问(index accessible) + +### 二分查找代码模板 +```python +left = 0, right = len(arr) - 1 +while(left <= right) +mid = left + (right - left) / 2 +if(arr[mid] == target) + # target founded + return result or break; +elif(arr[mid] < target) + left = mid + 1 +else + right = mid - 1 +``` + +### 思考作业 +使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 +思路:首先确认返回条件,即index与后一个数递增,与前一个数递减,然后套用模板,夹逼即可 +```java +public static int findDisorder(int[] arr) { + int left = 0; + int right = arr.length - 1; + while(left <= right) { + int middle = left + (right - left) / 2; + if (arr[middle - 1] > arr[middle] && arr[middle] < arr[middle + 1]) { + return middle; + } else if (arr[middle - 1] > arr[left]) { + // middle处于第一段位置 + left = middle + 1; + } else { + // middle处于第二段位置,但不是分界点 + right = middle - 1; + } + } + + return -1; +} +``` \ No newline at end of file diff --git a/Week 03/id_171/AssignCookiesSol.cs b/Week 03/id_171/AssignCookiesSol.cs new file mode 100644 index 000000000..3757c63a5 --- /dev/null +++ b/Week 03/id_171/AssignCookiesSol.cs @@ -0,0 +1,30 @@ +using System; + +namespace Poplar.Algorithm.WeekThree +{ + /// + /// 分发饼干 + /// https://leetcode.com/problems/assign-cookies + /// https://leetcode-cn.com/problems/assign-cookies + /// + public class AssignCookiesSol + { + public int FindContentChildren(int[] g, int[] s) + { + Array.Sort(g); + Array.Sort(s); + var count = 0; + var i = 0; + var j = 0; + while (i < g.Length && j < s.Length) + { + if (g[i] <= s[j]) + { + i++; + } + j++; + } + return count; + } + } +} diff --git a/Week 03/id_171/BestTimeToBuyAndSellStockIISol.cs b/Week 03/id_171/BestTimeToBuyAndSellStockIISol.cs new file mode 100644 index 000000000..dde44766d --- /dev/null +++ b/Week 03/id_171/BestTimeToBuyAndSellStockIISol.cs @@ -0,0 +1,60 @@ +namespace Poplar.Algorithm.WeekThree +{ + /// + /// 买卖股票最佳时机II + /// https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + /// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + /// + public class BestTimeToBuyAndSellStockIISol + { + public int MaxProfit(int[] prices) + { + //return PeakValley(prices); + return Greedy(prices); + } + + /// + /// 峰谷法,在谷买,在峰卖,减少购买次数 + /// + /// + /// + public int PeakValley(int[] prices) + { + var i = 0; + var profit = 0; + while (i < prices.Length - 1) + { + while (i < prices.Length - 1 && prices[i] >= prices[i + 1]) + { + i++; + } + var buy = prices[i]; + while (i < prices.Length - 1 && prices[i] <= prices[i + 1]) + { + i++; + } + var sell = prices[i]; + profit += sell - buy; + } + return profit; + } + + /// + /// 贪心算法,只要今天价格比明天高,就在今天买明天卖 + /// + /// + /// + private int Greedy(int[] prices) + { + var profit = 0; + for (int i = 0; i < prices.Length - 1; i++) + { + if (prices[i] < prices[i + 1]) + { + profit += prices[i + 1] - prices[i]; + } + } + return profit; + } + } +} diff --git a/Week 03/id_171/FindMinimumInRotatedSortedArraySol.cs b/Week 03/id_171/FindMinimumInRotatedSortedArraySol.cs new file mode 100644 index 000000000..2f9d158f1 --- /dev/null +++ b/Week 03/id_171/FindMinimumInRotatedSortedArraySol.cs @@ -0,0 +1,45 @@ +namespace Poplar.Algorithm.WeekThree +{ + /// + /// 寻找旋转排序数组中的最小值 + /// https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ + /// https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + /// + public class FindMinimumInRotatedSortedArraySol + { + /// + /// 二分查找法 + /// + /// + /// + public int FindMin(int[] nums) + { + if (nums.Length == 1) + { + return nums[0]; + } + var lo = 0; + var hi = nums.Length - 1; + while (lo < hi) + { + if (nums[lo] < nums[hi]) + { + return nums[lo]; + } + var mid = (lo + hi) / 2; + //新的右边界必须是mid + 1,左边界必须是mid。 + //当前循环时,如果左半部分的左边值大于右边值,则证明旋转点在左半部分,此时左半部分的右边界是一个较小的值,它可能是最小值,所以新的右边界不能加1。 + //如果左半部分的左边值小于右边值,则旋转点在右半部分,但是并不会是右半部分的左边界值,因为这个值大于是大于左半部分的左边界值的,所以新的左边界需要加1 + if (nums[lo] > nums[mid]) + { + hi = mid; + } + else + { + lo = mid + 1; + } + } + return nums[lo]; + } + } +} diff --git a/Week 03/id_171/SearchA2dMatrixSol.cs b/Week 03/id_171/SearchA2dMatrixSol.cs new file mode 100644 index 000000000..4e1d1ebf2 --- /dev/null +++ b/Week 03/id_171/SearchA2dMatrixSol.cs @@ -0,0 +1,45 @@ +namespace Poplar.Algorithm.WeekThree +{ + /// + /// 搜索二维矩阵 + /// https://leetcode.com/problems/search-a-2d-matrix/ + /// https://leetcode-cn.com/problems/search-a-2d-matrix/ + /// + public class SearchA2dMatrixSol + { + /// + /// 二分法 + /// + /// + /// + /// + public bool SearchMatrix(int[][] matrix, int target) + { + if (matrix == null || matrix.Length == 0) + { + return false; + } + var width = matrix[0].Length; + var lo = 0; + var hi = width * matrix.Length - 1; + while (lo <= hi) + { + var mid = (lo + hi) / 2; + var cur = matrix[mid / width][mid % width]; + if (cur == target) + { + return true; + } + else if (cur > target) + { + hi = mid - 1; + } + else + { + lo = mid + 1; + } + } + return false; + } + } +} diff --git a/Week 03/id_171/SearchInRotatedSortedArraySol.cs b/Week 03/id_171/SearchInRotatedSortedArraySol.cs new file mode 100644 index 000000000..918d2963d --- /dev/null +++ b/Week 03/id_171/SearchInRotatedSortedArraySol.cs @@ -0,0 +1,46 @@ +namespace Poplar.Algorithm.WeekThree +{ + /// + /// 搜索旋转排序数组 + /// https://leetcode.com/problems/search-in-rotated-sorted-array/ + /// https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + /// + public class SearchInRotatedSortedArraySol + { + /// + /// 二分查找。 + /// 当左半边是有序时并且target不在左半边范围内的,向右走。 + /// 当左半边是无序的并且target大于mid并且target小于索引0的位置,向右走。 + /// 否则就是向左走。 + /// + /// + /// + /// + public int Search(int[] nums, int target) + { + if (nums == null || nums.Length == 0) + { + return -1; + } + var lo = 0; + var hi = nums.Length - 1; + while (lo < hi) + { + var mid = (lo + hi) / 2; + if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) + { + lo = mid + 1; + } + else if (target > nums[mid] && target < nums[0]) + { + lo = mid + 1; + } + else + { + hi = mid; + } + } + return lo == hi && nums[lo] == target ? lo : -1; + } + } +} diff --git a/Week 03/id_176/LeetCode_127_176.swift b/Week 03/id_176/LeetCode_127_176.swift new file mode 100644 index 000000000..fb68d16a4 --- /dev/null +++ b/Week 03/id_176/LeetCode_127_176.swift @@ -0,0 +1,117 @@ +/* + * @lc app=leetcode.cn id=127 lang=swift + * + * [127] 单词接龙 + * + * https://leetcode-cn.com/problems/word-ladder/description/ + * + * algorithms + * Medium (37.12%) + * Likes: 152 + * Dislikes: 0 + * Total Accepted: 13.4K + * Total Submissions: 35.6K + * Testcase Example: '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]' + * + * 给定两个单词(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" 不在字典中,所以无法进行转换。 + * + */ + +// @lc code=start +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + var wordList = Set(wordList) + if !wordList.contains(endWord) { + return 0 + } + + if wordList.contains(beginWord) { + wordList.remove(beginWord) + } + + var (res, forward, backward) = (2, Set([beginWord]), Set([endWord])) + let letters = "abcdefghijklmnopqrstuvwxyz" + let length = endWord.count + + while !forward.isEmpty { + if forward.count > backward.count { + (forward, backward) = (backward, forward) //从小集合开始遍历 + } + + var cur: Set = Set() //相当于层次序遍历中的新一层 + + for word in forward { + + for idx in 0.. Bool { + // let rowSize = matrix.count + // guard rowSize > 0 else { + // return false + // } + + // let colSize = matrix[0].count + // var row = 0, col = colSize - 1 + + // while row < rowSize && col >= 0 { + // let element = matrix[row][col] + // if element < target { + // row += 1 + // } else if (element > target) { + // col -= 1 + // } else { + // return true + // } + // } + + // return false + // } + + //二分法 + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let rowSize = matrix.count + guard rowSize > 0 else { + return false + } + + let colSize = matrix[0].count + var low = 0, high = rowSize * colSize - 1 + while low <= high { + let mid = low + (high - low) / 2 + let element = matrix[mid / colSize][mid % colSize] + if element < target { + low = mid + 1 + } else if (element > target) { + high = mid - 1 + } else { + return true + } + } + + return false + } +} +// @lc code=end + diff --git a/Week 03/id_176/NOTE.md b/Week 03/id_176/NOTE.md index a6321d6e2..a44e06779 100644 --- a/Week 03/id_176/NOTE.md +++ b/Week 03/id_176/NOTE.md @@ -1,4 +1,94 @@ -# NOTE +## NOTE - +搜索 - 遍历 + +- 每个节点都要访问一次 +- 每个节点仅仅要访问一次 +- 对于节点的访问顺序不限 + \- 深度优先(depth first search) + \- 广度优先(breadth first search ) + +### DFS 代码 - 递归写法 + +```python +visited = set() +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + + visited.add(node) + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +``` + +### DFS 代码 - 非递归写法 + +```python +def DFS(self, tree): + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... +``` + +### BFS 代码 + +```python +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + # other processing work + ... +``` + +### 贪心算法 + +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行 选择,有回退功能。 + +贪心法可以解决一些最优化问题,如:求图中的最小生成树、求哈夫曼编码 等。然而对于工程和生活中的问题,贪心法一般不能得到我们所要求的答 案。一旦一个问题可以通过贪心法来解决,那么贪心法一般是解决这个问题的最 好办法。由于贪心法的高效性以及其所求得的答案比较接近最优结果,贪心 法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终 问题的最优解。这种子问题最优解称为最优子结构。 + +### 二分查找 + +1. 目标函数单调性(单调递增或者递减) +2. 存在上下界(bounded) +3. 能够通过索引访问(index accessible) + +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = left + (right - left) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` diff --git a/Week 03/id_181/LeetCode_127_181.py b/Week 03/id_181/LeetCode_127_181.py new file mode 100644 index 000000000..bc2229476 --- /dev/null +++ b/Week 03/id_181/LeetCode_127_181.py @@ -0,0 +1,49 @@ +# [127. 单词接龙 - 力扣(LeetCode)](https://leetcode-cn.com/problems/word-ladder/submissions/) + +from collections import defaultdict +# BFS +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + """ + :type beginWord:str + :type endWord:str + :type wordList:List[str] + :rtype:int + """ + + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + + L = len(beginWord) + + all_combo_dict = defaultdict(list) + + for word in wordList: + for i in range(L): + # 获取所有单词缺位映射 + all_combo_dict[word[:i]+"*"+word[i+1:]].append(word) + + queue = [(beginWord,1)] + + visited = {beginWord:True} # 标记已经访问过的单词 + + while queue: + current_word,level = queue.pop(0) # 删除对应索引的元素,默认删除最后一个 + for i in range(L): + # 当前单词可以配对的形式 intermediate_word + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + # 以此获取 all_combo_dict中可能的结果 + for word in all_combo_dict[intermediate_word]: + if word == endWord: + return level + 1 + + if word not in visited: + visited[word] = True + # 继续寻找下一个的单词 + queue.append((word,level + 1)) + + all_combo_dict[intermediate_word] = [] + + return 0 + + \ No newline at end of file diff --git a/Week 03/id_181/LeetCode_200_181.py b/Week 03/id_181/LeetCode_200_181.py new file mode 100644 index 000000000..a47a74255 --- /dev/null +++ b/Week 03/id_181/LeetCode_200_181.py @@ -0,0 +1,69 @@ +# DFS 深度优先 只要可以往下查就往下查 +from typing import List +from collections import deque + +class Solution: + # 方向数组 + directions=[(-1,0),(0,-1),(1,0),(0,1)] + + def numIslands(self, grid: List[List[str]]) -> int: + # grid的高度 + m = len(grid) + + if m==0: + return 0 + # grid的宽度 + n=len(grid[0]) + # 初始化一个全是False的数组,用以标记遍历过的节点 + marked = [[False for _ in range(n)] for _ in range(m)] + + count = 0 + + for i in range(m): + for j in range(n): + # 没有遍历过,且是岛屿 + if not marked[i][j] and grid[i][j] == '1': + count += 1 + self.__dfs(grid, i, j, m, n, marked) + + return count + + def __dfs(self, grid, i, j, m, n, marked): + marked[i][j] = True + for direction in self.directions: + new_i = i + direction[0] + new_j = j + direction[1] + # 没有过界 没有遍历过 且是岛屿 + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + self.__dfs(grid, new_i, new_j, m, n, marked) + # 广度优先算法,围绕某个节点只深入一层 数组是待遍历的节点 + def numIslands(self,grid:List[List[str]]) -> int: + m = len(grid) + if m == 0: + return 0 + n=len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + # 从第 1 行、第 1 格开始,对每一格尝试进行一次 DFS 操作 + for i in range(m): + for j in range(n): + # 只要是陆地,且没有被访问过的,就可以使用 BFS 发现与之相连的陆地,并进行标记 + if not marked[i][j] and grid[i][j] == '1': + # count 可以理解为连通分量,你可以在广度优先遍历完成以后,再计数, + count += 1 + queue = deque() + queue.append((i, j)) + # 标记上已经访问过 + marked[i][j] = True + while queue: + cur_x, cur_y = queue.popleft() + # 得到 4 个方向的坐标 + for direction in self.directions: + new_i = cur_x + direction[0] + new_j = cur_y + direction[1] + # 如果不越界、没有被访问过、并且还要是陆地,我就继续放入队列,放入队列的同时,要记得标记已经访问过 + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + queue.append((new_i, new_j)) + # 在放入队列以后,要马上标记成已经访问过 + marked[new_i][new_j] = True + return count \ No newline at end of file diff --git a/Week 03/id_181/LeetCode_455_181.py b/Week 03/id_181/LeetCode_455_181.py new file mode 100644 index 000000000..187c957c0 --- /dev/null +++ b/Week 03/id_181/LeetCode_455_181.py @@ -0,0 +1,22 @@ +# g 是孩子 s 是饼干 +# 饼干代表的数值必须大于等于孩子需要 +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + g_length = len(g) + s_length = len(s) + if s_length == 0 or g_length == 0: + return 0 + g.sort() + s.sort() + + res = i = j= 0 + + while i < g_length and j < s_length: + if g[i] <= s[j]: + res += 1 + i += 1 + j += 1 + else: + j += 1 + + return res \ No newline at end of file diff --git a/Week 03/id_181/LeetCode_74_181.py b/Week 03/id_181/LeetCode_74_181.py new file mode 100644 index 000000000..a902405d3 --- /dev/null +++ b/Week 03/id_181/LeetCode_74_181.py @@ -0,0 +1,23 @@ +# 先判断在哪一行,然后二分查找该行 +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix or not matrix[0]: return False + + m, n = len(matrix), len((matrix[0])) + + # 从左下角开始遍历,判断target在哪一行 + while matrix[m - 1][0] > target and m > 1: + m -= 1 + + # 二分查找 + l, r = 0, n - 1 + while l <= r: + mid = l + math.floor((r-l) / 2) // 2 + tmp = matrix[m - 1][mid] + if tmp == target: + return True + elif tmp > target: + r = mid - 1 + else: + l = mid + 1 + return False \ No newline at end of file diff --git a/Week 03/id_181/LeetCode_860_181.py b/Week 03/id_181/LeetCode_860_181.py new file mode 100644 index 000000000..eacc4a46f --- /dev/null +++ b/Week 03/id_181/LeetCode_860_181.py @@ -0,0 +1,25 @@ +# [860. 柠檬水找零 - 力扣(LeetCode)](https://leetcode-cn.com/problems/lemonade-change/description/) +# 5 元时 获取一张 +# 10元时 需要减去一个5元,若有则减去,若没有则返回False +# 15... 可以10 + 5,或者 5*3 找零,数目满足则成功 +# 需要对 5 和 10 的数目保存,20不用是因为找零用不上 +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + five = ten = 0 + for bill in bills: + if bill == 5: + five +=1 + elif bill == 10: + if not five: + return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >=3: + five-=3 + else: + return False + return True \ No newline at end of file diff --git a/Week 03/id_196/LeetCode_122_196.py b/Week 03/id_196/LeetCode_122_196.py new file mode 100644 index 000000000..a2715705b --- /dev/null +++ b/Week 03/id_196/LeetCode_122_196.py @@ -0,0 +1,8 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i - 1] + if tmp > 0: profit += tmp + return profit + diff --git a/Week 03/id_196/LeetCode_126_196.py b/Week 03/id_196/LeetCode_126_196.py new file mode 100644 index 000000000..d33872eec --- /dev/null +++ b/Week 03/id_196/LeetCode_126_196.py @@ -0,0 +1,36 @@ +class Solution(object): + def findLadders(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: List[List[str]] + """ + + def backtrack(res, routine, path, endWord): + if len(routine[endWord]) == 0: + res.append([endWord] + path) + else: + for pre in routine[endWord]: + backtrack(res, routine, [endWord] + path, pre) + + lookup = set(wordList) | set([beginWord]) + res, cur, routine = [], set([beginWord]), {word: [] for word in lookup} + while cur and endWord not in cur: + next_queue = set() + for word in cur: + lookup.remove(word) + for word in cur: + for i in range(len(word)): + for j in range(97, 123): + tmp = word[:i] + chr(j) + word[i + 1:] + if tmp in lookup: + next_queue.add(tmp) + routine[tmp].append(word) + cur = next_queue + + if cur: + backtrack(res, routine, [], endWord) + return res + + diff --git a/Week 03/id_196/LeetCode_127_196.py b/Week 03/id_196/LeetCode_127_196.py new file mode 100644 index 000000000..cc8921f52 --- /dev/null +++ b/Week 03/id_196/LeetCode_127_196.py @@ -0,0 +1,25 @@ +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if endWord not in wordList: + return 0 + wordict = set(wordList) + s1 = {beginWord} + s2 = {endWord} + n = len(beginWord) + step = 0 + wordict.remove(endWord) + while s1 and s2: + step += 1 + if len(s1) > len(s2): s1, s2 = s2, s1 + s = set() + for word in s1: + nextword = [word[:i] + chr(j) + word[i + 1:] for j in range(97, 123) for i in range(n)] + for w in nextword: + if w in s2: + return step + 1 + if w not in wordict: continue + wordict.remove(w) + s.add(w) + s1 = s + return 0 + diff --git a/Week 03/id_196/LeetCode_33_196.py b/Week 03/id_196/LeetCode_33_196.py new file mode 100644 index 000000000..516305be9 --- /dev/null +++ b/Week 03/id_196/LeetCode_33_196.py @@ -0,0 +1,59 @@ +class Solution: + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + + def find_rotate_index(left, right): + if nums[left] < nums[right]: + return 0 + + while left <= right: + pivot = (left + right) // 2 + if nums[pivot] > nums[pivot + 1]: + return pivot + 1 + else: + if nums[pivot] < nums[left]: + right = pivot - 1 + else: + left = pivot + 1 + + def search(left, right): + """ + Binary search + """ + while left <= right: + pivot = (left + right) // 2 + if nums[pivot] == target: + return pivot + else: + if target < nums[pivot]: + right = pivot - 1 + else: + left = pivot + 1 + return -1 + + n = len(nums) + + if n == 0: + return -1 + if n == 1: + return 0 if nums[0] == target else -1 + + rotate_index = find_rotate_index(0, n - 1) + + # if target is the smallest element + if nums[rotate_index] == target: + return rotate_index + # if array is not rotated, search in the entire array + if rotate_index == 0: + return search(0, n - 1) + if target < nums[0]: + # search on the right side + return search(rotate_index, n - 1) + # search on the left side + return search(0, rotate_index) + + diff --git a/Week 03/id_196/LeetCode_74_196.py b/Week 03/id_196/LeetCode_74_196.py new file mode 100644 index 000000000..73a199e14 --- /dev/null +++ b/Week 03/id_196/LeetCode_74_196.py @@ -0,0 +1,22 @@ +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + m = len(matrix) + if m == 0: + return False + n = len(matrix[0]) + + # 二分查找 + left, right = 0, m * n - 1 + while left <= right: + pivot_idx = (left + right) // 2 + pivot_element = matrix[pivot_idx // n][pivot_idx % n] + if target == pivot_element: + return True + else: + if target < pivot_element: + right = pivot_idx - 1 + else: + left = pivot_idx + 1 + return False + + diff --git a/Week 03/id_196/LeetCode_860_196.py b/Week 03/id_196/LeetCode_860_196.py new file mode 100644 index 000000000..a85b72266 --- /dev/null +++ b/Week 03/id_196/LeetCode_860_196.py @@ -0,0 +1,20 @@ +class Solution(object): #aw + def lemonadeChange(self, bills): + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + diff --git a/Week 03/id_201/LeetCode_102_LevelOrder b/Week 03/id_201/LeetCode_102_LevelOrder new file mode 100644 index 000000000..7cf6431b8 --- /dev/null +++ b/Week 03/id_201/LeetCode_102_LevelOrder @@ -0,0 +1,94 @@ +//给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 +// +// 例如: +//给定二叉树: [3,9,20,null,null,15,7], +// +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// +// +// 返回其层次遍历结果: +// +// [ +// [3], +// [9,20], +// [15,7] +//] +// +// Related Topics 树 广度优先搜索 + + + +//leetcode submit region begin(Prohibit modification and deletion) + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Stack; + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + /** + * #1 BFS + * 时间复杂度为O(N) + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + ArrayList levelNodeValList = new ArrayList(); + LinkedList nodes = new LinkedList<>(); + nodes.add(root); + int size = 0, level = 0; + ArrayList subList; + TreeNode current; + while (!nodes.isEmpty()) { + subList = new ArrayList(); + size = nodes.size(); + while (size-- > 0) { + current = nodes.poll(); + subList.add(current.val); + if (current.left != null) + nodes.add(current.left); + if (current.right != null) + nodes.add(current.right); + } + levelNodeValList.add(subList); + } + return levelNodeValList; + } + + /** + * #2 DFS + * 时间复杂度为O(N) + * @param root + * @return + */ + public List> levelOrder1(TreeNode root) { + List> levelOrderList = new ArrayList>(); + travelNode(root, 0, levelOrderList); + return levelOrderList; + } + + public void travelNode(TreeNode current, Integer level, List> levelOrderList) { + if (current == null) + return; + if (levelOrderList.size() == level) { + levelOrderList.add((new ArrayList())); + } + levelOrderList.get(level).add(current.val); + + travelNode(current.left, level + 1, levelOrderList); + travelNode(current.right, level + 1, levelOrderList); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_126_LadderLength2 b/Week 03/id_201/LeetCode_126_LadderLength2 new file mode 100644 index 000000000..e69de29bb diff --git a/Week 03/id_201/LeetCode_127_LadderLength b/Week 03/id_201/LeetCode_127_LadderLength new file mode 100644 index 000000000..f17318461 --- /dev/null +++ b/Week 03/id_201/LeetCode_127_LadderLength @@ -0,0 +1,275 @@ +//给定两个单词(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 广度优先搜索 + + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public HashMap> commonStatusMap; + public HashMap> wordStatusMap; + /** + * 时间复杂度为O(nk) n:字典中单词的数量, k为word长度 + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength(String beginWord, String endWord, List wordList) { + //每次只能变换一个字母,且每次产生的中间字符串必定在字典中, + // 所以找从begin world开始和wordList, endWord的上一个状态也在字典里 + HashSet visitedWords = new HashSet(); + LinkedList beginMediums = new LinkedList(); + beginMediums.add(beginWord); + String currentStr; + int size, step = 1; + boolean haveEnd = false; + while (!beginMediums.isEmpty()) { + size = beginMediums.size(); + while (size-- > 0) { + currentStr = beginMediums.poll(); + if (currentStr.equals(endWord)) + return step; + for (String str: wordList) { + if (!visitedWords.contains(str) && canReachEnd(currentStr, str)) { + visitedWords.add(str); + beginMediums.add(str); + } + if (!haveEnd && str.equals(endWord)) { + haveEnd = true; + } + } + if (false == haveEnd) + return 0; + } + step++; + } + return 0; + } + + public boolean canReachEnd(String start, String end) { + char[] startChars = start.toCharArray(); + char[] endChars = end.toCharArray(); + int changeCount = 0; + for (int i = 0; i < startChars.length; i++) { + if (startChars[i] != endChars[i]) + changeCount++; + if (changeCount > 1) + break; + } + return changeCount == 1; + } + + public int ladderLength1(String beginWord, String endWord, List wordList) { + HashSet wordSets = new HashSet(); + LinkedList beginMediums = new LinkedList(); + char[] charList = new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'y', 'w', 'x', 'y', 'z'}; + int size, step = 1; + String changeStr; + char[] changeChars; + char oldChar; + beginMediums.add(beginWord); + for (String str: wordList) + wordSets.add(str); + while (!beginMediums.isEmpty()) { + size = beginMediums.size(); + while (size-- > 0) { + changeStr = beginMediums.poll(); + if (changeStr.equals(endWord)) + return step; + changeChars = changeStr.toCharArray(); + for (int i = 0; i < changeChars.length; i++) { + for (char j: charList) { + if (changeChars[i] == j) + continue; + oldChar = changeChars[i]; + changeChars[i] = j; + changeStr = String.valueOf(changeChars); + if (wordSets.contains(changeStr)) { + wordSets.remove(changeStr); + beginMediums.add(changeStr); + } + changeChars[i] = oldChar; + } + } + } + step++; + } + return 0; + } + + /** + * todo + * #3 单指针,通用状态预处理 + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength2(String beginWord, String endWord, List wordList) { + int len = beginWord.length(), step = 0; + HashMap> commonStatusMap = new HashMap<>(); + HashMap> wordStatusMap = new HashMap<>(); + Queue headQueue = new LinkedList(); + headQueue.add(beginWord); + + //pre handle of dictionary + for (String word: wordList) { + ArrayList wordStatus = getCommonStatus(word, len); + wordStatusMap.put(word, wordStatus); + for (String s: wordStatus) { + if (!commonStatusMap.containsKey(s)) { + commonStatusMap.put(s, new ArrayList()); + } + commonStatusMap.get(s).add(word); + } + } + wordStatusMap.put(beginWord, getCommonStatus(beginWord, len)); + + while (!headQueue.isEmpty()) { + int size = headQueue.size(); + step++; + while (size-- > 0) { + String currentStr = headQueue.poll(); + if (currentStr.equals(endWord)) + return step; + if (!wordStatusMap.containsKey(currentStr)) + continue; + for (String str: wordStatusMap.get(currentStr)) { + if (!commonStatusMap.containsKey(str)) + continue; + for (String nextStr: commonStatusMap.get(str)) + headQueue.add(nextStr); + commonStatusMap.remove(str); + } + wordStatusMap.remove(currentStr); + } + } + return 0; + } + + public ArrayList getCommonStatus(String word, int length) { + ArrayList commonStatus = new ArrayList(); + char[] wordChar = word.toCharArray(); + char oldChar; + for (int i = 0; i < length; i++) { + oldChar = wordChar[i]; + wordChar[i] = '*'; + commonStatus.add(String.valueOf(wordChar)); + wordChar[i] = oldChar; + } + return commonStatus; + } + + /** + * #4 双指针 (head point and tail point) + * 时间复杂度为O(NK),实际时间比较小,双直针会在中间相遇 + * (原来的搜索是金字塔形,越往下层基数越大,指数型增长) + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength3(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + commonStatusMap = new HashMap<>(); + wordStatusMap = new HashMap<>(); + Queue> headQueue = new LinkedList(); + Queue> tailQueue = new LinkedList(); + HashMap headVisited = new HashMap(); + HashMap tailVisited = new HashMap(); + headQueue.add(new Pair(beginWord, 1)); + tailQueue.add(new Pair(endWord, 1)); + + //pre handle of dictionary + int len = beginWord.length(), vistedStep; + for (String word: wordList) { + ArrayList wordStatus = getCommonStatus(word, len); + wordStatusMap.put(word, wordStatus); + for (String s: wordStatus) { + if (!commonStatusMap.containsKey(s)) { + commonStatusMap.put(s, new ArrayList()); + } + commonStatusMap.get(s).add(word); + } + } + wordStatusMap.put(beginWord, getCommonStatus(beginWord, len)); + + while (!headQueue.isEmpty() && !tailQueue.isEmpty()) { + vistedStep = visitWord(headQueue, headVisited, tailVisited); + if (vistedStep > 0) { + return vistedStep; + } + vistedStep = visitWord(tailQueue, tailVisited, headVisited); + if (vistedStep > 0) { + return vistedStep; + } + } + return 0; + } + + public int visitWord(Queue> q, HashMap visitedMap, HashMap compareMap) { + Pair wordNode = q.poll(); + String word = wordNode.getKey(); + if (compareMap.containsKey(word)) { + return wordNode.getValue() + compareMap.get(word) -1; + } + for (String s: wordStatusMap.get(word)) { + if (!commonStatusMap.containsKey(s)) + continue; + for (String s1: commonStatusMap.get(s)) { + if (!visitedMap.containsKey(s1)) { + q.add(new Pair(s1, wordNode.getValue() + 1)); + visitedMap.put(s1, wordNode.getValue() + 1); + } + } + } + return 0; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_200_NumIslands b/Week 03/id_201/LeetCode_200_NumIslands new file mode 100644 index 000000000..e0c7306bc --- /dev/null +++ b/Week 03/id_201/LeetCode_200_NumIslands @@ -0,0 +1,212 @@ +//给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 +// +// 示例 1: +// +// 输入: +//11110 +//11010 +//11000 +//00000 +// +//输出: 1 +// +// +// 示例 2: +// +// 输入: +//11000 +//11000 +//00100 +//00011 +// +//输出: 3 +// +// Related Topics 深度优先搜索 广度优先搜索 并查集 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + /** + * #1 时间复杂度为O(M * N) M, n : 分别为横纵坐标最大值 + * DFS + * @param grid + * @return + */ + public int numIslands(char[][] grid) { + int length = grid.length; + if (length == 0) { + return 0; + } + int rowLength = grid[0].length; + int count = 0; + int[][] visitedGrid = new int[length][rowLength]; + for (int i = 0; i < length; i++) { + for (int j = 0; j < rowLength; j++) { + if (grid[i][j] == '1') { + visitGrid(i, j, visitedGrid, grid); + count++; + } + } + } + return count; + } + + + public void visitGrid(int i, int j, int[][] visitedGrid, char[][] grid) { + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || visitedGrid[i][j] == 1 || grid[i][j] == '0') + return; + grid[i][j] = '0'; + visitedGrid[i][j] = 1; + visitGrid(i + 1, j, visitedGrid, grid); + visitGrid(i, j + 1, visitedGrid, grid); + visitGrid(i - 1, j, visitedGrid, grid); + visitGrid(i, j - 1, visitedGrid, grid); + } + + /** + * #2 improvement of #1, the visitedgrid 比较多余 + * @param grid + * @return + */ + public int numIslands1(char[][] grid) { + if (grid.length == 0) { + return 0; + } + int count = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + visitGrid(i, j, grid); + count++; + } + } + } + return count; + } + + public void visitGrid1(int i, int j, char[][] grid) { + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') + return; + grid[i][j] = '0'; + visitGrid(i + 1, j, grid); + visitGrid(i, j + 1, grid); + visitGrid(i - 1, j, grid); + visitGrid(i, j - 1, grid); + } + + /** + * #3 + * BFS use Queue + * 时间复杂度为O(m*n) + * 空间复杂度为O(min(m, n)) + * @param grid + * @return + */ + public int numIslands2(char[][] grid) { + int count = 0; + if (grid.length == 0) + return count; + Queue> islandPoint = new LinkedList>(); + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + count++; + islandPoint.add(new Pair(i, j)); + while (!islandPoint.isEmpty()) { + Pair point = islandPoint.poll(); + int nr = point.getKey(), nc = point.getValue(); + if (nr > 0 && grid[nr - 1][nc] == '1') { + islandPoint.add(new Pair(nr - 1, nc)); + grid[nr - 1][nc] = '0'; + } + + if (nr + 1 < grid.length && grid[nr + 1][nc] == '1') { + islandPoint.add(new Pair(nr + 1, nc)); + grid[nr + 1][nc] = '0'; + } + + if (nc > 0 && grid[nr][nc - 1] == '1') { + islandPoint.add(new Pair(nr, nc - 1)); + grid[nr][nc - 1] = '0'; + } + + if (nc + 1 < grid[0].length && grid[nr][nc + 1] == '1') { + islandPoint.add(new Pair(nr, nc + 1)); + grid[nr][nc + 1] = '0'; + } + } + } + } + } + return count; + } + + class UnionFind { + int[] father; + int m, n; + int count = 0; + UnionFind(char[][] grid) { + m = grid.length; + n = grid[0].length; + father = new int[m*n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + int id = i * n + j; + father[id] = id; + count++; + } + } + } + } + public void union(int node1, int node2) { + int find1 = find(node1); + int find2 = find(node2); + if(find1 != find2) { + father[find1] = find2; + count--; + } + } + public int find (int node) { + if (father[node] == node) { + return node; + } + father[node] = find(father[node]); + return father[node]; + } + } + + int[][] distance = {{1,0},{-1,0},{0,1},{0,-1}}; + + /** + * union ann todo + * @param grid + * @return + */ + public int numIslands3(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + UnionFind uf = new UnionFind(grid); + int rows = grid.length; + int cols = grid[0].length; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == '1') { + for (int[] d : distance) { + int x = i + d[0]; + int y = j + d[1]; + if (x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] == '1') { + int id1 = i*cols+j; + int id2 = x*cols+y; + uf.union(id1, id2); + } + } + } + } + } + return uf.count; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_22_generateParenthesis b/Week 03/id_201/LeetCode_22_generateParenthesis new file mode 100644 index 000000000..e69de29bb diff --git a/Week 03/id_201/LeetCode_33_search b/Week 03/id_201/LeetCode_33_search new file mode 100644 index 000000000..ee3f80f3e --- /dev/null +++ b/Week 03/id_201/LeetCode_33_search @@ -0,0 +1,40 @@ +class Solution { + /** + * 时间复杂度为O(logn) + * @param nums + * @param target + * @return + */ + public int search(int[] nums, int target) { + int left = 0, right = nums.length - 1, middle; + while (left <= right) { + middle = left + (right - left) / 2; + if (nums[middle] == target) + return middle; + if (nums[middle] < nums[left]) { + if (nums[middle] < target && target <= nums[right]) { + left = middle + 1; + } else { + right = middle - 1; + } + } else if (nums[middle] > target && target >= nums[left]) { + right = middle - 1; + } else { + left = middle + 1; + } + } + return -1; + } + + /** + * todo ann + * 更简洁的写法 (TODO ANN 2 正负无穷) + * @param nums + * @param target + * @return + */ + public int search1(int[] nums, int target) { + + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_201/LeetCode_367_perfectSquare b/Week 03/id_201/LeetCode_367_perfectSquare new file mode 100644 index 000000000..3e641face --- /dev/null +++ b/Week 03/id_201/LeetCode_367_perfectSquare @@ -0,0 +1,70 @@ +//给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。 +// +// 说明:不要使用任何内置的库函数,如 sqrt。 +// +// 示例 1: +// +// 输入:16 +//输出:True +// +// 示例 2: +// +// 输入:14 +//输出:False +// +// Related Topics 数学 二分查找 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + /** + * 时间复杂度为O(LOGN) + * @param num + * @return + */ + public boolean isPerfectSquare(int num) { + int left = 0, right = num, middle, result; + while (left <= right) { + middle = left + (right - left) / 2; + result = middle * middle; + if (result > num) { + right = middle - 1; + } else if (result < num){ + left = middle + 1; + } else { + return true; + } + } + return false; + } + + /** + * 牛顿迭代法 + * @param num + * @return + */ + public boolean isPerfectSquare1(int num) { + if (num == 1) + return true; + long i = num >> 1; + while (i * i > num) { + i = (i + num / i) >> 1; + } + return i * i == num; + } + + /** + * 奇数 等差数列求和 + * @param num + * @return + */ + public boolean isPerfectSquare2(int num) { + int i = 1; + while (i < num) { + i = 2 * i + 2; + } + return i == num; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_433_MinMutation b/Week 03/id_201/LeetCode_433_MinMutation new file mode 100644 index 000000000..bc0f53d56 --- /dev/null +++ b/Week 03/id_201/LeetCode_433_MinMutation @@ -0,0 +1,114 @@ +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + /** + * #1 + * @param start + * @param end + * @param bank + * @return + */ + public int minMutation(String start, String end, String[] bank) { + if (start.length() != end.length()) + return 0; + HashSet bankSet = new HashSet(); + char[] startChars, replaceChars = new char[]{'A', 'C', 'G', 'T'}; + Queue possibleStr = new LinkedList<>(); + HashSet visitedSet = new HashSet(); + char diffChar; + int step = 0, size; + String currentStart; + possibleStr.offer(start); + // put element in bank to set + for (String s : bank) + bankSet.add(s); + while (!possibleStr.isEmpty()) { + size = possibleStr.size(); + while (size-- > 0) { + currentStart = possibleStr.poll(); + if (currentStart.equals(end)) + return step; + startChars = currentStart.toCharArray(); + for (int i = 0; i < startChars.length; i++) { + diffChar = startChars[i]; + for (int j = 0; j < replaceChars.length; j++) { + if (replaceChars[j] == startChars[i]) + continue; + startChars[i] = replaceChars[j]; + currentStart = String.valueOf(startChars); + if (!visitedSet.contains(currentStart) && bankSet.contains(currentStart)) { + visitedSet.add(currentStart); + possibleStr.offer(currentStart); + } + } + startChars[i] = diffChar; + } + } + step++; + } + return -1; + } + + /** + * #2 improvememt of #1 + * @param start + * @param end + * @param bank + * @return + */ + public int minMutation1(String start, String end, String[] bank) { + if (start.length() != end.length()) + return 0; + HashSet bankSet = new HashSet(); + char[] startChars, replaceChars = new char[]{'A', 'C', 'G', 'T'}; + Queue possibleStr = new LinkedList<>(); + char diffChar; + int step = 0, size; + String currentStart; + possibleStr.offer(start); + // put element in bank to set + for (String s : bank) + bankSet.add(s); + while (!possibleStr.isEmpty()) { + size = possibleStr.size(); + while (size-- > 0) { + currentStart = possibleStr.poll(); + if (currentStart.equals(end)) + return step; + startChars = currentStart.toCharArray(); + for (int i = 0; i < startChars.length; i++) { + diffChar = startChars[i]; + for (int j = 0; j < replaceChars.length; j++) { + if (replaceChars[j] == startChars[i]) + continue; + startChars[i] = replaceChars[j]; + currentStart = String.valueOf(startChars); + if (bankSet.contains(currentStart)) { + bankSet.remove(currentStart); + possibleStr.offer(currentStart); + } + } + startChars[i] = diffChar; + } + } + step++; + } + return -1; + } + + /** + * because bank is small 参考127 ladderLength + * @param start + * @param end + * @param bank + * @return + */ + public int minMutation2(String start, String end, String[] bank) { + return -1; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_45_jump2 b/Week 03/id_201/LeetCode_45_jump2 new file mode 100644 index 000000000..3a961a885 --- /dev/null +++ b/Week 03/id_201/LeetCode_45_jump2 @@ -0,0 +1,57 @@ +//给定一个非负整数数组,你最初位于数组的第一个位置。 +// +// 数组中的每个元素代表你在该位置可以跳跃的最大长度。 +// +// 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 +// +// 示例: +// +// 输入: [2,3,1,1,4] +//输出: 2 +//解释: 跳到最后一个位置的最小跳跃数是 2。 +//  从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 +// +// +// 说明: +// +// 假设你总是可以到达数组的最后一个位置。 +// Related Topics 贪心算法 数组 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int jump(int[] nums) { + rif (nums.length == 1) + return 0; + return jumpRoad(0, 1, Integer.MAX_VALUE, nums); + } + + public int jumpRoad(int index, int count, int maxNum, int[] nums) { + int step; + for (int i = nums[index] + index; i > index; i--) { + if (i >= nums.length - 1) { + return count; + } + step = jumpRoad(i, count + 1, maxNum, nums); + if (step < maxNum) { + maxNum = step; + } + } + + public int jump1(int[] nums) { + return jumpNum(nums[0], nums, 1); + } + + public int jumpNum(int maxReachIndex, int[] nums, int step) { + if (maxReachIndex >= nums.length - 1) + return step; + for (int i = current + 1; i < maxReachIndex; i++) { + if (nums[i] + i > maxReachIndex + nums[maxReachIndex]) { + maxReachIndex = nums[i] + i; + } + } + return jumpNum(maxReachIndex, nums, step++); + } + } +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_515_largestValues.java b/Week 03/id_201/LeetCode_515_largestValues.java new file mode 100644 index 000000000..020a2b40f --- /dev/null +++ b/Week 03/id_201/LeetCode_515_largestValues.java @@ -0,0 +1,95 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + /** + * #1 + * @param root + * @return + */ + public List largestValues(TreeNode root) { + int level = 0; + boolean preNodeNull = true; + ArrayList maxNums = new ArrayList(); + travelNode(root, maxNums, level); + return maxNums; + } + + public void travelNode(TreeNode current, ArrayList maxNums, int level) { + if (current == null) + return; + if (maxNums.size() <= level) { + maxNums.add(current.val); + } else if (current.val > maxNums.get(level)) { + maxNums.set(level, current.val); + } + travelNode(current.left, maxNums, level + 1); + travelNode(current.right, maxNums, level + 1); + } + + public List largestValues1(TreeNode root) { + int maxNum = 0; + boolean preNodeNull = true; + ArrayList maxNums = new ArrayList(); + Queue nodes = new LinkedList(); + TreeNode current; + nodes.add(root); + nodes.add(null); + while (true) { + current = nodes.poll(); + if (current == null) { + if (preNodeNull) { + break; + } + maxNums.add(maxNum); + nodes.add(null); + preNodeNull = true; + continue; + } + if (preNodeNull) { + preNodeNull = false; + maxNum = current.val; + } else if (current.val > maxNum) { + maxNum = current.val; + } + if (current.left != null) { + nodes.add(current.left); + } + if (current.right != null) { + nodes.add(current.right); + } + } + return maxNums; + } + + public List largestValues2(TreeNode root) { + int maxNum, size = 0; + TreeNode current; + ArrayList maxNums = new ArrayList(); + if (root == null) + return maxNums; + Queue nodes = new LinkedList<>(); + nodes.add(root); + while (!nodes.isEmpty()) { + size = nodes.size(); + maxNum = Integer.MIN_VALUE; + while (size-- > 0) { + current = nodes.poll(); + if (current.val > maxNum) + maxNum = current.val; + if (current.left != null) + nodes.add(current.left); + if (current.right != null) + nodes.add(current.right); + } + maxNums.add(maxNum); + } + return maxNums; + } +} \ No newline at end of file diff --git a/Week 03/id_201/LeetCode_529_UpdateBoard b/Week 03/id_201/LeetCode_529_UpdateBoard new file mode 100644 index 000000000..e69de29bb diff --git a/Week 03/id_201/LeetCode_69_mySqrt b/Week 03/id_201/LeetCode_69_mySqrt new file mode 100644 index 000000000..297a58c66 --- /dev/null +++ b/Week 03/id_201/LeetCode_69_mySqrt @@ -0,0 +1,35 @@ +//实现 int sqrt(int x) 函数。 +// +// 计算并返回 x 的平方根,其中 x 是非负整数。 +// +// 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 +// +// 示例 1: +// +// 输入: 4 +//输出: 2 +// +// +// 示例 2: +// +// 输入: 8 +//输出: 2 +//说明: 8 的平方根是 2.82842..., +//  由于返回类型是整数,小数部分将被舍去。 +// +// Related Topics 数学 二分查找 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int mySqrt(int x) { + long i = x; + while (true) { + i = (i + x / i) >> 1; + if (i * i - x < 0.001) + return (int) i; + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_201/LeetCode_74_searchMatrix b/Week 03/id_201/LeetCode_74_searchMatrix new file mode 100644 index 000000000..41338699d --- /dev/null +++ b/Week 03/id_201/LeetCode_74_searchMatrix @@ -0,0 +1,75 @@ +//编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: +// +// +// 每行中的整数从左到右按升序排列。 +// 每行的第一个整数大于前一行的最后一个整数。 +// +// +// 示例 1: +// +// 输入: +//matrix = [ +// [1, 3, 5, 7], +// [10, 11, 16, 20], +// [23, 30, 34, 50] +//] +//target = 3 +//输出: true +// +// +// 示例 2: +// +// 输入: +//matrix = [ +// [1, 3, 5, 7], +// [10, 11, 16, 20], +// [23, 30, 34, 50] +//] +//target = 13 +//输出: false +// Related Topics 数组 二分查找 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + /** + * 时间复杂度为O(LOGM + LOGN) + * M: 矩阵的长度 N :矩阵的列数 + * @param matrix + * @param target + * @return + */ + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0 || matrix[0].length == 0) + return false; + int left = 0, right = matrix.length - 1, middle, n = matrix[0].length - 1; + while (left <= right) { + middle = left + (right - left) / 2; + if (target > matrix[middle][n]) { + left = middle + 1; + } else if (target < matrix[middle][0]) { + right = middle - 1; + } else { + return search(matrix[middle], target); + } + } + return false; + } + + public boolean search(int[] nums, int target) { + int left = 0, right = nums.length - 1, middle; + while (left <= right) { + middle = left + (right - left) / 2; + if (nums[middle] == target) + return true; + if (nums[middle] > target) { + right = middle - 1; + } else { + left = middle + 1; + } + } + return false; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_216/Week03.java b/Week 03/id_216/Week03.java new file mode 100644 index 000000000..7a8beb668 --- /dev/null +++ b/Week 03/id_216/Week03.java @@ -0,0 +1,122 @@ +import java.util.*; + +/** + * Created by liuyp on 2019/11/3. + */ +public class Week03 { + + //127 + public class Pair { + private String key; + private Integer val; + + public Pair(String key, Integer val) { + this.key = key; + this.val = val; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Integer getVal() { + return val; + } + + public void setVal(Integer val) { + this.val = val; + } + } + + public int ladderLength(String beginWord, String endWord, List wordList) { +// + List visited = new ArrayList<>(); + + int len = beginWord.length(); + + Map> base = new HashMap<>(); + for (String word : wordList) { + + for (int i = 0; i < len; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, len); + List list = base.getOrDefault(newWord, new ArrayList()); + list.add(word); + base.put(newWord, list); + } + } + + Queue queue = new LinkedList<>(); + queue.add(new Pair(beginWord, 1)); + visited.add(beginWord); + + while (queue.size() > 0) { + Pair pair = queue.poll(); + visited.add(String.valueOf(pair.getKey())); + String curWord = String.valueOf(pair.getKey()); + int level = pair.getVal(); + for (int i = 0; i < len; i++) { + String keyWord = curWord.substring(0, i) + '*' + curWord.substring(i + 1, len); + List baseList = base.getOrDefault(keyWord, new ArrayList<>()); + for (String baseWord : baseList) { + if (baseWord.equals(endWord)) { + return level + 1; + } + if (!visited.contains(baseWord)) { + queue.add(new Pair(baseWord, level + 1)); + } + } + } + } + + return 0; + } + + //33 + public int search1(int[] nums, int target) { + int mid = 0; + int left = 0; + int right = nums.length - 1; + while (left <= right) { + mid = (left + right) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] > nums[right]) { + left = mid + 1; + } else if (nums[mid] < nums[left]) { + right = mid - 1; + } else { + right = mid - 1; + } + } + + return -1; + } + + public int search2(int[] nums, int target) { + + int left = 0; + int right = nums.length - 1; + while (left < right) { + System.out.println("left=====" + left); + System.out.println("right=====" + right); + + int mid = (left + right) / 2; + System.out.println("mid=====" + mid); + System.out.println("============================"); + + if (nums[mid] == target) { + return mid; + } else if ((nums[0] > target) && (nums[0] > nums[mid]) && (target > nums[mid])) { + left = mid + 1; + } else { + right = mid; + } + } + + return -1; + } +} diff --git a/Week 03/id_241/LeetCode_122_241.java b/Week 03/id_241/LeetCode_122_241.java new file mode 100644 index 000000000..849b2c521 --- /dev/null +++ b/Week 03/id_241/LeetCode_122_241.java @@ -0,0 +1,12 @@ +import java.util.*; +/** + * 买卖股票的最佳时机 II + */ +public class Solution { + public int maxProfit(int[] prices) { + int sum = 0; + for (int i = 1; i < prices.length; i++) + if (prices[i] > prices[i - 1]) sum += prices[i] - prices[i - 1]; + return sum; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_153_241.java b/Week 03/id_241/LeetCode_153_241.java new file mode 100644 index 000000000..7e847befb --- /dev/null +++ b/Week 03/id_241/LeetCode_153_241.java @@ -0,0 +1,23 @@ +import java.util.*; +/** + * 寻找旋转排序数组中的最小值 + */ +public class Solution { + /** + * 寻找旋转排序数组中的最小值 + */ + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while (left < right) { + if (left + 1 == right) { + if (nums[right] > nums[left]) return nums[left]; + break; + } + int mid = (left + right) >> 1; + if (nums[mid] < nums[right]) right = mid; + else left = mid; + } + return nums[right]; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_200_241.java b/Week 03/id_241/LeetCode_200_241.java new file mode 100644 index 000000000..8a59320ae --- /dev/null +++ b/Week 03/id_241/LeetCode_200_241.java @@ -0,0 +1,65 @@ +import java.util.*; +/** + * 岛屿数量 + */ +public class Solution { + /** + * 岛屿数量(2ms) + */ + private char[][] grid; + + public int numIslands(char[][] grid) { + int sum = 0; + this.grid = grid; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + numIslandsHelper(i, j); + sum++; + } + } + } + return sum; + } + + private void numIslandsHelper(int i, int j) { + if (i < 0 || i >= grid.length || j < 0 || j >= grid[i].length || grid[i][j] == '0') + return; + if (grid[i][j] == '1') + grid[i][j] = '0'; + numIslandsHelper(i + 1, j); + numIslandsHelper(i - 1, j); + numIslandsHelper(i, j + 1); + numIslandsHelper(i, j - 1); + } + + /** + * 岛屿数量(3ms) + */ + private int[] dx = new int[]{-1, 1, 0, 0}; + private int[] dy = new int[]{0, 0, -1, 1}; + + public int numIslands2(char[][] grid) { + int sum = 0; + this.grid = grid; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + numIslandsHelper2(i, j); + sum++; + } + } + } + return sum; + } + + private void numIslandsHelper2(int i, int j) { + if (grid[i][j] == '1') grid[i][j] = '0'; + else return; + for (int k = 0; k < dx.length; k++) { + int x = i + dx[k], y = j + dy[k]; + if (x < 0 || x >= grid.length || y < 0 || y >= grid[x].length || grid[x][y] == '0') continue; + numIslandsHelper2(x, y); + } + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_33_241.java b/Week 03/id_241/LeetCode_33_241.java new file mode 100644 index 000000000..802149c36 --- /dev/null +++ b/Week 03/id_241/LeetCode_33_241.java @@ -0,0 +1,52 @@ +import java.util.*; +/** + * 搜索旋转排序数组 + */ +public class Solution { + /** + * 搜索旋转排序数组 + * (0ms) + */ + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) return -1; + int left = 0; + int right = nums.length - 1; + while (left < right) { + int mid = (left + right) >> 1; + if (nums[mid] == target) return mid; + if (nums[left] <= nums[mid]) { + if (target >= nums[left] && target <= nums[mid]) + right = mid - 1; + else + left = mid + 1; + } else { + if (target >= nums[mid] && target <= nums[right]) + left = mid + 1; + else + right = mid - 1; + } + } + return nums[left] == target ? left : -1; + } + + /** + * 搜索旋转排序数组 + * (将上面的判断精简一下) + * (1ms) + */ + private int search2(int[] nums, int target) { + if (nums == null || nums.length == 0) return -1; + int left = 0; + int right = nums.length - 1; + while (left < right) { + int mid = (left + right) >> 1; + if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) + left = mid + 1; + else if (target > nums[mid] && target < nums[0]) + left = mid + 1; + else + right = mid; + } + return nums[left] == target ? left : -1; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_455_241.java b/Week 03/id_241/LeetCode_455_241.java new file mode 100644 index 000000000..df43fb0b6 --- /dev/null +++ b/Week 03/id_241/LeetCode_455_241.java @@ -0,0 +1,40 @@ +import java.util.*; +/** + * 分发饼干 + */ +public class Solution { + /** + * 分发饼干 + */ + public int findContentChildren(int[] g, int[] s) { + int sum = 0; + Arrays.sort(g); + Arrays.sort(s); + for (int i = s.length - 1, j = g.length - 1; i >= 0 && j >= 0; ) { + if (s[i] >= g[j]) { + sum++; + i--; + } + j--; + } + return sum; + } + + /** + * 分发饼干 + * (改进版) + */ + public int findContentChildren2(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int i = 0; + int j = 0; + while (i < g.length && j < s.length) { + if (g[i] <= s[j]) { + i++; + } + j++; + } + return i; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_529_241.java b/Week 03/id_241/LeetCode_529_241.java new file mode 100644 index 000000000..6b1494628 --- /dev/null +++ b/Week 03/id_241/LeetCode_529_241.java @@ -0,0 +1,53 @@ +import java.util.*; +/** + * 扫雷游戏 + */ +public class Solution { + /** + * 扫雷游戏 + */ + public char[][] updateBoard(char[][] board, int[] click) { + if (board[click[0]][click[1]] == 'M') { + board[click[0]][click[1]] = 'X'; + return board; + } + return updateBoardHelper(board, click[0], click[1]); + } + + private char[][] updateBoardHelper(char[][] board, int x, int y) { + //如果一开始点击是雷,则退出游戏 + int nums = getNums(board, x, y); + if (nums == 0) + board[x][y] = 'B'; + else { + //forDigit函数,将第一个参数转为字符。radix 有效值为 2~36.nums 小于 10 则为数字字符,否则为'a' + nums - 10,也就是 26 个小写英文字母 + board[x][y] = Character.forDigit(nums, 10); + //退出时因为,题目要求无需遍历所有点,遇到雷即可。 + return board; + } + //只遍历周围八个点中为 E 的点。 + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (x + i < 0 || x + i > board.length - 1 || y + j < 0 || y + j > board[0].length - 1 || board[x + i][y + j] != 'E') + continue; + board = updateBoardHelper(board, x + i, y + j); + } + } + return board; + } + + /* + 计算当前点周围八个点雷的数量 + */ + private int getNums(char[][] board, int x, int y) { + int num = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (x + i < 0 || x + i > board.length - 1 || y + j < 0 || y + j > board[0].length - 1 || board[x + i][y + j] != 'M') + continue; + num++; + } + } + return num; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_55_241.java b/Week 03/id_241/LeetCode_55_241.java new file mode 100644 index 000000000..08cc623e4 --- /dev/null +++ b/Week 03/id_241/LeetCode_55_241.java @@ -0,0 +1,12 @@ +import java.util.*; +/** + * 跳跃游戏 + */ +public class Solution { + public boolean canJump(int[] nums) { + int endIndex = nums.length - 1; + for (int i = endIndex - 1; i >= 0; i--) + if (nums[i] >= (endIndex - i)) endIndex = i; + return endIndex == 0; + } +} \ No newline at end of file diff --git a/Week 03/id_241/LeetCode_74_241.java b/Week 03/id_241/LeetCode_74_241.java new file mode 100644 index 000000000..316fbe7c1 --- /dev/null +++ b/Week 03/id_241/LeetCode_74_241.java @@ -0,0 +1,29 @@ +import java.util.*; +/** + * 搜索二维矩阵 + */ +public class Solution { + /** + * 搜索二维矩阵 + */ + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0 || matrix[0].length == 0) return false; + for (int[] ints : matrix) { + if (target >= ints[0] && target <= ints[ints.length - 1]) { + int left = 0; + int right = ints.length - 1; + while (left <= right) { + int mid = (left + right) >> 1; + if (ints[mid] == target) + return true; + if (ints[mid] < target) + left = mid + 1; + else + right = mid - 1; + } + break; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_122_246.py b/Week 03/id_246/LeetCode_122_246.py new file mode 100644 index 000000000..62ab63d84 --- /dev/null +++ b/Week 03/id_246/LeetCode_122_246.py @@ -0,0 +1,25 @@ +''' +best-time-to-buy-and-sell-stock-ii_122 + +给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + +示例: +输入: [7,1,5,3,6,4] +输出: 7 +''' + +def maxProfit(prices): + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i-1] + if tmp > 0: profit += tmp + return profit + + +#优化 +def maxProfit_2(prices): + return sum(max(prices[i+1]-prices[i], 0) for i in range(len(prices) - 1)) \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_126_246.py b/Week 03/id_246/LeetCode_126_246.py new file mode 100644 index 000000000..cae33a480 --- /dev/null +++ b/Week 03/id_246/LeetCode_126_246.py @@ -0,0 +1,90 @@ +''' +word-ladder_126 + +给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则: + +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 +说明: + +如果不存在这样的转换序列,返回一个空列表。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +示例 1: + +输入: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +输出: +[ + ["hit","hot","dot","dog","cog"], +  ["hit","hot","lot","log","cog"] +] +''' + +#bfs + dfs +from collections import defaultdict + +def findLadders_1(beginWord, endWord, wordList): + neighbors = defaultdict(list) + for w in wordList: + for i in range(len(w)): + placeholder = w[:i] + '_' + w[i+1:] + neighbors[placeholder] += w + + #bfs + tree = defaultdict(set) + cur_layer = {beginWord} + + while cur_layer and not endWord in cur_layer: + next_layer = defaultdict(set) + for word in cur_layer: + for i in range(len(word)): + placeholder = word[:i] + '_' + word[i+1:] + for neigh in neighbors[placeholder]: + if not neigh in tree: + next_layer[neigh].add(word) + tree.update(next_layer) + cur_layer = next_layer + + #dfs + def dfs(source, dest): + if source == dest: + return [[source]] + return [pre_path + [dest] for parent in tree[dest] for pre_path in dfs(source, parent)] + + return dfs(beginWord,endWord) + + + # 优化 +from collections import defaultdict + +def findLadders_2(beginWord, endWord, wordList): + if endWord not in wordList: return [] + forword, backword, wordList, dic = {beginWord}, {endWord}, set(wordList), defaultdict(set) + flag, letters, length = True, set('qwertyuioplkjhgfdsazxcvbnm'), len(endWord) + while forword: + if len(forword) > len(backword): + forword, backword, flag = backword, forword, not flag + cur = set() + wordList -= forword + for word in forword: + for idx in range(length): + x,y = word[:idx], word[idx+1:] + for letter in letters: + temp = x + letter + y + if temp in wordList: + cur.add(temp) + if flag: dic[temp].add(word) + else: dic[word].add(temp) + if cur&backword: + res = [[endWord]] + while res[0][0] != beginWord: + res = [[x]+y for y in res for x in dic[y[0]]] + return res + forword = cur + return [] \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_127_246.py b/Week 03/id_246/LeetCode_127_246.py new file mode 100644 index 000000000..e704c724c --- /dev/null +++ b/Week 03/id_246/LeetCode_127_246.py @@ -0,0 +1,55 @@ +''' +word-ladder_127 + +给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 +说明: + +如果不存在这样的转换序列,返回 0。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + +示例: +输入: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +输出: 5 + +解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", + 返回它的长度 5。 +''' + +#bfs + +from collections import defaultdict + +def ladderLength(beginWord, endWord, wordList): + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + L = len(beginWord) + + all_combo_dict = defaultdict(list) + for word in wordList: + for i in range(L): + all_combo_dict[word[:i]+"*"+word[i+1:]].append(word) + + queue = [(beginWord,1)] + visited = {beginWord:True} + while queue: + current_word, level = queue.pop(0) + for i in range(L): + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + for word in all_combo_dict[intermediate_word]: + if word == endWord: + return level+1 + if word not in visited: + visited[word] = True + queue.append((word, level+1)) + all_combo_dict[intermediate_word] = [] + return 0 \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_153_246.py b/Week 03/id_246/LeetCode_153_246.py new file mode 100644 index 000000000..8cfd43e92 --- /dev/null +++ b/Week 03/id_246/LeetCode_153_246.py @@ -0,0 +1,34 @@ +''' +find-minimum-in-rotated-sorted-array_153 + +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + +( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + +请找出其中最小的元素。 + +你可以假设数组中不存在重复元素。 + +示例 1: + +输入: [3,4,5,1,2] +输出: 1 +''' + +def findMin(nums): + l, r = 0, len(nums)-1 + + # 找旋转点 + # 1. 如果某半边数组仍为旋转数组(头元素大于尾元素),则最小值在这半边; + # 2. 如果两半边数组均为有序数组,则最小值为左半边数组的头元素。 + while l < r: + m = (l+r)//2 + if nums[l] >= nums[m] >= nums[r]: #完全逆序 + return nums[r] + elif nums[m] > nums[r]: # 后半边旋转,前半边有序 + l = m+1 + elif nums[l] > nums[m]: # 前半边旋转,后半边有序 + r = m # 没有减1是为了考虑当前元素就是旋转点的情况 + else: # 完全有序(nums[l] < nums[mid] < nums[r]) + return nums[l] + return nums[l] \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_200_246.py b/Week 03/id_246/LeetCode_200_246.py new file mode 100644 index 000000000..ad0e071be --- /dev/null +++ b/Week 03/id_246/LeetCode_200_246.py @@ -0,0 +1,104 @@ +''' +number of islands_200 + +给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + +示例 1: +输入: +11110 +11010 +11000 +00000 + +输出: 1 + +示例 2: +输入: +11000 +11000 +00100 +00011 + +输出: 3 +''' + +#dfs + +from typing import List + +class Solution: + directions = [(-1,0), (0,-1), (1,0), (0,1)] + + def numIslands(self, grid): + m = len(grid) + if m == 0: return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + + for i in range(m): + for j in range(n): + if not marked[i][j] and grid[i][j] == '1': + count += 1 + self.__dfs(grid, i, j, m, n, marked) + return count + + def __dfs(self,grid, i, j, m, n, marked): + marked[i][j] = True + for directions in self.directions: + new_i = i + directions[0] + new_j = j + directions[1] + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + self.__dfs(grid, new_i, new_j, m, n, marked) + +grid = [['1', '1', '1', '0', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '1']] + +solution = Solution() +result = solution.numIslands(grid) +print(result) + + +#bfs +from typing import List +from collections import deque + +class Solution: + directions = [(-1,0), (0,-1), (1,0), (0,1)] + + def numIslands(self, grid): + m = len(grid) + if m == 0: return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + + for i in range(m): + for j in range(n): + if not marked[i][j] and grid[i][j] == '1': + count += 1 + queue = deque() + queue.append((i,j)) + marked[i][j] = True + while queue: + cur_x, cur_y = queue.popleft() + for direction in self.directions: + new_i = cur_x + direction[0] + new_j = cur_y + direction[1] + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + queue.append((new_i, new_j)) + marked[new_i][new_j] = True + return count + +grid = [['1', '1', '1', '0', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '1']] + +solution = Solution() +result = solution.numIslands(grid) +print(result) + + diff --git a/Week 03/id_246/LeetCode_33_246.py b/Week 03/id_246/LeetCode_33_246.py new file mode 100644 index 000000000..a8e3e8b6c --- /dev/null +++ b/Week 03/id_246/LeetCode_33_246.py @@ -0,0 +1,41 @@ +''' +search-in-rotated-sorted-array_33 + +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + +( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + +搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + +你可以假设数组中不存在重复的元素。 + +你的算法时间复杂度必须是 O(log n) 级别。 + +示例 1: +输入: nums = [4,5,6,7,0,1,2], target = 0 +输出: 4 + +示例 2: +输入: nums = [4,5,6,7,0,1,2], target = 3 +输出: -1 +''' + +#二分 +def search(nums, target): + left, right = 0, len(nums)-1 + mid = (left+right) //2 + + while left <= right: + if nums[mid] == target: + return mid + judge1 = nums[left] < nums[mid] and target < nums[mid] and target >= nums[left] + #半边有序 + judge2 = nums[left] > nums[mid] and (target < nums[mid] or target >= nums[left]) + #半边旋转 + if judge1 or judge2: #半边有序 + right = mid - 1 + mid = (left + right)//2 + else: + left = mid + 1 + mid = (left + right)//2 + return -1 \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_455_246.py b/Week 03/id_246/LeetCode_455_246.py new file mode 100644 index 000000000..88e80ae57 --- /dev/null +++ b/Week 03/id_246/LeetCode_455_246.py @@ -0,0 +1,36 @@ +''' +assign-cookies_455 + +假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + +注意: + +你可以假设胃口值为正。 +一个小朋友最多只能拥有一块饼干。 + +示例 1: +输入: [1,2,3], [1,1] +输出: 1 + +示例 2: +输入: [1,2], [1,2,3] +输出: 2 + +''' + +def findContentChildren(g,s): #g:胃口, s: 饼干 + res = 0 + g.sort() + s.sort() + g_length = len(g) + s_length = len(s) + i = 0 + j = 0 + while i< g_length and j < s_length: + if g[i] <= s[j]: + res += 1 + i += 1 + j += 1 + else: + j += 1 + return res \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_45_246.py b/Week 03/id_246/LeetCode_45_246.py new file mode 100644 index 000000000..f7b359b3f --- /dev/null +++ b/Week 03/id_246/LeetCode_45_246.py @@ -0,0 +1,53 @@ +''' + +jump-game-ii_45 + +给定一个非负整数数组,你最初位于数组的第一个位置。 + +数组中的每个元素代表你在该位置可以跳跃的最大长度。 + +你的目标是使用最少的跳跃次数到达数组的最后一个位置。 + +示例: + +输入: [2,3,1,1,4] + +输出: 2 + +说明: +假设你总是可以到达数组的最后一个位置。 +''' + +def jump(nums): + last_max_reach, current_max_reach = 0, 0 + njump, i = 0, 0 + while current_max_reach < len(nums)-1: + while i <= last_max_reach: + current_max_reach = max(i+nums[i], current_max_reach) + i += 1 + if last_max_reach == current_max_reach: + return -1 + last_max_reach = current_max_reach + njump += 1 + return njump + + +#优化 +def jump_2(nums): + if len(nums) == 1: + return 0 + cur = 0 + max_jump = 0 + k = nums[0] + tm = 1 + while cur <= max_jump: + max_jump = max(cur+nums[cur], max_jump) + if cur == k: + k = max_jump + tm += 1 + cur +=1 + if max_jump >= len(nums)-1: + if k >= len(nums)-1: + return tm + else: + return tm+1 diff --git a/Week 03/id_246/LeetCode_529_246.py b/Week 03/id_246/LeetCode_529_246.py new file mode 100644 index 000000000..736ee0d4c --- /dev/null +++ b/Week 03/id_246/LeetCode_529_246.py @@ -0,0 +1,83 @@ +''' +minesweeper_529 + +给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。 + +现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板: + +如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。 +如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。 +如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。 +如果在此次点击中,若无更多方块可被揭露,则返回面板。 +  + +示例 1: + +输入: + +[['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'M', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E']] +Click : [3,0] + +输出: +[['B', '1', 'E', '1', 'B'], + ['B', '1', 'M', '1', 'B'], + ['B', '1', '1', '1', 'B'], + ['B', 'B', 'B', 'B', 'B']] + + +示例 2: +输入: + +[['B', '1', 'E', '1', 'B'], + ['B', '1', 'M', '1', 'B'], + ['B', '1', '1', '1', 'B'], + ['B', 'B', 'B', 'B', 'B']] + +Click : [1,2] + +输出: + +[['B', '1', 'E', '1', 'B'], + ['B', '1', 'X', '1', 'B'], + ['B', '1', '1', '1', 'B'], + ['B', 'B', 'B', 'B', 'B']] + +注意: + +输入矩阵的宽和高的范围为 [1,50]。 +点击的位置只能是未被挖出的方块 ('M' 或者 'E'),这也意味着面板至少包含一个可点击的方块。 +输入面板不会是游戏结束的状态(即有地雷已被挖出)。 +简单起见,未提及的规则在这个问题中可被忽略。例如,当游戏结束时你不需要挖出所有地雷,考虑所有你可能赢得游戏或标记方块的情况。 +''' + +#dfs + +def updateBoard(board, click): + click = tuple(click) + R,C = len(board), len(board[0]) + + def neighbors(r, c): + for dr in range(-1,2): + for dc in range(-1,2): + if (dr or dc) and 0 <= r + dr < R and 0 <= c + dc < C: + yield r+dr, c+dc + stack = [click] + seen = {click} + while stack: + r, c = stack.pop() + if board[r][c] == 'M': + board[r][c] = 'X' + else: + mines_adj = sum( board[nr][nc] in 'MX' for nr, nc in neighbors(r, c) ) + if mines_adj: + board[r][c] = str(mines_adj) + else: + board[r][c] = 'B' + for nei in neighbors(r, c): + if board[nei[0]][nei[1]] in 'ME' and nei not in seen: + stack.append(nei) + seen.add(nei) + return board \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_55_246.py b/Week 03/id_246/LeetCode_55_246.py new file mode 100644 index 000000000..27b9bb28e --- /dev/null +++ b/Week 03/id_246/LeetCode_55_246.py @@ -0,0 +1,27 @@ +''' +jump-game_55 + +给定一个非负整数数组,你最初位于数组的第一个位置。 + +数组中的每个元素代表你在该位置可以跳跃的最大长度。 + +判断你是否能够到达最后一个位置。 + +示例 1: +输入: [2,3,1,1,4] +输出: true +解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + +示例 2: +输入: [3,2,1,0,4] +输出: false +解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 +''' + +def canJump(nums): + m = 0 #m tells the maximum index we can reach so far. + for i, n in enumerate(nums): + if i > m: + return False + m = max(m, i+n) + return True \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_74_246.py b/Week 03/id_246/LeetCode_74_246.py new file mode 100644 index 000000000..fc88b8e5c --- /dev/null +++ b/Week 03/id_246/LeetCode_74_246.py @@ -0,0 +1,38 @@ +''' +search-a-2d-matrix_74 + +编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: + +每行中的整数从左到右按升序排列。 +每行的第一个整数大于前一行的最后一个整数。 +示例 1: + +输入: +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] + ] +target = 3 +输出: true + +''' + +def searchMatrix(matrix): + m = len(matrix) + if m == 0: + return False + n = len(matrix[0]) + + left, right = 0, m*n-1 + while left<=right: + pivot_idx = (left+right)//2 + pivot_element = matrix[pivot_idx//n][pivot_idx%n] + if target == pivot_element: + return True + else: + if target < pivot_element: + right = pivot_idx - 1 + else: + left = pivot_idx + 1 + return False \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_860_246.py b/Week 03/id_246/LeetCode_860_246.py new file mode 100644 index 000000000..e1a170c9c --- /dev/null +++ b/Week 03/id_246/LeetCode_860_246.py @@ -0,0 +1,43 @@ +''' +lemonade-change_860 + +在柠檬水摊上,每一杯柠檬水的售价为 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。 +''' + + +def lemonadeChange(bills): + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True \ No newline at end of file diff --git a/Week 03/id_246/LeetCode_874_246.py b/Week 03/id_246/LeetCode_874_246.py new file mode 100644 index 000000000..8bb2c454b --- /dev/null +++ b/Week 03/id_246/LeetCode_874_246.py @@ -0,0 +1,42 @@ +''' +walking-robot-simulation_874 + +机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令: + +-2:向左转 90 度 +-1:向右转 90 度 +1 <= x <= 9:向前移动 x 个单位长度 +在网格上有一些格子被视为障碍物。 + +第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1]) + +如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。 + +返回从原点到机器人的最大欧式距离的平方。 + +示例: + +输入: commands = [4,-1,3], obstacles = [] +输出: 25 +解释: 机器人将会到达 (3, 4) +''' + +def robotSim(commands, obstacles): + dx = [0,1,0,-1] + dy = [1,0,-1,0] + x = y = di = 0 + obstaclesSet = set(map(tuple, obstacles)) + ans = 0 + + for cmd in commands: + if cmd == -2: + di = (di-1)%4 + elif cmd == -1: + di = (di+1)%4 + else: + for k in range(cmd): + if (x+dx[di], y+dy[di]) not in obstaclesSet: + x += dx[di] + y += dy[di] + ans = max(ans, x*x+y*y) + return ans \ No newline at end of file diff --git a/Week 03/id_246/NOTE.md b/Week 03/id_246/NOTE.md index a6321d6e2..2024b4c69 100644 --- a/Week 03/id_246/NOTE.md +++ b/Week 03/id_246/NOTE.md @@ -1,4 +1,24 @@ # NOTE - +第九课: +深度优先搜索(DFS): +1、从根节点开始, 沿着树的分支一直往下找子节点 +2、直到没有子节点, 再往回上一级, 重复第一步 +3、直到所有的子节点都遍历了一遍 +需要熟练掌握内容: DFS模板(递归、非递归写法) +广度优先搜索(BFS): 每个节点仅访问一次 +1、从根节点开始, 沿着树的分支往下找,每层的节点。 +2、每个节点仅访问一次 +3、直到最后一层没有节点的时候结束 +需要熟练掌握内容: BFS模板 + + +第十课: +贪心算法: +1. 每一步选择当前最优解,特定情况下能得到全局最优解 +2. 与动态规划区别:不能回退;动态规划会保存以前的运算结果,具有回退功能 + +第十一课: +二分查找 : +1、前提:目标函数单调;存在上下界;能够通过索引访问; \ No newline at end of file diff --git "a/Week 03/id_251/BFS\344\273\243\347\240\201\346\250\241\346\235\277.md" "b/Week 03/id_251/BFS\344\273\243\347\240\201\346\250\241\346\235\277.md" new file mode 100644 index 000000000..8b7bcc1a8 --- /dev/null +++ "b/Week 03/id_251/BFS\344\273\243\347\240\201\346\250\241\346\235\277.md" @@ -0,0 +1,18 @@ +```python +def BFS(graph, start, end): + + queue = [] + queue.append(start) + visited = {start} + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... +``` \ No newline at end of file diff --git "a/Week 03/id_251/DFS\344\273\243\347\240\201\346\250\241\346\235\277.md" "b/Week 03/id_251/DFS\344\273\243\347\240\201\346\250\241\346\235\277.md" new file mode 100644 index 000000000..c8ac0b6b2 --- /dev/null +++ "b/Week 03/id_251/DFS\344\273\243\347\240\201\346\250\241\346\235\277.md" @@ -0,0 +1,58 @@ +## 递归写法 + +### 树、图 +```python +visited = set() + +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) +``` + +### 二叉树 +```python +visited = set() + +def dfs(node): + # terminator + if node in visited: + # already visited + return + + visited.add(node) + + # process current node + # ... # logic here + dfs(node.left) + dfs(node.right) +``` + +## 非递归写法 +```python +def DFS(tree): + # terminator + if tree.root is None: + return [] + + visited, stack = set(), [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... +``` \ No newline at end of file diff --git a/Week 02/id_251/LeetCode_104_251.py b/Week 03/id_251/LeetCode_104_251.py similarity index 64% rename from Week 02/id_251/LeetCode_104_251.py rename to Week 03/id_251/LeetCode_104_251.py index 502aa3378..5fc85a087 100644 --- a/Week 02/id_251/LeetCode_104_251.py +++ b/Week 03/id_251/LeetCode_104_251.py @@ -26,8 +26,8 @@ # self.right = None """ -1 递归解法 -2 迭代解法 +1 递归解法 DFS +2 迭代解法 DFS """ @@ -41,3 +41,25 @@ def maxDepth(self, root): return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1 if root else 0 """ return 1 + max(map(self.maxDepth, (root.left, root.right))) if root else 0 + + +class SolutionDFS(object): + def maxDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + stack = [] + if root: + stack.append((1, root)) + + depth = 0 + + while stack: + cur_depth, root = stack.pop() + if root: + depth = max(depth, cur_depth) + stack.append((cur_depth + 1, root.left)) + stack.append((cur_depth + 1, root.right)) + + return depth diff --git a/Week 03/id_251/LeetCode_122_251.py b/Week 03/id_251/LeetCode_122_251.py new file mode 100644 index 000000000..6ef8742da --- /dev/null +++ b/Week 03/id_251/LeetCode_122_251.py @@ -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。 +# Related Topics 贪心算法 数组 + +""" +1 贪心 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + profit = 0 + + for i in range(1, len(prices)): + if prices[i] > prices[i - 1]: + profit += prices[i] - prices[i - 1] + + return profit + + # 一行搞定 + def maxProfit_(self, prices): + return sum([prices[i] - prices[i - 1] for i in range(1, len(prices)) if prices[i] > prices[i - 1]]) diff --git a/Week 03/id_251/LeetCode_127_251.py b/Week 03/id_251/LeetCode_127_251.py new file mode 100644 index 000000000..d02781cd0 --- /dev/null +++ b/Week 03/id_251/LeetCode_127_251.py @@ -0,0 +1,82 @@ +# 给定两个单词(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 广度优先搜索 + +""" +1 BFS 重点是刚开始的 构造通用状态字典 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + from collections import defaultdict + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + + L = len(beginWord) + + # 构造通用状态字典 + all_combo_dict = defaultdict(list) + for word in wordList: + for i in range(L): + all_combo_dict[word[:i] + '*' + word[i + 1:]].append(word) + + # Queue for BFS + queue = [(beginWord, 1)] + visited = {beginWord: True} + while queue: + current_word, level = queue.pop(0) + for i in range(L): + intermediate_word = current_word[:i] + '*' + current_word[i + 1:] + for word in all_combo_dict[intermediate_word]: + if word == endWord: + return level + 1 + if word not in visited: + visited[word] = True + queue.append((word, level + 1)) + return 0 diff --git a/Week 03/id_251/LeetCode_33_251.py b/Week 03/id_251/LeetCode_33_251.py new file mode 100644 index 000000000..2ad6bbbc9 --- /dev/null +++ b/Week 03/id_251/LeetCode_33_251.py @@ -0,0 +1,75 @@ +# 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +# +# ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +# +# 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +# +# 你可以假设数组中不存在重复的元素。 +# +# 你的算法时间复杂度必须是 O(log n) 级别。 +# +# 示例 1: +# +# 输入: nums = [4,5,6,7,0,1,2], target = 0 +# 输出: 4 +# +# +# 示例 2: +# +# 输入: nums = [4,5,6,7,0,1,2], target = 3 +# 输出: -1 +# Related Topics 数组 二分查找 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left < right: + mid = left + (right - left) // 2 + if (nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]): + left = mid + 1 + else: + right = mid + return left if target in nums[left: left + 1] else -1 + + +# 好理解的解法 +class Solution1(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + if not nums: + return -1 + + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + (right - left) // 2 + if nums[mid] == target: + return mid + if nums[left] <= nums[mid]: + if nums[left] <= target < nums[mid]: + right = mid - 1 + else: + left = mid + 1 + else: + if nums[mid] < target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + return -1 + + +if __name__ == '__main__': + s = Solution1() + print(s.search([], 0)) + print(s.search([1, 2, 3], 2)) + print(s.search([4, 5, 6, 0, 1, 3], 0)) diff --git "a/Week 03/id_251/\344\272\214\345\210\206\346\237\245\346\211\276\344\273\243\347\240\201\346\250\241\346\235\277.md" "b/Week 03/id_251/\344\272\214\345\210\206\346\237\245\346\211\276\344\273\243\347\240\201\346\250\241\346\235\277.md" new file mode 100644 index 000000000..7b7036fc6 --- /dev/null +++ "b/Week 03/id_251/\344\272\214\345\210\206\346\237\245\346\211\276\344\273\243\347\240\201\346\250\241\346\235\277.md" @@ -0,0 +1,12 @@ +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = left + (right - left) // 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` \ No newline at end of file diff --git "a/Week 03/id_251/\350\277\230\345\216\237\344\270\200\344\270\252\350\242\253\346\227\213\350\275\254\347\232\204\346\216\222\345\272\217\345\210\227\350\241\250.py" "b/Week 03/id_251/\350\277\230\345\216\237\344\270\200\344\270\252\350\242\253\346\227\213\350\275\254\347\232\204\346\216\222\345\272\217\345\210\227\350\241\250.py" new file mode 100644 index 000000000..47a2e5ef8 --- /dev/null +++ "b/Week 03/id_251/\350\277\230\345\216\237\344\270\200\344\270\252\350\242\253\346\227\213\350\275\254\347\232\204\346\216\222\345\272\217\345\210\227\350\241\250.py" @@ -0,0 +1,25 @@ +""" +约束条件:列表中没有重复元素 +""" + + +def revert(array): + left, right = 0, len(array) - 1 + while left < right: + mid = left + (right - left) // 2 + # 找到旋转后第二段的起点 + if array[mid] > array[right]: + left = mid + 1 + else: + right = mid + return array[left:] + array[:left] + + +if __name__ == '__main__': + print(revert([4, 5, 6, 1, 2, 3])) + print(revert([4, 5, 6, 0, 1, 2, 3])) + print(revert([4, 5, 6, 7, 0, 1, 2])) + print(revert([4, 5, 6, 7, -3, -2, 0, 1, 2])) + print(revert([])) + print(revert([1])) + print(revert([1, 2, 3])) diff --git a/Week 03/id_256/LeetCode_105_256.js b/Week 03/id_256/LeetCode_105_256.js new file mode 100644 index 000000000..ae35dc273 --- /dev/null +++ b/Week 03/id_256/LeetCode_105_256.js @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=105 lang=javascript + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number[]} preorder 前序遍历 根 左 右 + * @param {number[]} inorder 中序遍历 左 根 右 + * @return {TreeNode} + */ +var buildTree = function(preOrder, inOrder) { + if (inOrder.length == 0 && preOrder.length == 0) { + return null; + } + let root = {}; + // 根据前序,中序规则,preOrder的第一个一定是根 + root.val = preOrder[0]; + let rootIdxInOrder = inOrder.indexOf(root.val); + // 左子树的中序遍历 即根左边的列表 + let leftTreeInOrder = inOrder.slice(0, rootIdxInOrder); + // 左子树的前序遍历 第一个是根跳过第一个,后续与 中序列表个数一致。 + let leftTreePreOrder = preOrder.slice(1, leftTreeInOrder.length + 1); + root.left = buildTree(leftTreePreOrder, leftTreeInOrder); + // 右子树的中序遍历 + let rightTreeInOrder = inOrder.slice(rootIdxInOrder + 1); + let rightTreePreOrder = preOrder.slice(rootIdxInOrder + 1); + root.right = buildTree(rightTreePreOrder, rightTreeInOrder); + console.log(root); + return root; + } + // @lc code=end + \ No newline at end of file diff --git a/Week 03/id_256/LeetCode_127_256.js b/Week 03/id_256/LeetCode_127_256.js new file mode 100644 index 000000000..3a3fef5b9 --- /dev/null +++ b/Week 03/id_256/LeetCode_127_256.js @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode.cn id=127 lang=javascript + * + * [127] 单词接龙 + */ + +// @lc code=start +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +var ladderLength = function(beginWord, endWord, wordList) { + // hit cog ['hot','dot','dog','lot','log','cog'] + let beginIndex = wordList.indexOf(beginWord); + if(beginIndex >= 0) { + wordList.splice(beginIndex, 1); + } + let endIndex = wordList.indexOf(endWord); + if(endIndex < 0 || wordList.length <= 0)return 0; + let queue = [beginWord]; + let res = 2; + while(queue.length > 0) { + let len = queue.length; + for (let i = 0; i < len; i++) { + let str = queue.shift(); + for(let j = 0; j < wordList.length; j++) { + if (diff(str, wordList[j])) { + let newStr = wordList.splice(j--,1)[0]; + if(newStr === endWord){ + return res; + }else{ + queue.push(newStr); + } + } + } + } + res++; + } + return 0; + function diff(str1, str2) { + let res = 0; + for (let i = 0; i < str1.length; i++) { + if (str1[i] !== str2[i]) { + res += 1; + } + if(res>1)return false; + } + return true; + } +}; +// @lc code=end + diff --git a/Week 03/id_256/LeetCode_33_256.js b/Week 03/id_256/LeetCode_33_256.js new file mode 100644 index 000000000..756a6ff96 --- /dev/null +++ b/Week 03/id_256/LeetCode_33_256.js @@ -0,0 +1,44 @@ +/* + * @lc app=leetcode.cn id=33 lang=javascript + * + * [33] 搜索旋转排序数组 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function(nums, target) { + let left = 0; + let right = nums.length - 1; + if(nums.length <= 0) return -1; + while (left < right) { + let mid = parseInt((left + right) / 2); + if(target < nums[0] && target > nums[mid]) { + left = mid + 1; + } else if(nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + left = mid + 1; + } else { + right = mid; + } + } + return left == right && nums[left] == target ? left : -1 ; + + // let left = 0; + // let right = nums.length - 1; + // while (left < right) { + // let mid = parseInt((left + right) / 2); + // if(target < nums[0] && target > nums[mid]) { + // left = mid + 1; + // }else if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + // left = mid + 1; + // }else{ + // right = mid; + // } + // } + // return left == right && nums[left] == target ? left : -1; + +}; +// @lc code=end diff --git a/Week 03/id_256/LeetCode_70_256.js b/Week 03/id_256/LeetCode_70_256.js new file mode 100644 index 000000000..c09484179 --- /dev/null +++ b/Week 03/id_256/LeetCode_70_256.js @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=70 lang=javascript + * + * [70] 爬楼梯 + */ + +// @lc code=start +/** + * @param {number} n + * @return {number} + */ +var climbStairs = function(n) { + //方法一 暴力 +// let dfs = function(start, n) { +// if (start > n) { +// return 0; +// } else if (start === n) { +// return 1; +// } +// return dfs(start + 1, n) + dfs(start + 2, n); +// }; +// return dfs(0, n); + //方法二 + let valueMap = {}; + valueMap['1'] = 1; + valueMap['2'] = 2; + for (let i = 3; i <= n; i ++) { + valueMap[`${i}`] = valueMap[`${i-1}`] + valueMap[`${i-2}`]; + } + return valueMap[`${n}`]; +}; + +// @lc code=end diff --git a/Week 03/id_256/LeetCode_77_256.js b/Week 03/id_256/LeetCode_77_256.js new file mode 100644 index 000000000..b27b29171 --- /dev/null +++ b/Week 03/id_256/LeetCode_77_256.js @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=77 lang=javascript + * + * [77] 组合 + */ + +// @lc code=start +/** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ +var combine = function(n, k) { + //循环匹配 + if(k == 0 || k > n) return [[]]; + let result = []; + let temp = []; + return dfs(1, n, k, result, temp); + }; + var dfs = function(start, n, k, result, temp) { + if(temp.length == k) { + result.push([...temp]); + return; + } + for (let i = start; i < n+1; i++) { + temp.push(i); + dfs(i+1, n, k, result, temp); + temp.pop(); + } + return result; + } + // @lc code=end + \ No newline at end of file diff --git a/Week 03/id_256/LeetCode_860_256.js b/Week 03/id_256/LeetCode_860_256.js new file mode 100644 index 000000000..105befaec --- /dev/null +++ b/Week 03/id_256/LeetCode_860_256.js @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=860 lang=javascript + * + * [860] 柠檬水找零 + */ + +// @lc code=start +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function(bills) { + let five = 0; + let ten = 0; + for (let i = 0; i < bills.length; i++) { + if(bills[i] === 5) { + five++; + } else if (bills[i] === 10) { + five--; + ten++; + } else if (bills[i] === 20) { + if(ten > 0 && five > 0) { + ten --; + five --; + } else{ + five -= 3; + } + } + if(five < 0 || ten < 0) return false; + } + return true; +}; +// @lc code=end + diff --git a/Week 03/id_261/leetcode_153_261.go b/Week 03/id_261/leetcode_153_261.go new file mode 100644 index 000000000..38b02d2f6 --- /dev/null +++ b/Week 03/id_261/leetcode_153_261.go @@ -0,0 +1,16 @@ +// leetcode - https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array + +func findMin(nums []int) int { + left, right := 0, len(nums) - 1 + for left < right { + mid := (left + right) / 2 + if nums[mid] < nums[right] { + right = mid + } else if nums[mid] > nums[right] && right - mid == 1 { + return nums[right] + } else { + left = mid + } + } + return nums[0] +} \ No newline at end of file diff --git a/Week 03/id_261/leetcode_74_261.go b/Week 03/id_261/leetcode_74_261.go new file mode 100644 index 000000000..907fd6e0d --- /dev/null +++ b/Week 03/id_261/leetcode_74_261.go @@ -0,0 +1,23 @@ +// leetcode - https://leetcode-cn.com/problems/search-a-2d-matrix + +func searchMatrix(matrix [][]int, target int) bool { + len1 := len(matrix) + if len1 == 0 { + return false + } + len2 := len(matrix[0]) + left, right := 0, len1*len2-1 + + for left <= right { + mid := (left + right) / 2 + x,y := (mid/len2), (mid%len2) + if matrix[x][y] == target { + return true + } else if matrix[x][y] < target { + left = mid + 1 + } else { + right = mid - 1 + } + } + return false +} \ No newline at end of file diff --git a/Week 03/id_266/266-Week 03 b/Week 03/id_266/266-Week 03 new file mode 100644 index 000000000..1351f630a --- /dev/null +++ b/Week 03/id_266/266-Week 03 @@ -0,0 +1,48 @@ +1.搜索二维矩阵search-a-2d-matrix + +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + + // 二分查找 + int left = 0, right = m * n - 1; + int pivotIdx, pivotElement; + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if (target == pivotElement) return true; + else { + if (target < pivotElement) right = pivotIdx - 1; + else left = pivotIdx + 1; + } + } + return false; + } +} + +2.搜索旋转排序数组search-in-rotated-sorted-array + +class Solution { + public int search(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + + while (left <= right) { + int mid = (left + right) / 2; + if (nums[mid] == target) + return mid; + else if (nums[left] <= nums[mid] && (target > nums[mid] || target < nums[left])) { + left = mid + 1; + } + else if (target > nums[mid] && target < nums[left]) { + left = mid + 1; + } + else { + right = mid - 1; + } + } + return -1; + } +} diff --git a/Week 03/id_276/LeetCode_122_276.java b/Week 03/id_276/LeetCode_122_276.java new file mode 100644 index 000000000..26ce48920 --- /dev/null +++ b/Week 03/id_276/LeetCode_122_276.java @@ -0,0 +1,11 @@ +package Greedy; + +public class LeetCode_122_276 { + public int maxProfile(int[] prices) { + int max = 0; + for (int i=0; i prices[i+1] ? prices[i]-prices[i+1] : 0; + } + return max; + } +} diff --git a/Week 03/id_276/LeetCode_33_276.java b/Week 03/id_276/LeetCode_33_276.java new file mode 100644 index 000000000..7e9cd5734 --- /dev/null +++ b/Week 03/id_276/LeetCode_33_276.java @@ -0,0 +1,52 @@ +package Greedy; + +public class LeetCode_33_276 { + //思路: + //1.还原排序数组,再用二分法查找 + //2.直接用二分法查找 + //找到最小值位置 + public int search(int[] nums, int target) { + int lo = 0, hi = nums.length-1; + while (lo < hi) { + int mid = (lo + hi + 1) >>> 1; + if (target > nums[mid] && target > nums[lo]) + } + } + + public int search(int[] nums, int target) { + if (nums == null || nums.length < 1) return -1; + int lo = 0,hi = nums.length-1; + while (lo < hi) { + int mid = (lo + hi) / 2; + if (nums[mid] > nums[hi]) lo = mid + 1; + else hi = mid; + } + int min = lo; + lo = (target <= nums[nums.length-1])? min : 0; + hi = (target > nums[nums.length-1] ) ? min-1 : nums.length-1; + while (lo < hi) { + int mid = (lo + hi) / 2; + if (nums[mid] > target) hi = mid - 1; + else if (nums[mid] == target) return mid; + else lo = mid + 1; + } + return -1; + } + + //直接二分 + public int search (int[] nums, int target) { + if (nums == null || nums.length < 1) return -1; + int lo = 0, hi = nums.length-1; + while (lo < hi) { + int mid = (hi +hi)/2; + if (nums[mid] == target) return mid; + int key = (nums[mid] < nums[0]) == (target >> 1; + long square = mid * mid; + if (square > x) right = mid - 1; + else if (square < x) left = mid; + else return (int) mid; + } + return (int) left; + } + + + public int sqrt(int x) { + long r = x / 2; + while (r*r > x) r = (r + x/r)/2; + return (int) r; + } +} diff --git a/Week 03/id_281/LeetCode_127_281.java b/Week 03/id_281/LeetCode_127_281.java new file mode 100644 index 000000000..e1f122a8b --- /dev/null +++ b/Week 03/id_281/LeetCode_127_281.java @@ -0,0 +1,64 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import jdk.internal.util.xml.impl.Pair; + +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ + +// @lc code=start +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + + int L = beginWord.length(); + + HashMap> allCommonDict = new HashMap>(); + wordList.forEach( + word -> { + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + ArrayList transforms = allCommonDict.getOrDefault(newWord, new ArrayList()); + transforms.add(word); + allCommonDict.put(newWord, transforms); + } + } + ); + + // Queue For BFS + Queue> Q = new LinkedList>(); + Q.add(new Pair(beginWord, 1)); + + HashMap visited = new HashMap(); + visited.put(beginWord, true); + + while (!Q.isEmpty()) { + Pair node = Q.remove(); + String word = node.getkey(); + int level = node.getValue(); + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + + for (String adjacentWord : allCommonDict.getOrDefault(newWord, new ArrayList())) { + if (adjacentWord.equals(endWord)) { + return level + 1; + } + + if (!visited.containsKey(adjacentWord)) { + visited.put(adjacentWord, true); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + } + + return 0; + } +} +// @lc code=end + diff --git a/Week 03/id_281/LeetCode_33_281.java b/Week 03/id_281/LeetCode_33_281.java new file mode 100644 index 000000000..fcaead106 --- /dev/null +++ b/Week 03/id_281/LeetCode_33_281.java @@ -0,0 +1,66 @@ +class Solution { + int [] nums; + int target; + + public int find_rotate_index(int left, int right) { + if (nums[left] < nums[right]) + return 0; + + while (left <= right) { + int pivot = (left + right) / 2; + if (nums[pivot] > nums[pivot + 1]) + return pivot + 1; + else { + if (nums[pivot] < nums[left]) + right = pivot - 1; + else + left = pivot + 1; + } + } + return 0; + } + + public int search(int left, int right) { + /* + Binary search + */ + while (left <= right) { + int pivot = (left + right) / 2; + if (nums[pivot] == target) + return pivot; + else { + if (target < nums[pivot]) + right = pivot - 1; + else + left = pivot + 1; + } + } + return -1; + } + + public int search(int[] nums, int target) { + this.nums = nums; + this.target = target; + + int n = nums.length; + + if (n == 0) + return -1; + if (n == 1) + return this.nums[0] == target ? 0 : -1; + + int rotate_index = find_rotate_index(0, n - 1); + + // if target is the smallest element + if (nums[rotate_index] == target) + return rotate_index; + // if array is not rotated, search in the entire array + if (rotate_index == 0) + return search(0, n - 1); + if (target < nums[0]) + // search in the right side + return search(rotate_index, n - 1); + // search in the left side + return search(0, rotate_index); + } + } \ No newline at end of file diff --git a/Week 03/id_281/NOTE.md b/Week 03/id_281/NOTE.md index a6321d6e2..d502e4340 100644 --- a/Week 03/id_281/NOTE.md +++ b/Week 03/id_281/NOTE.md @@ -1,4 +1,6 @@ -# NOTE +# 第三周学习总结 + +本周学习效率有点低,下周把总结在补上,感觉完成题目的代码明显要多了,坚持五毒神掌,一定有作用。 diff --git a/Week 03/id_286/LeetCode_102_286.java b/Week 03/id_286/LeetCode_102_286.java new file mode 100644 index 000000000..d7f80da21 --- /dev/null +++ b/Week 03/id_286/LeetCode_102_286.java @@ -0,0 +1,85 @@ +package com.uanei; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class LeetCode_102_286 { + + /** + * dfs 深度优先:递归 + */ + public List> levelOrder1(TreeNode root) { + List> res = new ArrayList<>(); + + if (root == null) return res; + else compute(root, 0, res); + return res; + } + + private void compute(TreeNode node, int level, List> res) { + // level 从0开始,即根节点开始 + // 初始化 level + 1 层,即当前层的集合 + // 如果不想等,说明集合已经初始化了 + if (level == res.size()) { + res.add(new ArrayList<>()); + } + + // 将当前节点添加到当前层的集合中 + res.get(level).add(node.val); + + // 继续处理子节点 + if (node.left != null) compute(node.left, level + 1, res); + if (node.right != null) compute(node.right, level + 1, res); + } + + /** + * bfs 广度优先,queue + while + */ + public List> levelOrder(TreeNode root) { + List> res = new ArrayList<>(); + + if (root == null) return res; + + Queue queue = new LinkedList<>(); + queue.add(root); + int level = 0; + + // 队列中的节点是一层一层的 + while (!queue.isEmpty()) { + // 初始化当前层集合 + res.add(new ArrayList<>()); + + // 遍历当前层 + int currentLevelLength = queue.size(); + for (int i = 0; i < currentLevelLength; i++) { + // 从队列中移除 + TreeNode node = queue.remove(); + + // 添加到集合中 + res.get(level).add(node.val); + + // 将当前层节点的子节点添加到队列中 + if (node.left != null) queue.add(node.left); + if (node.right != null) queue.add(node.right); + } + + // 下一层 + level++; + } + + return res; + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + +} diff --git a/Week 03/id_286/LeetCode_122_286.java b/Week 03/id_286/LeetCode_122_286.java new file mode 100644 index 000000000..0a1f75eb6 --- /dev/null +++ b/Week 03/id_286/LeetCode_122_286.java @@ -0,0 +1,18 @@ +package com.uanei; + +public class LeetCode_122_286 { + + /** + * 贪心算法:只要后边比前边大,前一天就买,后一天就卖 + */ + public int maxProfit(int[] prices) { + int max = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + max = max + (prices[i] - prices[i - 1]); + } + } + return max; + } + +} diff --git a/Week 03/id_286/LeetCode_200_286.java b/Week 03/id_286/LeetCode_200_286.java new file mode 100644 index 000000000..ad11b2c4f --- /dev/null +++ b/Week 03/id_286/LeetCode_200_286.java @@ -0,0 +1,58 @@ +package com.uanei; + +public class LeetCode_200_286 { + + // 构建一个坐标中的上下左右 + int dx[] = {-1, 1, 0, 0}; + int dy[] = {0, 0, -1, 1}; + char[][] g; + + /** + * dfs 深度优先的算法,判断周围的1 + */ + public int numIslands(char[][] grid) { + // 初始化岛屿的数量 + int islands = 0; + // g是临时网格,岛屿会被打掉变成水 + g = grid; + + for (int i = 0; i < g.length; i++) { + for (int j = 0; j < g[i].length; j++) { + // 遇到水不处理 + if (g[i][j] == '0') continue; + + // g[i][j] = '1' 表示陆地 + // 遇到1,岛屿,需要通过dfs,深度优先,递归的方式打掉 + islands += sink(i, j); + } + } + + return islands; + } + + private int sink(int i, int j) { + if (g[i][j] == '0') { + return 0; + } + + // 打掉1 + g[i][j] = '0'; + + // 上下左右挨着的位置是1也需要被打掉 + for (int k = 0; k < dx.length; k++) { + // 坐标中的位置 + int x = i + dx[k], y = j + dy[k]; + // 数组下标是大于等于0的 + if (x >= 0 && x < g.length && y >= 0 && y < g[i].length) { + if (g[x][y] == '0') continue; + + // 还需要检查相邻的1的周围是否有1 + sink(x, y); + } + } + + // 一个岛屿被打掉之后,计数 + return 1; + } + +} diff --git a/Week 03/id_286/LeetCode_33_286.java b/Week 03/id_286/LeetCode_33_286.java new file mode 100644 index 000000000..4f8042893 --- /dev/null +++ b/Week 03/id_286/LeetCode_33_286.java @@ -0,0 +1,34 @@ +package com.uanei; + +public class LeetCode_33_286 { + + /** + * 二分查找:通过二分和收敛 + * 本题的关键点是时间复杂度,必须是o(logN)级别的 + */ + public int search(int[] nums, int target) { + int low = 0; + int high = nums.length - 1; + + while (low < high) { + int mid = (low + high) / 2; + + // 如果0到mid有序,则向后规约 + if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + low = mid + 1; + } + // 如果0到mid无序,则说明发生了旋转,如果不在0到mid中,则向后规约 + else if (target > nums[mid] && target < nums[0]) { + low = mid + 1; + } + // 向前规约 + else { + high = mid; + } + } + + // 找到了返回位置索引,没有找到,直接返回-1 + return low == high && nums[low] == target ? low : -1; + } + +} diff --git a/Week 03/id_286/LeetCode_55_286.java b/Week 03/id_286/LeetCode_55_286.java new file mode 100644 index 000000000..661319f4a --- /dev/null +++ b/Week 03/id_286/LeetCode_55_286.java @@ -0,0 +1,23 @@ +package com.uanei; + +public class LeetCode_55_286 { + + /** + * 贪心算法:从后往前,记录能够跳到最后那一个位置的第一个下标值 + * 简单理解就是,从最后位置向前看,能否到达最后 + */ + public boolean canJump(int[] nums) { + if (nums == null) return false; + + int endReachable = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + // 如果某个位置能到达下一个位置,就往前推 + if (nums[i] + i >= endReachable) { + endReachable = i; + } + } + + return endReachable == 0; + } + +} diff --git a/Week 03/id_286/LeetCode_69_286.java b/Week 03/id_286/LeetCode_69_286.java new file mode 100644 index 000000000..81929d21b --- /dev/null +++ b/Week 03/id_286/LeetCode_69_286.java @@ -0,0 +1,46 @@ +package com.uanei; + +public class LeetCode_69_286 { + + /** + * 二分查找 + */ + public int mySqrt1(int x) { + // 边界情况判断 + if (x == 0 || x == 1) { + return x; + } + + long left = 1; + long right = x; + while (left < right) { + long mid = left + (right - left + 1) / 2; + if (mid * mid > x) { + // mid 比较大,往左边找 + right = mid - 1; + } else { + left = mid; + } + } + + return (int) left; + } + + /** + * 牛顿迭代法:数学公式计算 + */ + public int mySqrt2(int x) { + if (x == 0 || x == 1) { + return x; + } + + long r = x; + + while (r * r > x) { + r = (r + x / r) / 2; + } + + return (int)r; + } + +} diff --git a/Week 03/id_296/LeetCode_33_296.java b/Week 03/id_296/LeetCode_33_296.java new file mode 100644 index 000000000..681ee3710 --- /dev/null +++ b/Week 03/id_296/LeetCode_33_296.java @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=33 lang=java + * + * [33] 搜索旋转排序数组 + */ + +// @lc code=start +class Solution { + public int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + while (start <= end) { + int mid = (start + end) / 2; + if (target == nums[mid]) { + return mid; + } + //左半段是有序的 + if (nums[start] <= nums[mid]) { + // 如果target在这段里,那么就继续在这找,不然丢弃 + if (target >= nums[start] && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + //右半段是有序的 + } else { + //如果target在这段里,那么就继续在这找,不然丢弃 + if (target > nums[mid] && target <= nums[end]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + } + return -1; + } +} +// @lc code=end + diff --git a/Week 03/id_296/LeetCode_74_296.java b/Week 03/id_296/LeetCode_74_296.java new file mode 100644 index 000000000..468557a65 --- /dev/null +++ b/Week 03/id_296/LeetCode_74_296.java @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=74 lang=java + * + * [74] 搜索二维矩阵 + */ + +// @lc code=start +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if(matrix == null || matrix.length == 0) + return false; + + int row = 0, col = matrix[0].length - 1; + while (row < matrix.length && col >= 0) { + if (target == matrix[row][col]) + return true; + else if (target > matrix[row][col]) + row++; + else { + // col--; + //这道题是参照了其中一个题解,通过每行最右边一个元素来查找,如果发现在这一行里就一个一个继续滚动 + //我突然觉得在最后这里可以再插入一个二分查找 + //结果是可以的,而且打败了100%的提交者,开心 + //不过这里也占用了一些内存,相当于用空间换时间了 + int left = 0, right = matrix[0].length - 2, mid = 0; + while (left <= right) { + mid = (left + right) / 2; + if (target == matrix[row][mid]) + return true; + else if (target > matrix[row][mid]){ + left = mid + 1; + } else { + right = mid - 1; + } + } + return false; + } + } + return false; + } +} +// @lc code=end + diff --git a/Week 03/id_296/LeetCode_860_296.java b/Week 03/id_296/LeetCode_860_296.java new file mode 100644 index 000000000..cb5c61082 --- /dev/null +++ b/Week 03/id_296/LeetCode_860_296.java @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + */ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int c5=0; + int c10=0; + for(int bill:bills){ + if(bill==5){ + c5 += 5; + }else if(bill==10){ + if(c5!=0){ + c5-=5; + c10+=10; + }else + return false; + }else if(c10!=0){ + if(c5!=0){ + c5-=5; + c10-=10; + }else + return false; + }else if(c5>=15){ + c5 -= 15; + }else + return false; + } + return true; + } +} +// @lc code=end + diff --git a/Week 03/id_301/LeetCode_102_301.go b/Week 03/id_301/LeetCode_102_301.go new file mode 100644 index 000000000..ab4ebf4b7 --- /dev/null +++ b/Week 03/id_301/LeetCode_102_301.go @@ -0,0 +1,65 @@ +package main + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +/** +广度优先遍历 +*/ +func levelOrder(root *TreeNode) [][]int { + if root == nil { + return [][]int{} + } + var slice [][]*TreeNode + slice = append(slice, []*TreeNode{root}) + var res [][]int + for i := 0; ; i++ { + for _, v := range slice[0] { + if len(res) > i { + res[i] = append(res[i], v.Val) + } else { + res = append(res, []int{v.Val}) + } + slice = add(slice, v.Left) + slice = add(slice, v.Right) + } + slice = slice[1:] + if len(slice) == 0 { + break + } + } + return res +} + +func add(slice [][]*TreeNode, node *TreeNode) [][]*TreeNode { + if node == nil { + return slice + } + if len(slice) > 1 { + slice[1] = append(slice[1], node) + } else { + slice = append(slice, []*TreeNode{node}) + } + return slice +} + +/** +深度优先遍历 +*/ +func levelOrderByDFS(root *TreeNode) [][]int { + var res [][]int + + return res +} diff --git a/Week 03/id_301/LeetCode_33_301.go b/Week 03/id_301/LeetCode_33_301.go new file mode 100644 index 000000000..40d78aa89 --- /dev/null +++ b/Week 03/id_301/LeetCode_33_301.go @@ -0,0 +1,30 @@ +package main + +/** +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + +( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + +搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + +你可以假设数组中不存在重复的元素。 + +你的算法时间复杂度必须是 O(log n) 级别。 +*/ +func search(nums []int, target int) int { + left, right := 0, len(nums)-1 + var mid int + for left < right { + mid = left + (right-left)/2 + if target == nums[mid] { + return mid + } + if nums[0] < nums[mid] && nums[mid] > target { + left = mid + } + if nums[0] > nums[mid] && nums[mid] > target { + left = mid + } + } + return -1 +} diff --git a/Week 03/id_301/LeetCode_69_301.go b/Week 03/id_301/LeetCode_69_301.go new file mode 100644 index 000000000..5d95a7a5a --- /dev/null +++ b/Week 03/id_301/LeetCode_69_301.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func mySqrt(x int) int { + if x == 0 || x == 1 { + return x + } + var mid int + left, right := 0, x + for left < right { + mid = left + (right-left+1)/2 + if mid*mid > x { + right = mid - 1 + } else { + left = mid + } + } + return left +} + +func main() { + fmt.Println(mySqrt(9)) +} diff --git a/Week 03/id_306/FindContentChildren.java b/Week 03/id_306/FindContentChildren.java new file mode 100644 index 000000000..890c7f96a --- /dev/null +++ b/Week 03/id_306/FindContentChildren.java @@ -0,0 +1,21 @@ +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/10/31. + * 力扣题目地址:https://leetcode-cn.com/problems/assign-cookies/description/ + */ +public class FindContentChildren { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int l = 0, r = 0,res = 0; + while (l < g.length && r < s.length) { + if (g[l] <= s[r]) { + l++; + res++; + } + r++; + } + return res; + } +} diff --git a/Week 03/id_306/FindMinimumInRotatedSortedArray.java b/Week 03/id_306/FindMinimumInRotatedSortedArray.java new file mode 100644 index 000000000..e7799f737 --- /dev/null +++ b/Week 03/id_306/FindMinimumInRotatedSortedArray.java @@ -0,0 +1,18 @@ +/** + * Created by LynnSun on 2019/11/3. + * 力扣题目地址:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + */ +public class FindMinimumInRotatedSortedArray { + public int findMin(int[] nums) { + int left = 0, right = nums.length - 1; + while(left < right){ + //找到数组的中间元素 mid。 + int mid = (left + right) / 2; + /*如果中间元素 > 数组第一个元素,变化点在右边。 + 如果中间元素 < 数组第一个元素,变化点在左边*/ + if(nums[mid] > nums[right]) left = mid + 1; + else right = mid; + } + return nums[left]; + } +} diff --git a/Week 03/id_306/JumpGame.java b/Week 03/id_306/JumpGame.java new file mode 100644 index 000000000..7e16c6018 --- /dev/null +++ b/Week 03/id_306/JumpGame.java @@ -0,0 +1,16 @@ +/** + * Created by LynnSun on 2019/11/1. + * 力扣题目地址:https://leetcode-cn.com/problems/jump-game/ + */ +public class JumpGame { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + // 如果 数组索引 + 数组值>= 最后的索引值 才能意味着 可以跳到最后 如此 如果能找到第一个索引为正确 + if (i + nums[i] >= lastPos) { + lastPos = i; + } + } + return lastPos == 0; + } +} diff --git a/Week 03/id_306/JumpGameTwo.java b/Week 03/id_306/JumpGameTwo.java new file mode 100644 index 000000000..dcae094c3 --- /dev/null +++ b/Week 03/id_306/JumpGameTwo.java @@ -0,0 +1,20 @@ +/** + * Created by LynnSun on 2019/11/1. + * 力扣题目地址:https://leetcode-cn.com/problems/jump-game-ii/ + */ +public class JumpGameTwo { + public int jump(int[] nums) { + int end = 0; + int maxPosition = 0; + int steps = 0; + for(int i = 0; i < nums.length - 1; i++){ + // 找能跳的最远的 + maxPosition = Math.max(maxPosition, nums[i] + i); + if( i == end){ // 遇到边界,就更新边界,并且步数加一 + end = maxPosition; + steps++; + } + } + return steps; + } +} diff --git a/Week 03/id_306/LemonadeChange.java b/Week 03/id_306/LemonadeChange.java new file mode 100644 index 000000000..683384d6d --- /dev/null +++ b/Week 03/id_306/LemonadeChange.java @@ -0,0 +1,32 @@ +/** + * Created by LynnSun on 2019/10/31. + * 力扣题目地址:https://leetcode-cn.com/problems/lemonade-change/description/ + */ +public class LemonadeChange { + public boolean lemonadeChange(int[] bills) { + int money_five=0; + int money_ten=0; + for (int bill :bills) { + if(5==bill){ + money_five++; + }else if (10==bill){ + if(money_five==0){ + return false; + } + money_five--; + money_ten++; + }else{ + // 这样才是贪心 先考虑10元再考虑5元 + if(money_ten>0 && money_five>0){ + money_ten--; + money_five--; + }else if(money_five>2){ + money_five=money_five-3; + }else{ + return false; + } + } + } + return true; + } +} diff --git a/Week 03/id_306/LevelOrder.java b/Week 03/id_306/LevelOrder.java new file mode 100644 index 000000000..9358d73ef --- /dev/null +++ b/Week 03/id_306/LevelOrder.java @@ -0,0 +1,78 @@ +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by LynnSun on 2019/10/28. + * 力扣题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/#/description + */ +public class LevelOrder { + + /** + * 广度优先搜索,用队列完成 + * @param root + * @return + */ + public List> levelOrder_bfs(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) return res; + // 队列 + Deque treeNodeQueque=new LinkedList<>(); + // 先保存第一个元素 + treeNodeQueque.add(root); + // 队列不为空进行循环,同时也是结束条件 + while (!treeNodeQueque.isEmpty()){ + // 保存每一层的输出结果 + List tmpOutList = new ArrayList<>(); + // 这里必须如此,不然for循环会改变treeNodeQueque.size()的值 + int queueSize=treeNodeQueque.size(); + // 循环取出队列中的元素 + for(int i=0;i> levelOrder_dfs(TreeNode root) { + List> levels = new ArrayList>(); + if (root == null) return levels; + dfs_helper(root, 0,levels); + return levels; + } + + /** + * 递归遍历左右分支树,但是需要传当前深度(层),这样出栈时就可以确定自己的层并保存正确 + * @param node + * @param level + * @param levels + */ + private void dfs_helper(TreeNode node,int level,List> levels){ + // 给每一层构建一个保存节点数据的List + if (levels.size() == level) + levels.add(new ArrayList()); + // 保存此节点数据 + levels.get(level).add(node.val); + // 如果左分支有下一层 继续递归遍历 + if (node.left != null) + dfs_helper(node.left, level + 1,levels); + // 如果右分支有下一层 继续递归遍历 + if (node.right != null) + dfs_helper(node.right, level + 1,levels); + } +} diff --git a/Week 03/id_306/MaxProfit.java b/Week 03/id_306/MaxProfit.java new file mode 100644 index 000000000..324b7ebae --- /dev/null +++ b/Week 03/id_306/MaxProfit.java @@ -0,0 +1,23 @@ +/** + * Created by LynnSun on 2019/10/31. + * 力扣题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + */ +public class MaxProfit { + public int maxProfit(int[] prices) { + // 贪心算法 + // 求最优解 + /**因为现实中对股票价格的不可预测性,我们不可能真的乱买乱卖。 + * 但是程序有数据能预测我们只是做一个模拟的话是可以求出最优解的。 + * 比如 2 4 9,来说,我应该今天买后天卖,最优解为 9 - 2 = 7, + * 那我就不能明天卖,应该后天卖,但是程序它不知道啊, + * 我们这样想,明天卖早了说明我明天买后天在卖还是有钱赚, + * 并且和后天卖的钱挣得是一样的即:9-4+4-2 = 7 + */ + int maxProfit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) + maxProfit += prices[i] - prices[i - 1]; + } + return maxProfit; + } +} diff --git a/Week 03/id_306/NumIslands_Union.java b/Week 03/id_306/NumIslands_Union.java new file mode 100644 index 000000000..453a83097 --- /dev/null +++ b/Week 03/id_306/NumIslands_Union.java @@ -0,0 +1,85 @@ +/** + * 并查集方法 + * Created by LynnSun on 2019/10/29. + * 力扣题目地址:https://leetcode-cn.com/problems/number-of-islands/ + */ +public class NumIslands_Union { + class UnionFind { + int count; // # of connected components + int[] parent; + int[] rank; + + public UnionFind(char[][] grid) { // for problem 200 + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { // path compression + if (parent[i] != i) parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { // union with rank + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r-1][c] == '1') { + uf.union(r * nc + c, (r-1) * nc + c); + } + if (r + 1 < nr && grid[r+1][c] == '1') { + uf.union(r * nc + c, (r+1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c-1] == '1') { + uf.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c+1] == '1') { + uf.union(r * nc + c, r * nc + c + 1); + } + } + } + } + + return uf.getCount(); + } +} diff --git a/Week 03/id_306/NumIslands_bfs.java b/Week 03/id_306/NumIslands_bfs.java new file mode 100644 index 000000000..faf3db9db --- /dev/null +++ b/Week 03/id_306/NumIslands_bfs.java @@ -0,0 +1,91 @@ +import java.util.LinkedList; + +/** + * Created by LynnSun on 2019/10/29. + * 力扣题目地址:https://leetcode-cn.com/problems/number-of-islands/ + * 广度优先搜索 + */ +public class NumIslands_bfs { + // 陆地坐标 + class Point{ + int x; + int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length < 1) { + return 0; + } + int count = 0, rows = grid.length; + // X 轴可以移动到的坐标,Y 轴可以移动到的坐标 + int[] moveX = {-1, 1, 0, 0}, moveY = {0, 0, -1, 1}; + LinkedList queue = new LinkedList(); + // rows 行数 + for (int i = 0; i < rows ; i++) { + // cols 列数 + int cols = grid[i].length; + for (int j = 0; j < cols; j++) { + if (grid[i][j] == '1') { + // 累加岛屿的数量 + count++; + // 把访问过的陆地坐标变成0(海水),再一次就不会再访问 + grid[i][j] = '0'; + // 添加到队列中 + queue.add(new Point(i, j)); + // 广度优先遍历,上下左右染色 + while (queue.size() != 0) { + // 取出陆地坐标 + Point p = queue.poll(); + // 对其进行上下左右的坐标进行判断能否组成岛屿 + for (int k = 0; k < moveX.length; k++) { + int x = p.x + moveX[k], y = p.y + moveY[k]; + // 判断是否能组成岛屿 + if (isValid(rows, cols, x, y) && grid[x][y] == '1') { + // 能组成岛屿就变成0(海水),下一次就不会再访问 + grid[x][y] = '0'; + queue.add(new Point(x, y)); + } + } + } + } + } + } + return count; + } + + /** + * 判断能否能移动 + * @param rows + * @param cols + * @param x + * @param y + * @return + */ + private boolean isValid(int rows,int cols, int x, int y) { + return x >= 0 && x < rows && y >= 0 && y < cols; + } + + public static void main(String[] args) { + NumIslands_bfs ns = new NumIslands_bfs(); + char[][] grid1 = { + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'}}; + int numIslands1 = ns.numIslands(grid1); + System.out.println(numIslands1); + + char[][] grid2 = { + {'1', '1', '0', '0', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '1', '0', '0'}, + {'0', '0', '0', '1', '1'}}; + int numIslands2 = ns.numIslands(grid2); + System.out.println(numIslands2); + } +} diff --git a/Week 03/id_306/NumIslands_dfs.java b/Week 03/id_306/NumIslands_dfs.java new file mode 100644 index 000000000..7abbd7b8a --- /dev/null +++ b/Week 03/id_306/NumIslands_dfs.java @@ -0,0 +1,67 @@ +/** + * Created by LynnSun on 2019/10/28. + * 力扣题目地址:https://leetcode-cn.com/problems/number-of-islands/ + * 深度优先搜索 + */ +public class NumIslands_dfs { + class Point{ + int x; + int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + } + private int[] moveX = {-1, 1, 0, 0},moveY = {0, 0, -1, 1}; + public int numIslands(char[][] grid) { + if (grid == null || grid.length < 1) { + return 0; + } + int count = 0, len1 = grid.length; + + for (int i = 0; i < len1; i++) { + int len2 = grid[i].length; + for (int j = 0; j < len2; j++) { + // 每次返回的岛屿数量总和 + count += dfs(grid, len1, len2, i, j); + } + } + return count; + } + // 深度优先模式,递归方式遍历 + private int dfs(char[][] grid,int len1,int len2,int x,int y) { + if ((!isValid(len1, len2, x, y))||grid[x][y]!='1') { + return 0; + } + grid[x][y] = '0'; + // 循环并递归是否能连成一个岛屿 + for (int i = 0; i < moveX.length; i++) { + dfs(grid,len1, len2, x + moveX[i], y+moveY[i]); + } + return 1; + } + + private boolean isValid(int len1,int len2, int x, int y) { + return x >= 0 && x < len1 && y >= 0 && y < len2; + } + + public static void main(String[] args) { + NumIslands_dfs ns = new NumIslands_dfs(); + char[][] grid1 = { + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'}}; + int numIslands1 = ns.numIslands(grid1); + System.out.println(numIslands1); + + char[][] grid2 = { + {'1', '1', '0', '0', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '1', '0', '0'}, + {'0', '0', '0', '1', '1'}}; + int numIslands2 = ns.numIslands(grid2); + System.out.println(numIslands2); + } +} diff --git a/Week 03/id_306/SearchInRotatedSortedArray.java b/Week 03/id_306/SearchInRotatedSortedArray.java new file mode 100644 index 000000000..ac9cb9ada --- /dev/null +++ b/Week 03/id_306/SearchInRotatedSortedArray.java @@ -0,0 +1,24 @@ +/** + * Created by LynnSun on 2019/11/3. + * 力扣题目地址:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + */ +public class SearchInRotatedSortedArray { + public int search(int[] nums, int target) { + int lo = 0; + int hi = nums.length - 1; + + while (lo < hi) { + int mid = (lo + hi) / 2; + // 当[0,mid]有序时,向后规约条件 + if (nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + lo = mid + 1; + // 当[0,mid]发生旋转时,向后规约条件 + } else if (target > nums[mid] && target < nums[0]) { + lo = mid + 1; + } else { + hi = mid; + } + } + return lo == hi && nums[lo] == target ? lo : -1; + } +} diff --git a/Week 03/id_306/Sqrtx.java b/Week 03/id_306/Sqrtx.java new file mode 100644 index 000000000..14c7da62d --- /dev/null +++ b/Week 03/id_306/Sqrtx.java @@ -0,0 +1,36 @@ +/** + * Created by LynnSun on 2019/11/3. + * 力扣题目地址:https://leetcode-cn.com/problems/sqrtx/ + */ +public class Sqrtx { + public int mySqrt(int x) { + if (x == 0 || x==1) { + return x; + } + // 注意:针对特殊测试用例,例如 2147395599 + // 要把搜索的范围设置成长整型 + long left = 1; + long right = x / 2; + while (left < right) { + // 注意:这里一定取右中位数,如果取左中位数,代码会进入死循环 + // long mid = left + (right - left + 1) / 2; + long mid = (left + right + 1) >>> 1; // 小技巧防越界 + long square = mid * mid; + if (square > x) { + right = mid - 1; + } else { + left = mid; + } + } + // 因为一定存在,因此无需后处理 + return (int) left; + } + + public int mySqrt_ND(int a){ + long x = a; + while (x * x > a) { + x = (x + a / x) / 2; + } + return (int) x; + } +} diff --git a/Week 03/id_306/UpdateBoard.java b/Week 03/id_306/UpdateBoard.java new file mode 100644 index 000000000..ce86cae8d --- /dev/null +++ b/Week 03/id_306/UpdateBoard.java @@ -0,0 +1,73 @@ +/** + * Created by LynnSun on 2019/10/30. + * 力扣题目地址:https://leetcode-cn.com/problems/minesweeper/description/ + */ +public class UpdateBoard { + public char[][] updateBoard(char[][] board, int[] click) { + if (click[0] < 0 || click[1] < 0) return board; + if (click[0] >= board.length || click[1] >= board[0].length) return board; + + int row, col; + row = click[0]; + col = click[1]; + + // Hit a blank, skip + if (board[row][col] == 'B') { + return board; + } + + // Hit a mine, game over + if (board[row][col] == 'M') { + board[row][col] = 'X'; + return board; + } + + // Check for surrounding mines + int mines = checkAdjacent(board, click); + if (mines != 0) { + board[row][col] = (char) (mines + '0'); + return board; + } + + // Totally blank + board[row][col] = 'B'; + // Update all surrounding tiles + for (int i = row-1; i <= row+1; i++) { + for (int j = col-1; j <= col+1; j++) { + board = updateBoard(board, new int[]{i, j}); + } + } + + return board; + } + + private int checkAdjacent(char[][] board, int[] tile) { + int total = 0; + int iMin, iMax, jMin, jMax; + iMin = jMin = 0; + iMax = board.length - 1; + jMax = board[0].length - 1; + + // Start with top left surrounding tile + int startI = tile[0] - 1; + int startJ = tile[1] - 1; + for (int i = startI; i <= startI + 2; i++) { + // skip out of bound indices + if (i < iMin) continue; + if (i > iMax) continue; + + for (int j = startJ; j <= startJ + 2; j++) { + // skip out of bound indices + if (j < jMin) continue; + if (j > jMax) continue; + + // Add all adjacent mines to the list + if (board[i][j] == 'M') { + total++; + } + } + } + + return total; + } +} diff --git a/Week 03/id_306/WalkingRobotSim.java b/Week 03/id_306/WalkingRobotSim.java new file mode 100644 index 000000000..98386386b --- /dev/null +++ b/Week 03/id_306/WalkingRobotSim.java @@ -0,0 +1,39 @@ +import java.util.HashSet; +import java.util.Set; + +/** + * Created by LynnSun on 2019/10/31. + * 力扣题目地址:https://leetcode-cn.com/problems/walking-robot-simulation/description/ + */ +public class WalkingRobotSim { + public int robotSim(int[] commands, int[][] obstacles) { + int[][] dir = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + int x = 0, y=0; + int dir_index=0; + int ans = 0; + Set blockSet = new HashSet(); + for (int i=0;i0) { + for (int j=1;j<=commands[i];j++) { + int next_x = x+ dir[dir_index][0]; + int next_y = y+ dir[dir_index][1]; + if (blockSet.contains(next_x+","+next_y)) { + break; + }else { + x = next_x; + y = next_y; + ans = Math.max(ans, x*x+y*y); + } + } + } + } + return ans; + } +} diff --git a/Week 03/id_311/LeetCode_126_Solution.java b/Week 03/id_311/LeetCode_126_Solution.java new file mode 100644 index 000000000..735d20279 --- /dev/null +++ b/Week 03/id_311/LeetCode_126_Solution.java @@ -0,0 +1,81 @@ +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + List> ans = new ArrayList<>(); + if (!wordList.contains(endWord)) { + return ans; + } + HashMap> map = new HashMap<>(); + bfs(beginWord, endWord, wordList, map); + ArrayList temp = new ArrayList(); + temp.add(beginWord); + findLaddersHelper(beginWord, endWord, map, temp, ans); + return ans; + } + + private void findLaddersHelper(String beginWord, String endWord, HashMap> map, + ArrayList temp, List> ans) { + if (beginWord.equals(endWord)) { + ans.add(new ArrayList(temp)); + return; + } + ArrayList neighbors = map.getOrDefault(beginWord, new ArrayList()); + for (String neighbor : neighbors) { + temp.add(neighbor); + findLaddersHelper(neighbor, endWord, map, temp, ans); + temp.remove(temp.size() - 1); + } + } + + private void bfs(String beginWord, String endWord, List wordList, HashMap> map) { + Set set1 = new HashSet(); + set1.add(beginWord); + Set set2 = new HashSet(); + set2.add(endWord); + Set wordSet = new HashSet(wordList); + bfsHelper(set1, set2, wordSet, true, map); + } + + private boolean bfsHelper(Set set1, Set set2, Set wordSet, boolean direction, + HashMap> map) { + if (set1.isEmpty()) { + return false; + } + if (set1.size() > set2.size()) { + return bfsHelper(set2, set1, wordSet, !direction, map); + } + wordSet.removeAll(set1); + wordSet.removeAll(set2); + + boolean done = false; + + Set set = new HashSet(); + + for (String str : set1) { + for (int i = 0; i < str.length(); i++) { + char[] chars = str.toCharArray(); + for (char ch = 'a'; ch <= 'z'; ch++) { + if (chars[i] == ch) { + continue; + } + chars[i] = ch; + String word = new String(chars); + String key = direction ? str : word; + String val = direction ? word : str; + ArrayList list = map.containsKey(key) ? map.get(key) : new ArrayList(); + if (set2.contains(word)) { + done = true; + list.add(val); + map.put(key, list); + } + if (!done && wordSet.contains(word)) { + set.add(word); + list.add(val); + map.put(key, list); + } + } + } + } + return done || bfsHelper(set2, set, wordSet, !direction, map); + + } +} \ No newline at end of file diff --git a/Week 03/id_311/LeetCode_127_Solution.java b/Week 03/id_311/LeetCode_127_Solution.java new file mode 100644 index 000000000..886df1ddc --- /dev/null +++ b/Week 03/id_311/LeetCode_127_Solution.java @@ -0,0 +1,61 @@ +import javafx.util.Pair; + +import java.util.*; + +class Solution { + private int L = 0; + private Map> allComboDict; + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + L = beginWord.length(); + allComboDict = new HashMap>(); + for (String str : wordList) { + for (int i = 0; i < L; i++) { + String newString = str.substring(0, i) + "*" + str.substring(i + 1, L); + ArrayList transformations = allComboDict.getOrDefault(newString, new ArrayList()); + transformations.add(str); + allComboDict.put(newString, transformations); + } + } + Queue> q_begin = new LinkedList>(); + Queue> q_end = new LinkedList>(); + q_begin.add(new Pair(beginWord, 1)); + q_end.add(new Pair(endWord, 1)); + Map vistedBegin = new HashMap(); + vistedBegin.put(beginWord, 1); + Map vistedEnd = new HashMap(); + vistedEnd.put(endWord, 1); + while(!q_begin.isEmpty() && !q_end.isEmpty()){ + int ans = vistedCount(q_begin, vistedBegin, vistedEnd); + if(ans > -1){ + return ans; + } + ans = vistedCount(q_end, vistedEnd, vistedBegin); + if(ans > -1){ + return ans; + } + } + return 0; + + } + private int vistedCount(Queue> queue, Map visted, Map otherVisted){ + Pair node = queue.remove(); + String str = node.getKey(); + int level = node.getValue(); + for (int i = 0; i < L; i++) { + String newString = str.substring(0, i) + "*" + str.substring(i + 1, L); + for(String adjacentWord : allComboDict.getOrDefault(newString, new ArrayList<>())){ + if(otherVisted.containsKey(adjacentWord)){ + return level + otherVisted.get(adjacentWord); + } + if(!visted.containsKey(adjacentWord)){ + visted.put(adjacentWord, level + 1); + queue.add(new Pair(adjacentWord, level +1)); + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_321/LeetCode_122_321.java b/Week 03/id_321/LeetCode_122_321.java new file mode 100644 index 000000000..bc1aa92b6 --- /dev/null +++ b/Week 03/id_321/LeetCode_122_321.java @@ -0,0 +1,28 @@ +package week03; + +public class MaxProfit122 { +//޴ + //1̬滮 + public int maxProfit_k_inf(int[] prices) { + int n = prices.length; + int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE; + for (int i = 0; i < n; i++) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, temp - prices[i]); + } + return dp_i_0; + } + //2ֻҪڶȵһߵͿ + public int maxProfit2(int[] prices) { + int maxprofit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) + maxprofit += prices[i] - prices[i - 1]; + } + return maxprofit; + } + + + +} diff --git a/Week 03/id_321/LeetCode_200_321.java b/Week 03/id_321/LeetCode_200_321.java new file mode 100644 index 000000000..dcf4887ef --- /dev/null +++ b/Week 03/id_321/LeetCode_200_321.java @@ -0,0 +1,46 @@ +package week03; + +public class NumIslands200 { +/* + * 1.dfsÿ1½ʱ++ͬʱԪΧ½0 + */ + public static void main(String[] args) { + // TODO Զɵķ + + } + + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int sum = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++sum; + dfs(grid, r, c); + } + } + } + + return sum; + } +} diff --git a/Week 03/id_321/LeetCode_33_321(2).java b/Week 03/id_321/LeetCode_33_321(2).java new file mode 100644 index 000000000..c07216a5d --- /dev/null +++ b/Week 03/id_321/LeetCode_33_321(2).java @@ -0,0 +1,37 @@ +package week03; + +public class Search33 { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + int start = 0; + int end = nums.length - 1; + int mid; + while (start <= end) { + mid = start + (end - start) / 2; + if (nums[mid] == target) { + return mid; + } + + if (nums[start] <= nums[mid]) { + + if (target >= nums[start] && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + } else { + if (target <= nums[end] && target > nums[mid]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + + } + return -1; + + } + +} diff --git a/Week 03/id_321/LeetCode_455_321.java b/Week 03/id_321/LeetCode_455_321.java new file mode 100644 index 000000000..842bceb29 --- /dev/null +++ b/Week 03/id_321/LeetCode_455_321.java @@ -0,0 +1,26 @@ +package week03; + +import java.util.Arrays; + +public class FindContentChildren455 { + //̰ĵ˼ǣþСıȥСĺӣҪ + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int sum = 0; + int leng = 0, lens = 0; + + while (leng < g.length && lens < s.length) { + if (s[lens] >= g[leng]) { + leng++; + lens++; + sum++; + } else { + lens++; + } + + } + return sum; + + } +} diff --git a/Week 03/id_321/LeetCode_55_321.java b/Week 03/id_321/LeetCode_55_321.java new file mode 100644 index 000000000..0f320cea6 --- /dev/null +++ b/Week 03/id_321/LeetCode_55_321.java @@ -0,0 +1,44 @@ +package week03; + +public class CanJump55 { +//̰ģ + public boolean canJump(int[] nums) { + if (nums == null) { + return false; + } + // posʾҪλ + int pos = nums.length - 1; + for (int i = nums.length - 2; i >= 0; i--) { + if (nums[i] + i >= pos) { + pos = i; + } + + } + return pos == 0; + + } + + // ˳ƣٶȱȽ + public boolean canJump1(int[] nums) { + + if (nums == null) { + return false; + } + int len = nums.length; + boolean[] dp = new boolean[len]; + dp[0] = true; + for (int i = 0; i < len - 1; i++) { + if (dp[i]) { + for (int j = i; j < len && j <= i + nums[i]; j++) { + dp[j] = true; + + } + + } + + } + return dp[len - 1]; + + } + +} diff --git a/Week 03/id_331/LeetCode_122_331.java b/Week 03/id_331/LeetCode_122_331.java new file mode 100644 index 000000000..8d4180aa4 --- /dev/null +++ b/Week 03/id_331/LeetCode_122_331.java @@ -0,0 +1,13 @@ +class Solution { + + public int maxProfit(int[] prices) { + int maxprofit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + maxprofit += prices[i] - prices[i - 1]; + } + } + + return maxprofit; + } +} \ No newline at end of file diff --git a/Week 03/id_331/LeetCode_860_331.java b/Week 03/id_331/LeetCode_860_331.java new file mode 100644 index 000000000..a6c3075da --- /dev/null +++ b/Week 03/id_331/LeetCode_860_331.java @@ -0,0 +1,30 @@ +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/Week 03/id_331/NOTE.md b/Week 03/id_331/NOTE.md index a6321d6e2..1d8787624 100644 --- a/Week 03/id_331/NOTE.md +++ b/Week 03/id_331/NOTE.md @@ -2,3 +2,149 @@ +#### DFS代码 - 递归写法 + +```java +visited = set() + +def dfs(node, visited): +if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + + + +``` + + + +#### DFS代码 - 非递归写法 + +```java +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... +``` + + + +#### BFS 代码模块 + +```java +def BFS(graph, start, end): + + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... +``` + + + +#### 贪心算法 Greedy + +##### 定义 + +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 + + + +##### 适用贪心算法的场景 + +简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。 + + + +#### 二分查找 + +##### 前提 + +- 目标函数单调性(单调递增或递减) +- 存在上下界 +- 能够通过索引访问 + + + +##### 代码模板 + +```java +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + + + +##### 课后习题 + +> 使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +```java +class Solution { + + //思路: + //1.直接套用代码模板,先将left,right,mid三个指针找到。 + //2.如果nums[mid]大于nums[right],说明右端无序,将left指针移动到mid+1 + //3.如果nums[mid]小于nums[right],说明左端无序,将right指针移动到mid+1 + //4.当left > right,取nums[left] + public int search(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + + int left = 0; + int right = nums.length - 1; + int mid; + while (left <= right) { + mid = (left + right) / 2; + + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return nums[left]; + } +} +``` + diff --git a/Week 03/id_336/LeetCode_336_122.js b/Week 03/id_336/LeetCode_336_122.js new file mode 100644 index 000000000..94eacaf9f --- /dev/null +++ b/Week 03/id_336/LeetCode_336_122.js @@ -0,0 +1,59 @@ +// #### 解法一:暴力枚举 +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + return calc(prices,prices.length,0) +}; +function calc(prices,len,start){ + if(start >= len){ + return 0; + } + var max = 0; + for(var startIndex = start;startIndex prices[startIndex]){ + // 当前剩余价值+当前价值-第一天起始点价值 == 当前组合的总价值 + var profit = calc(prices,len,i+1) + prices[i] - prices[startIndex]; + // 更新当天与第i天 最大价值和 + if(profit > maxProfit){ + maxProfit = profit; + } + } + } + // 更新每天价值最大值的和 + if(maxProfit > max){ + max = maxProfit; + } + } + return max; +} +// #### 解法二 +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + // 谷值 + var valley = prices[0]; + // 峰值 + var peak = prices[0]; + // 最大利润值 + var maxProfit = 0; + var lenNeed = prices.length - 1; + var i = 0; + while(i < lenNeed){ + while(i < lenNeed && prices[i] > prices[i+1]){ + i++; + } + valley = prices[i]; + while(i < lenNeed && prices[i] <= prices[i+1]){ + i++; + } + peak = prices[i]; + maxProfit += peak - valley; + } + return maxProfit; +}; \ No newline at end of file diff --git a/Week 03/id_336/LeetCode_336_200.js b/Week 03/id_336/LeetCode_336_200.js new file mode 100644 index 000000000..a253f5013 --- /dev/null +++ b/Week 03/id_336/LeetCode_336_200.js @@ -0,0 +1,94 @@ +// #### 解法一:DFS +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + if(!grid || grid.length == 0){ + return 0; + } + var len = grid.length; + var size = grid[0].length; + var island = 0; + function sink(i,j){ + // terminator + if(grid[i][j] == '0'){ + return 0; + } + // process + grid[i][j] = '0'; + // drill down + if(i+1= 0 && grid[i-1][j] == '1'){ + sink(i-1,j); + } + if(j+1 < size && grid[i][j+1] == '1'){ + sink(i,j+1); + } + if(j-1 >= 0 && grid[i][j-1] == '1'){ + sink(i,j-1); + } + return 1; + } + for(var i = 0;i= 0 && x < grid.length && y >=0 && y0){ + var tmpIsland = queue.shift(); + sink(tmpIsland[0],tmpIsland[1]); + } + } + } + } + return island; +}; \ No newline at end of file diff --git a/Week 03/id_336/LeetCode_336_45.js b/Week 03/id_336/LeetCode_336_45.js new file mode 100644 index 000000000..f1d6429f1 --- /dev/null +++ b/Week 03/id_336/LeetCode_336_45.js @@ -0,0 +1,22 @@ +// #### 解法:贪心算法 +/** + * @param {number[]} nums + * @return {number} + */ +var jump = function(nums) { + var steps = 0; + var canJumpMax = 0; + var last_canJumpMax = 0; + var len = nums.length; + for(var i = 0;i= len-1){ + break; + } + } + return steps; +}; \ No newline at end of file diff --git a/Week 03/id_336/LeetCode_336_55.js b/Week 03/id_336/LeetCode_336_55.js new file mode 100644 index 000000000..673350c89 --- /dev/null +++ b/Week 03/id_336/LeetCode_336_55.js @@ -0,0 +1,40 @@ +// 解法一:暴力递归 +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function(nums) { + function canJumpFromWhere(position,nums){ + // 跳到终点了 + if(position == nums.length - 1){ + return true; + } + // 当前位置可跳的最远距离索引位置,取min是因为最远距离不能超过nums的长度对应的索引值 + var furthestPosition = Math.min(position+nums[position],nums.length - 1); + for(var nextPosition = position+1;nextPosition <= furthestPosition;nextPosition++){ + if(canJumpFromWhere(nextPosition,nums)){ + return true; + } + } + return false; + } + return canJumpFromWhere(0,nums); +}; +// 解法二:贪心算法 +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function(nums) { + var canJumpMax = 0; + var len = nums.length; + for(var i = 0;i canJumpMax){ + return false; + } + canJumpMax = Math.max(canJumpMax,i+nums[i]); + if(canJumpMax >= len-1){ + return true; + } + } +}; \ No newline at end of file diff --git a/Week 03/id_336/LeetCode_336_860.js b/Week 03/id_336/LeetCode_336_860.js new file mode 100644 index 000000000..85396249c --- /dev/null +++ b/Week 03/id_336/LeetCode_336_860.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function(bills) { + var five = 0; + var ten = 0; + var len = bills.length; + for(var i = 0;i 0 && five > 0){ + ten--; + five--; + }else if(five >= 3){ + five -= 3; + }else{ + return false; + } + } + } + return true; +}; \ No newline at end of file diff --git a/Week 03/id_346/LeetCode_200_346.java b/Week 03/id_346/LeetCode_200_346.java new file mode 100644 index 000000000..0a946d5ae --- /dev/null +++ b/Week 03/id_346/LeetCode_200_346.java @@ -0,0 +1,37 @@ +/** + * @auther: TKQ + * @Title: LeetCode_200_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-03 14:04 + */ +public class LeetCode_200_346 { + private int n; + private int m; + + public int numIslands(char[][] grid) { + int count = 0; + n = grid.length; + if (n == 0) {return 0;} + m = grid[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + DFSMarking(grid, i, j); + ++count; + } + } + } + return count; + } + + private void DFSMarking(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') {return;} + grid[i][j] = '0'; + DFSMarking(grid, i + 1, j); + DFSMarking(grid, i - 1, j); + DFSMarking(grid, i, j + 1); + DFSMarking(grid, i, j - 1); + } +} diff --git a/Week 03/id_346/LeetCode_529_346.java b/Week 03/id_346/LeetCode_529_346.java new file mode 100644 index 000000000..e3b1b065e --- /dev/null +++ b/Week 03/id_346/LeetCode_529_346.java @@ -0,0 +1,45 @@ +/** + * @auther: TKQ + * @Title: LeetCode_529_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-03 14:20 + */ +public class LeetCode_529_346 { + public char[][] updateBoard(char[][] board, int[] click) { + int m = board.length, n = board[0].length; + int row = click[0], col = click[1]; + + if (board[row][col] == 'M') { // Mine + board[row][col] = 'X'; + } else { // Empty + // Get number of mines first. + int count = 0; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + + if (count > 0) { // If it is not a 'B', stop further DFS. + board[row][col] = (char) (count + '0'); + } else { // Continue DFS to adjacent cells. + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'E') updateBoard(board, new int[]{r, c}); + } + } + } + } + + return board; + } +} diff --git a/Week 03/id_361/NOTE.md b/Week 03/id_361/NOTE.md index a6321d6e2..384688c1d 100644 --- a/Week 03/id_361/NOTE.md +++ b/Week 03/id_361/NOTE.md @@ -1,4 +1,60 @@ -# NOTE - +### 1.深度优先搜索 广度优先搜索 +#### 1.1 搜索-遍历 + + - 每个节点都要访问一次 + - 每个节点仅访问一次 + +- 深度优先:depth first search + - [模板](https://shimo.im/docs/ddgwCccJQKxkrcTq/read) +- 广度优先:breath first search搜索:暴力、简单朴素 + - [模板](https://shimo.im/docs/P8TqKHGKt3ytkYYd/read) +- 其他优先:比如从中间优先 +- 在树图中寻找特定点 + +- 案例: + - 深度优先:递归、遍历 + - 广度优先:队列 + - 广度优先实例:水波纹、地震。 更符合人脑裂解 + +#### 1.2 应用 +- java:链表 link 、双端队列deque + +- python:高性能connection库的deque + + + +- 启发式搜索:抖音、快手 + +#### 1.3 实战、高频 +- 二叉树的层次遍历 +- 岛屿数量:bfs dfs 并查集 flood fill + +### 2.贪心算法 Greedy +#### 2.1 前提 +- 能证明用贪心能得到全局最优解 +- 从后往前、从局部贪心 + +#### 2.2 与回溯、动态规划对比 +- 贪心:当下做局部最优判断 +- 回溯:能够回退 +- 动态规划:最优判断+回退 + +#### 2.3 实战 +- 硬币法 + + +### 3.二分查找 [模板](https://shimo.im/docs/hjQqRQkGgwd9g36J/read) + +#### 3.1 二分查找前提 + +- 目标函数单调性(单调递增或递减) +- 存在上下界(bounded) +- 能够通过索引访问(index accessible) + + + + +#### 3.实战 高频 +- 平方根: 二分、牛顿迭代法 diff --git a/Week 03/id_361/leetCode_153_361.js b/Week 03/id_361/leetCode_153_361.js new file mode 100644 index 000000000..831bde889 --- /dev/null +++ b/Week 03/id_361/leetCode_153_361.js @@ -0,0 +1,58 @@ +//153. 寻找旋转排序数组中的最小值 +//https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + + +/** + *1.二分法 + * @param nums + * @returns {number|*} + */ +var findMin = function (nums) { + var len = nums.length; + if (len == 0) { + return 0; + } + var left = 0; + var right = len - 1; + while (left < right) { + // int mid = left + (right - left) / 2; + var mid = (left + right) >>> 1; + if (nums[mid] > nums[right]) { + left = mid + 1; + } else if (nums[mid] < nums[right]) { + right = mid; + } else { + assert + nums[mid] == nums[right]; + right--; + } + } + return nums[left]; +} + + + +/** + *2.分治法 + * @param nums + * @returns {number|*} + */ +var findMin = function (nums) { + var len = nums.length; + if (len == 0) { + throw new Error("数组为空,最小值不存在"); + } + return helper(nums, 0, len - 1); +} + +var helper = function (nums, left, right) { + if (left + 1 >= right) { + return Math.min(nums[left], nums[right]); + } + if (nums[left] < nums[right]) { + return nums[left]; + } + // int mid = left + (right - left) / 2; + var mid = (left + right) >>> 1; + return Math.min(helper(nums, left, mid - 1), helper(nums, mid, right)); +} diff --git a/Week 03/id_361/leetCode_200_361.js b/Week 03/id_361/leetCode_200_361.js new file mode 100644 index 000000000..fafe4e023 --- /dev/null +++ b/Week 03/id_361/leetCode_200_361.js @@ -0,0 +1,104 @@ +//leetCode 200. 岛屿数量 + + +/** + * 解法1:DFS flood fill + * 时间复杂度 :O(M×N),其中 MM 和 NN 分别为行数和列数。 + * 空间复杂度 :O(M×N),此时整个网格均为陆地,深度优先搜索的深度达到 M×N + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function (grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + var nr = grid.length; + var nc = grid[0].length; + var num_islands = 0; + for (var r = 0; r < nr; ++r) { + for (var c = 0; c < nc; ++c) { + if ('1' === grid[r][c]) { //if 1 begin dfs + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; +} + +/** + * dfs算法 + * @param grid + * @param r + * @param c + */ +function dfs(grid, r, c) { + var nr = grid.length; + var nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + grid[r][c] = '0'; // flood fill + //4 directions + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); +} + +//////////////////////////////////////////////////////////////////////////// +/** + * 解法2:DFS + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + if(!grid || grid.length == 0){ + return 0; + } + var len = grid.length; + var size = grid[0].length; + var island = 0; + // 从右到左 队列 + var queue = []; + // 方向向量 + var dx = [-1,1,0,0]; + var dy = [0,0,-1,1]; + // dfs 推平 + function sink(i,j){ + // terminator + if(grid[i][j] == '0'){ + return 0; + } + // process + grid[i][j] = '0'; + // drill down + for(var k = 0;k< dx.length;k++){ + var x = i + dx[k]; + var y = j + dy[k]; + if(x >= 0 && x < grid.length && y >=0 && y0){ + var tmpIsland = queue.shift(); + sink(tmpIsland[0],tmpIsland[1]); + } + } + } + } + return island; +}; + diff --git a/Week 03/id_366/Leetcode_127_366.java b/Week 03/id_366/Leetcode_127_366.java new file mode 100644 index 000000000..210ddcac2 --- /dev/null +++ b/Week 03/id_366/Leetcode_127_366.java @@ -0,0 +1,46 @@ +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ + +// @lc code=start +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Map map = new HashMap<>(); + for (int i = 0; i < wordList.size(); i++) { + map.put(wordList.get(i), wordList.get(i)); + } + if ( !map.containsKey(endWord)) return 0; + //Queue queue = new ArrayList(); ArrayList没有实现Queue + Queue queue = new LinkedList(); + queue.offer(beginWord); + int ladder = 1; + while (queue.size() != 0) { + int n = queue.size(); + for (int i = 0; i < n; i++) { + String processWord = queue.poll(); + char[] chars = processWord.toCharArray(); + if(processWord.equals(endWord)){ + return ladder; + } + map.remove(processWord); + for (int j = 0; j < chars.length; j++) { + char currentChar = chars[j]; + for (char c = 'a'; c <= 'z'; c++) { + chars[j] = c; + String temp = String.valueOf(chars); + if (map.containsKey(temp) && map.get(temp) != endWord) { + queue.offer(temp); + } + } + chars[j] = currentChar; + } + } + ladder ++; + } + return 0; + } +} +// @lc code=end + diff --git a/Week 03/id_366/Leetcode_200_366.java b/Week 03/id_366/Leetcode_200_366.java new file mode 100644 index 000000000..0ea747423 --- /dev/null +++ b/Week 03/id_366/Leetcode_200_366.java @@ -0,0 +1,46 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @lc code=start +/** + * 方法一:深度优先遍历 + */ +class Solution { + char[][] grid; + int rows; + int cols; + + public int numIslands(char[][] grid) { + this.grid = grid; + if (grid.length == 0) return 0; + //if (gird == null || grid.length == 0) return 0; + rows = grid.length; + cols = grid[0].length; + int countNum = 0; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + countNum += sink(i, j); + } + } + return countNum; + } + + public int sink(int i, int j) { + if (i < 0 || i >= rows || j < 0 || j >= cols || grid[i][j] == '0') { + return 0; + } + grid[i][j] = '0'; + sink(i-1, j); + sink(i+1, j); + sink(i, j+1); + sink(i, j-1); + return 1; + } + +} + +// @lc code=end + diff --git a/Week 03/id_366/Leetcode_33_366.java b/Week 03/id_366/Leetcode_33_366.java new file mode 100644 index 000000000..9b561685e --- /dev/null +++ b/Week 03/id_366/Leetcode_33_366.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=33 lang=java + * + * [33] 搜索旋转排序数组 + */ + +// @lc code=start +class Solution { + public int search(int[] nums, int target) { + if (nums == null || nums.length ==0) return -1; + int lo = 0; + int hi = nums.length - 1; + + while (lo <= hi) { + int mid = lo + (hi - lo)/2; + if (nums[mid] == target) return mid; + //前半部分递增 + if (nums[lo] <= nums[mid]) { + //target在前半部分 + if (target >= nums[lo] && target < nums[mid]) { + hi = mid - 1; + } else { + lo = mid + 1; + } + } else { //前半部分含旋转 + //target在后半部分 + if (target > nums[mid] && target <= nums[hi]) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + } + return -1; + } +} +// @lc code=end + diff --git a/Week 03/id_366/Leetcode_860_366.java b/Week 03/id_366/Leetcode_860_366.java new file mode 100644 index 000000000..80d484e89 --- /dev/null +++ b/Week 03/id_366/Leetcode_860_366.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + */ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten =0; + for (int i:bills) { + if (i == 5) { //顾客付5元 + five++; + }else if (i == 10) { //顾客付10元 + ten++; + five--; + } else if (ten > 0) { //顾客付20元,并且我们有10块零钱可以找零 + ten--; + five--; + } else { //顾客付20元,但是我们没有10块零钱可以找零 + five -= 3; + } + if (five < 0) return false; + } + return true; + } +} +// @lc code=end + diff --git a/Week 03/id_371/Leetcode0_127_371.java b/Week 03/id_371/Leetcode0_127_371.java new file mode 100644 index 000000000..d93781f77 --- /dev/null +++ b/Week 03/id_371/Leetcode0_127_371.java @@ -0,0 +1,160 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-29 22:22 + **/ + +public class Leetcode0_127_371 { + + public static void main(String[] args) { + String beginWord = "hit"; + String endWord = "cog"; +// List wordList = Arrays.asList("hot","dot","dog","lot","log"); + List wordList = Arrays.asList("hot", "dot", "dog", "lot", "log", "cog"); + int i = ladderLength3(beginWord, endWord, wordList); + System.out.println("i = " + i); + } + + + /** + * 仿解2:(双向 BFS 优化:优化掉了 visited;以前的思路是记录访问的节点,现在是直接删除访问的节点,而下一轮要遍历的一度关系节点都已经保存在beginSet 容器合 endSet 容器中了) + * + * @author Shaobo.Qian + * @date 2019/10/30 + */ + public static int ladderLength3(String beginWord, String endWord, List wordAsList) { + //0.边界处理 + if (!wordAsList.contains(endWord)) return 0; + //1.定义容器,变量 + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + Set wordList = new HashSet<>(wordAsList); + beginSet.add(beginWord); + endSet.add(endWord); + int step = 1; + wordList.remove(beginWord); + wordList.remove(endWord); + //2.每次选择较小的那一层,对该层进行遍历 + while (!beginSet.isEmpty()) { + step++; + Set nextSet = new HashSet<>(); + //3.对当前层节点进行遍历 + for (String currWord : beginSet) { + char[] chars = currWord.toCharArray(); + for (int i = 0; i < currWord.length(); i++) { + + for (char c = 'a'; c < 'z'; c++) { + char old = chars[i]; + chars[i] = c; + String targetStr = String.valueOf(chars); + if (endSet.contains(targetStr)) return step; + if (wordList.contains(targetStr)) { + //4.生成下一层元素 + nextSet.add(targetStr); + wordList.remove(targetStr); + } + chars[i] = old; + } + } + } + + beginSet = nextSet.size() < endSet.size() ? nextSet : endSet; + endSet = beginSet.size() < endSet.size() ? endSet : nextSet; + } + return 0; + } + + /** + * 仿解1:(双向 BFS) + * + * @author Shaobo.Qian + * @date 2019/10/30 + */ + public static int ladderLength2(String beginWord, String endWord, List wordList) { + //0.边界处理 + if (!wordList.contains(endWord)) return 0; + //1.定义容器,变量 + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + Set visited = new HashSet<>(); + beginSet.add(beginWord); + endSet.add(endWord); + int step = 0; + //2.每次选择较小的那一层,对该层进行遍历 + while (!beginSet.isEmpty()) { + step++; + if (endSet.size() < beginSet.size()) { + Set set = beginSet; + beginSet = endSet; + endSet = set; + } + Set tempSet = new HashSet<>(); + //3.对当前层节点进行遍历 + for (String word : beginSet) { + char[] chars = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + for (char c = 'a'; c < 'z'; c++) { + char old = chars[i]; + chars[i] = c; + String targetStr = String.valueOf(chars); + if (endSet.contains(targetStr)) return step + 1; + if (!visited.contains(targetStr) && wordList.contains(targetStr)) { + visited.add(targetStr); + tempSet.add(targetStr); + } + chars[i] = old; + } + } + } + + beginSet = tempSet; + } + return 0; + } + + + /** + * 原解1:最短路径问题(BFS) + * + * @author Shaobo.Qian + * @date 2019/10/30 + */ + public static int ladderLength1(String beginWord, String endWord, List wordList) { + //0.边界处理 + if (wordList == null || wordList.size() == 0) return 0; + if (!wordList.contains(endWord)) return 0; + //1.创建各种容器 + Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.add(beginWord); + int step = 0; + while (!queue.isEmpty()) { + step++; + //2.确定每次BFS 的宽度 + int count = queue.size(); + while (count-- > 0) { + //3.处理当前节点 + String curr = queue.poll(); + if (!visited.contains(curr)) { + visited.add(curr); + for (String wordStr : wordList) { + int diff = 0; + for (int i = 0; i < curr.length(); i++) { + if (curr.charAt(i) != wordStr.charAt(i)) diff++; + } + if (diff == 1) { + //4.找到新节点,放入队列 + if (endWord.equals(wordStr)) return step + 1; + queue.add(wordStr); + } + } + } + } + } + + return 0; + } +} diff --git a/Week 03/id_371/Leetcode_102_371.java b/Week 03/id_371/Leetcode_102_371.java new file mode 100644 index 000000000..314f30877 --- /dev/null +++ b/Week 03/id_371/Leetcode_102_371.java @@ -0,0 +1,84 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-29 08:42 + **/ + +public class Leetcode_102_371 { + + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + this.val = val; + } + } + + + /** + * 原解2:迭代,广度优先搜索 + * + * @param root + * @return + */ + public List> levelOrder2(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + Queue queue = new LinkedList<>(); + queue.add(root); + while (queue != null) { + List list = new ArrayList<>(); + int count = queue.size(); + while (count-- > 0) {//保证将当前层的元素在内循环中全部消耗掉 + //处理当前逻辑 + TreeNode curr = queue.poll(); + list.add(curr.val); + if (curr.left != null) queue.add(curr.left); + if (curr.right != null) queue.add(curr.right); + } + result.add(list); + } + + return result; + } + + /** + * 原解1:递归,广度优先搜索 + * + * @param root + * @return + */ + public List> levelOrder1(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + recur(root, 0, result); + return result; + } + + private void recur(TreeNode root, int level, List> result) { + //1.递归出口 + if (root == null) return; + + //2.处理当前层 + if (level + 1 > result.size()) {//保证每一层的元素加入对应层的容器`` + result.add(new ArrayList<>()); + } + List list = result.get(level); + list.add(root.val); + //3.带上参数,去下一层 + if (root.left != null) recur(root.left, level + 1, result); + if (root.right != null) recur(root.right, level + 1, result); + //4.清理当前层 + } +} diff --git a/Week 03/id_371/Leetcode_122_371.java b/Week 03/id_371/Leetcode_122_371.java new file mode 100644 index 000000000..0e2095870 --- /dev/null +++ b/Week 03/id_371/Leetcode_122_371.java @@ -0,0 +1,108 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-01 07:57 + **/ + +public class Leetcode_122_371 { + + public static void main(String[] args) { +// int[] prices = {7, 6, 4, 3, 1}; +// int[] prices = {1, 2, 3, 4, 5}; +// int[] prices = {1, 2, 5, 3, 4}; + int[] prices = {1,2,3,4,5}; + int profit = maxProfit3(prices); + System.out.println(profit); + } + + /** + * 仿解4:dp + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int maxProfit4(int[] prices) { + int n = prices.length; + if (n <= 1) return 0; +// int[][] dp = new int[n][2]; +// dp[0][0] = 0; + int dp_i_0 = 0; +// dp[0][1] = Integer.MIN_VALUE; + int dp_i_1 = Integer.MIN_VALUE; + for (int i = 0; i < n; i++) { +// dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, temp - prices[i]); +// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + } + return dp_i_0; + } + + /** + * 仿解3:dp + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int maxProfit3(int[] prices) { + int n = prices.length; + if (n <= 1) return 0; + int[][] dp = new int[n][2]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + for (int i = 1; i < n; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + } + return dp[n - 1][0]; + } + + /** + * 原解2:累加每段上升的利润 + * + * @author Shaobo.Qian + * @date 2019/11/1 + */ + public static int maxProfit2(int[] prices) { + if (prices.length == 0 || prices.length == 1) return 0; + int sum = 0; + int min = 0; + int max = 0; + boolean flag = true;//是否处于上升 + for (int i = 1; i < prices.length; i++) { + if (prices[i] < prices[i - 1]) { + if (flag && max > min) { + sum += (prices[max] - prices[min]); + } + min = i; + flag = false; + } else { + flag = true; + max = i; + } + if (flag && i == prices.length - 1 && (max > min)) { + sum += (prices[max] - prices[min]); + } + } + return sum; + } + + /** + * 原解1:暴力法 + * + * @author Shaobo.Qian + * @date 2019/11/1 + */ + public static int maxProfit1(int[] prices) { + if (prices.length == 0 || prices.length == 1) return 0; + int profit = 0; + //22比较,当后面的数大于前面的数就产生了利润 + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) profit += (prices[i] - prices[i - 1]); + } + return profit; + } + +} diff --git a/Week 03/id_371/Leetcode_126_371.java b/Week 03/id_371/Leetcode_126_371.java new file mode 100644 index 000000000..55073d40d --- /dev/null +++ b/Week 03/id_371/Leetcode_126_371.java @@ -0,0 +1,120 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-31 07:35 + **/ + +public class Leetcode_126_371 { + public static void main(String[] args) { + String beginWord = "hit"; + String endWord = "cog"; + List wordList = Arrays.asList("hot", "dot", "dog", "lot", "log", "cog"); + List> res = findLadders(beginWord, endWord, wordList); + res.stream().forEach(System.out::println); + } + + /** + * 仿解1(BFS+DFS) + * @author Shaobo.Qian + * @date 2019/10/31 + */ + public static List> findLadders(String beginWord, String endWord, List wordList) { + //0.处理边界情况 + Set dict = new HashSet<>(wordList); + List> result = new ArrayList<>(); + if(!wordList.contains(endWord)) return result; + //1.记录每个节点的所有邻居节点 + Map> nodeNeighbors = new HashMap<>(); + //2.记录每个节点到起点的最短路径 + Map distance = new HashMap<>(); + + //从起点到终点的路径 + ArrayList path = new ArrayList<>(); + dict.add(beginWord); + bfs(beginWord, endWord, dict, nodeNeighbors, distance); + dfs(beginWord, endWord, dict, nodeNeighbors, distance, path, result); + return result; + } + + private static void dfs(String currWord, String endWord, Set dict, Map> nodeNeighbors, Map distance, ArrayList path, List> result) { + //1.递归出口(当没有下一层为被访问的节点时,递归结束) + //2.处理当前层 + path.add(currWord); + if (endWord.equals(currWord)) { + result.add(new ArrayList<>(path)); + } else { + List neighbors = nodeNeighbors.get(currWord); + for (String nextWord : neighbors) { + //3.带上参数,去下一层 + if (distance.get(currWord) + 1 == distance.get(nextWord)) {//确保是当前节点的下一层,因为邻点也包括它的父节点 + dfs(nextWord, endWord, dict, nodeNeighbors, distance, path, result); + } + } + + } + //4.清理当前层数据 ---> 每一条路径在处理完时(只要走完,无论是否找到终点)需要清除, 因为path容器是所有容器共享的 + path.remove(path.size() - 1); + } + + private static void bfs(String beginWord, String endWord, Set dict, Map> nodeNeighbors, Map distance) { + for (String str : dict) { + nodeNeighbors.put(str, new ArrayList()); + } + + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + distance.put(beginWord, 0);//起点与起点之间的距离为0 + boolean foundEnd = false; //如果在当前层找到 endstr + while (!queue.isEmpty()) { + int count = queue.size(); + for (int i = 0; i < count; i++) { + //获取当前节点 + String curr = queue.poll(); + //起点到当前节点的距离 + int currDistance = distance.get(curr); + //找到邻居节点(下一层节点),并记录当前节点到起点的最短 + ArrayList neighbors = getNeighbor(curr, dict); + for (String neighbor : neighbors) { + nodeNeighbors.get(curr).add(neighbor); + if (!distance.containsKey(neighbor)) {//check if visited 该节点 + distance.put(neighbor, currDistance + 1); + if (endWord.equals(neighbor)) { + foundEnd = true; + } else { + queue.offer(neighbor); + } + } + } + if (foundEnd) break;//从当前节点所在层去往终点只有一条路径,所以跳出循环,不需要在当前层找了 + } + + } + } + + /** + * 找到当前节点的下一层节点 + * + * @param curr + * @param dict + * @return + */ + private static ArrayList getNeighbor(String curr, Set dict) { + ArrayList res = new ArrayList<>(); + char[] chs = curr.toCharArray(); + for (char ch = 'a'; ch < 'z'; ch++) { + for (int i = 0; i < chs.length; i++) { + if (ch == chs[i]) continue; + char old = chs[i]; + chs[i] = ch; + if (dict.contains(String.valueOf(chs))) res.add(String.valueOf(chs)); + chs[i] = old; + } + } + return res; + } + + +} diff --git a/Week 03/id_371/Leetcode_153_371.java b/Week 03/id_371/Leetcode_153_371.java new file mode 100644 index 000000000..1e18fda08 --- /dev/null +++ b/Week 03/id_371/Leetcode_153_371.java @@ -0,0 +1,40 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-03 11:54 + **/ + +public class Leetcode_153_371 { + public static void main(String[] args) { + int[] nums = {3, 4, 5, 6, 7,0, 1, 2}; + int min = findMin(nums); + System.out.println("min = " + min); + } + + /** + * 原解1:二分查找(每次确定剩下空间的最小值,和之前已确定的空间最小值进行比较) + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + + int min = nums[0]; + while (left <= right) { + int mid = left + (right - left) / 2; + //1.左边有序,记录左边最小值, 继续在右边搜索 + if (nums[mid] >= nums[0]) { + min = Math.min(min, nums[left]); + left = mid + 1; + } else { + //2.右边有序,记录右边的最小值,继续在左边搜索 + min = Math.min(min, nums[mid]); + right = mid - 1; + } + } + return min; + } + +} diff --git a/Week 03/id_371/Leetcode_200_371.java b/Week 03/id_371/Leetcode_200_371.java new file mode 100644 index 000000000..fbf99d21a --- /dev/null +++ b/Week 03/id_371/Leetcode_200_371.java @@ -0,0 +1,55 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-31 12:02 + **/ + +public class Leetcode_200_371 { + public static void main(String[] args) { + char[][] grid = {{'1', '0', '1', '1', '0', '1', '1'}}; + int count = numIslands(grid); + System.out.println("count = " + count); + + } + + /** + * 原解1:DFS + * + * @param grid + * @return + */ + public static int numIslands(char[][] grid) { + //把1变为0需要多少次 + int count = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + count++; + zeroGrid(i, j, grid); + } + } + } + return count; + } + + private static void zeroGrid(int i, int j, char[][] grid) { + int nLine = grid.length; + int nColumn = grid[0].length; + //1.递归出口 + if (i < 0 || j < 0 || i >= nLine || j >= nColumn || grid[i][j] == '0') return; + //2.处理当前层 + grid[i][j] = '0'; + //3.带上参数去下一层 + //同一层,向左 + zeroGrid(i, j - 1, grid); + //同一层,向右 + zeroGrid(i, j + 1, grid); + //同一列,向上 + zeroGrid(i - 1, j, grid); + //同一列,向下 + zeroGrid(i + 1, j, grid); + //4.清理当前层 + } + +} diff --git a/Week 03/id_371/Leetcode_322_371.java b/Week 03/id_371/Leetcode_322_371.java new file mode 100644 index 000000000..6aedc4652 --- /dev/null +++ b/Week 03/id_371/Leetcode_322_371.java @@ -0,0 +1,97 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-02 17:36 + **/ + +public class Leetcode_322_371 { + public static void main(String[] args) { +// int[] coins = {186, 419, 83, 408}; +// int[] coins = {1}; +// int[] coins = {1,2,5}; + int[] coins = {2}; +// int amount = 6249; +// int amount = 11; + int amount = 3; +// int amount = 1; + int count = coinChange2(coins, amount); + System.out.println("count = " + count); + + } + + + /** + * 仿解2:动态规划(自底向上) + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int coinChange2(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + for (int i = 1; i <= amount; i++) { + int min = Integer.MAX_VALUE; + for (int coin : coins) { + if (i >= coin && dp[i - coin] != -1) { + min = Math.min(min, dp[i - coin]); + } + } + dp[i] = min == Integer.MAX_VALUE ? -1 : min+1; + } + + return dp[amount]; + } + /** + * 仿解1:动态规划(自顶向下) + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int coinChange1(int[] coins, int amount) { + if (amount<1) return 0; + int[] count = new int[amount]; + + return helper(coins,amount,count); + } + + private static int helper(int[] coins, int rem, int[] count) { + //1.递归出口 + if(rem <0) return -1; //invalid + if(rem == 0) return 0;//completed + //如果计算过的结果 + if(count[rem-1]!= 0) return count[rem - 1]; + int min = Integer.MAX_VALUE; + //2.处理当前层(动态规划的方式处理) + for (int coin : coins) { + //3.带上参数,去下一层 + int res = helper(coins, rem - coin, count); + if (res >= 0 && res < min) { + min = 1 + res; + } + } + //处理当前层结果,并返回 + count[rem - 1] = min == Integer.MAX_VALUE ? -1 : min; + return count[rem - 1]; + } + + /** + /** + * 原解1:(未解出) + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int coinChange(int[] coins, int amount) { + if(amount == 0) return 0; + Arrays.sort(coins); + int count = 0; + for (int i = coins.length - 1; i >= 0; i--) { + if (amount >= coins[i]) { + count += amount / coins[i]; + amount %= coins[i]; + if (amount == 0) return count; + } + } + return -1; + } + +} diff --git a/Week 03/id_371/Leetcode_33_371.java b/Week 03/id_371/Leetcode_33_371.java new file mode 100644 index 000000000..c67ac87dc --- /dev/null +++ b/Week 03/id_371/Leetcode_33_371.java @@ -0,0 +1,53 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-03 11:53 + **/ + +public class Leetcode_33_371 { + + public static void main(String[] args) { + int[] nums = {3, 1}; +// int[] nums = {4, 5, 6, 7, 0, 1, 2,3}; + int target = 1; + int index = search(nums, target); + System.out.println("index = " + index); + } + + /** + * 仿解1:二分查找(判断升序) + * + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int search(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; +// int mid = left + (right - left) / 2; + while (left <= right) { + int mid = left + (right - left) / 2; + //出口 + if (nums[mid] == target) { + return mid; + } + + if (nums[mid] >= nums[left]) {//mid的左边升序(left-mid) + if (target <= nums[mid] && target >= nums[left]) {//在左边 + right = mid - 1; + } else {//在右边 + left = mid + 1; + } + } else {//右边升序 + if (target >= nums[mid] && target <= nums[right]) {//在右边搜 + left = mid + 1; + } else {//去左边 + right = mid - 1; + } + + } +// mid = left + (right - left) / 2; + } + return -1; + } +} diff --git a/Week 03/id_371/Leetcode_367_371.java b/Week 03/id_371/Leetcode_367_371.java new file mode 100644 index 000000000..06727888a --- /dev/null +++ b/Week 03/id_371/Leetcode_367_371.java @@ -0,0 +1,50 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-03 11:35 + **/ + +public class Leetcode_367_371 { + public static void main(String[] args) { + int num = 16; + boolean perfectSquare = isPerfectSquare2(num); + System.out.println("perfectSquare = " + perfectSquare); + } + + /** + * 原解2:牛顿迭代法 + * + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static boolean isPerfectSquare2(int num) { + long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } + /** + * 原解1:二分查找法 + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static boolean isPerfectSquare1(int num) { + //确定左右边界 + long left = 0; + long right = num / 2 + 1;//num开根号的值不会大于 num/2+1 + while (left <= right) { + long mid = left + (right - left) / 2; + if (mid * mid == num) { + return true; + } else if (mid * mid > num) { + right = mid - 1; + } else { + left = left + 1; + } + } + return false; + } + +} diff --git a/Week 03/id_371/Leetcode_433_371.java b/Week 03/id_371/Leetcode_433_371.java new file mode 100644 index 000000000..ce5c6e661 --- /dev/null +++ b/Week 03/id_371/Leetcode_433_371.java @@ -0,0 +1,75 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-29 10:09 + **/ + +public class Leetcode_433_371 { + public static void main(String[] args) { + String start = "AACCGGTT"; + String end = "AAACGGTA"; + String[] bank = {"AACCGGTA", "AACCGCTA", "AAACGGTA"}; + int i = minMutation(start, end, bank); + System.out.println("i = " + i); + } + + /** + * 仿解1:单向 BFS<===(如何转化成单向 BFS的问题的?差1个字符就是1度关系,差2个字符就是2度关系,依次将当前顶点的一度关系加入队列) + * + * @return + */ + public static int minMutation(String start, String end, String[] bank) { + //0.边界情况处理 + if (start.isEmpty() || end.isEmpty() || bank ==null|| bank.length == 0) return -1; + + if (start.equals(end)) return 0; + + + //1.定义是否访问过该节点 + Set visited = new HashSet<>(); + //2.创建队列 + Queue queue = new LinkedList<>(); + //3.将起点加入队列 + queue.add(start); + int step = 0; + while (!queue.isEmpty()) { + step++; + int count = queue.size(); //确定每次 BFS 的宽度 + for (int i = 0; i < count; i++) { + String curr = queue.poll(); + for (int j = 0; j < bank.length; j++) { + int diff = 0;//注意 diff 的作用域 + if (!visited.contains(bank[j])) {//当前节点未被访问 + String bankStr = bank[j]; + for (int k = 0; k < curr.length(); k++) { + if (curr.charAt(k) != bankStr.charAt(k)) diff++; + } + if (diff == 1) { + //判断是否是end + if (bankStr.equals(end)) return step; + visited.add(bank[j]);//标记该节点已经访问 + queue.add(bankStr); + } + } + } + } + } + return -1; + } +} + + + + + + + + + + + + + diff --git a/Week 03/id_371/Leetcode_455_371.java b/Week 03/id_371/Leetcode_455_371.java new file mode 100644 index 000000000..d711a1c53 --- /dev/null +++ b/Week 03/id_371/Leetcode_455_371.java @@ -0,0 +1,44 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-02 11:28 + **/ + +public class Leetcode_455_371 { + + public static void main(String[] args) { +// int[] g = {1, 2,2}; + int[] g = {10,9,8,7}; +// int[] s = {1, 1}; +// int[] s = {1,2,3}; + int[] s = {5,6,7,8}; + int content = findContentChildren1(g, s); + System.out.println("content = " + content); + } + + /** + * 原解1:贪心算法 + * + * @author Shaobo.Qian + * @date 2019/11/2 + */ + public static int findContentChildren1(int[] g, int[] s) { + int content = 0; + int sLen = s.length; + Arrays.sort(g); + //先满足胃口大的 + for (int i = g.length - 1; i >= 0; i--) { + if (sLen <= 0) return content; + //边界处理 + if (s[sLen - 1] >= g[i]) { + content++; + sLen--; + } + } + return content; + } + +} diff --git a/Week 03/id_371/Leetcode_45_371.java b/Week 03/id_371/Leetcode_45_371.java new file mode 100644 index 000000000..5b3146696 --- /dev/null +++ b/Week 03/id_371/Leetcode_45_371.java @@ -0,0 +1,35 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-02 16:17 + **/ + +public class Leetcode_45_371 { + public static void main(String[] args) { + int[] nums = {2, 3, 1, 1, 4}; + int jump = jump(nums); + System.out.println("jump = " + jump); + + } + + /** + * 仿解1:贪婪法(每次在可跳访问内,选择那个能调到更远的地方) + * @author Shaobo.Qian + * @date 2019/11/2 + * @link https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-10/ + */ + public static int jump(int[] nums) { + int end = 0; + int step = 0; + int maxPosition = 0; + for (int i = 0; i < nums.length - 1; i++) { + maxPosition = Math.max(maxPosition, nums[i] + i); + if (i == end) {//每次到达能边界的时候更新能跳跃到的边界和步数+1 + end = maxPosition; + step++; + } + } + return step; + } +} diff --git a/Week 03/id_371/Leetcode_515_371.java b/Week 03/id_371/Leetcode_515_371.java new file mode 100644 index 000000000..70ba5f84d --- /dev/null +++ b/Week 03/id_371/Leetcode_515_371.java @@ -0,0 +1,94 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-29 21:47 + **/ + +public class Leetcode_515_371 { + class TreeNode { + int val; + TreeNode left, right; + + public TreeNode(int val) { + + this.val = val; + } + + } + + /** + * 原解2:优化 BFS + * @param root + * @return + */ + public List largestValues2(TreeNode root) { + //边界条件 + if (root == null) return new ArrayList<>(); + //1.结果 + List result = new ArrayList<>(); + //2.创建队列 + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + int count = queue.size(); + Integer max = null; + while (count-- > 0) { + TreeNode curr = queue.poll(); + if (max == null + ) { + max = curr.val; + } else { + max = Math.max(max, curr.val); + } + if (curr.left != null) queue.add(curr.left); + if (curr.right != null) queue.add(curr.right); + } + result.add(max); + } + return result; + } + + /** + * 原解1:BFS + * + * @param root + * @return + */ + public List largestValues1(TreeNode root) { + //边界条件 + if (root == null) return new ArrayList<>(); + //1.结果 + List result = new ArrayList<>(); + Set visited = new HashSet<>(); + //2.创建队列 + Queue queue = new LinkedList<>(); + queue.add(root); + //3.BFS + while (!queue.isEmpty()) { + Integer max = null; + //3.1确定队列的广度 + int count = queue.size(); + while (count-- > 0) { + TreeNode curr = queue.poll(); + if (!visited.contains(curr)) { + visited.add(curr); + //更新最大值 + if (max == null) { + max = curr.val; + } else { + max = Math.max(curr.val, max); + } + max = Math.max(max, curr.val); + if (curr.left != null) queue.add(curr.left); + if (curr.right != null) queue.add(curr.right); + } + } + result.add(max); + } + + return result; + } +} diff --git a/Week 03/id_371/Leetcode_529_371.java b/Week 03/id_371/Leetcode_529_371.java new file mode 100644 index 000000000..84bba0c8f --- /dev/null +++ b/Week 03/id_371/Leetcode_529_371.java @@ -0,0 +1,61 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-31 17:29 + **/ + +public class Leetcode_529_371 { + + /** + * 仿解1:DFS + * + * @param board 字典 + * @param click 传入的坐标 + * @return + * @link https://leetcode.com/problems/minesweeper/discuss/99826/Java-Solution-DFS-%2B-BFS + */ + public char[][] updateBoard(char[][] board, int[] click) { + int nRow = board.length; + int nColumn = board[0].length; + //1.坐标 + int row = click[0]; + int col = click[1]; + + //1.递归出口 + if (board[row][col] == 'M') { + board[row][col] = 'X'; + return board; + } else { + //2.处理当前节点(找出当前坐标邻点中有多少雷) + int count = 0; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue;//当前节点 + int r = row + i; + int c = col + j; + if (r < 0 || r >= nRow || c < 0 || c >= nColumn) continue;//超出边界,不处理 + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + if (count > 0) { + board[row][col] = (char) (count + '0'); + } else { + //3.带上参数,去下一层 递归调用 + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i; + int c = col + j; + if (r < 0 || r >= nRow || c < 0 || c >= nColumn) continue;//超出边界,不处理 + + } + } + } + + } + return board; + } + +} diff --git a/Week 03/id_371/Leetcode_55_371.java b/Week 03/id_371/Leetcode_55_371.java new file mode 100644 index 000000000..fec279692 --- /dev/null +++ b/Week 03/id_371/Leetcode_55_371.java @@ -0,0 +1,38 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-02 16:17 + **/ + +public class Leetcode_55_371 { + public static void main(String[] args) { +// int[] nums = {0,2,3}; + int[] nums = {1, 0, 1, 0}; +// int[] nums = {2, 3, 1, 1, 4}; +// int[] nums = {3, 2, 1, 0, 4}; + System.out.println(canJump(nums)); + + } + + /** + * 原解1.累加有效长度 + * + * @author Shaobo.Qian + * @date 2019/11/2 + */ + public static boolean canJump(int[] nums) { + if (nums.length <= 1) return true; + int targetLen = nums.length; + int maxLen = 0; //在当前位置能达到的最远位置 + for (int i = 0; i < nums.length - 1; i++) { + maxLen = Math.max(maxLen - 1, nums[i]); + //maxLen和 nus[i]都为0,已经跳不过去了 + if (maxLen == 0 && nums[i] == 0) return false; + targetLen = targetLen - 1; + if (maxLen >= targetLen) return true; + } + return false; + } + +} diff --git a/Week 03/id_371/Leetcode_69_371.java b/Week 03/id_371/Leetcode_69_371.java new file mode 100644 index 000000000..8e7700ce9 --- /dev/null +++ b/Week 03/id_371/Leetcode_69_371.java @@ -0,0 +1,56 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-03 10:05 + **/ + +public class Leetcode_69_371 { + + public static void main(String[] args) { +// int x = 16; +// int x = 17; + int x = 12; + int res = mySqrt2(x); + System.out.println("res = " + res); + + } + + /** + * 仿解2:(牛顿迭代法) + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int mySqrt2(int x) { + long r = x; + while (r * r > x) { + r = (r + x / r) / 2; + } + return (int) r; + } + + + /** + * 仿解1:(二分查找) + * + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static int mySqrt1(int x) { + //确定左右边界,开根号的值在 left 到 right 之间 + long left = 0; + long right = x / 2 + 1;//对于一个非负数n,它的平方根不会大于(n/2+1) + while (left <= right) { + long mid = left + (right - left) / 2; + if (mid * mid == x) { + return (int) mid; + } else if (mid * mid > x) { + right = mid - 1; + } else { + left = left + 1; + } + } + //如果开根号不是正数,最后的值在left到right之间 + return (int) right; + } +} diff --git a/Week 03/id_371/Leetcode_74_371.java b/Week 03/id_371/Leetcode_74_371.java new file mode 100644 index 000000000..8bb6ac092 --- /dev/null +++ b/Week 03/id_371/Leetcode_74_371.java @@ -0,0 +1,56 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-03 11:53 + **/ + +public class Leetcode_74_371 { + + public static void main(String[] args) { +// int[][] martrix = {}; + int[][] martrix = {{1, 3, 5, 7}, {10, 11, 16, 20}, {23, 30, 34, 50}}; + boolean res = searchMatrix(martrix, 51); + System.out.println("res = " + res); + } + /** + * 原解1:2次二分搜素 + * + * @author Shaobo.Qian + * @date 2019/11/3 + */ + public static boolean searchMatrix(int[][] matrix, int target) { + //0.处理边界值 + if(matrix==null || matrix.length == 0 || matrix[0].length == 0 || target < matrix[0][0]) return false; + //1.先确定在哪一行 + int rMinIndex = 0; + int rMaxIndex = matrix.length - 1; + int rMidIndex = 0; + // 如果没有搜索到target,出循环后,target肯定matrix[rMaxIndex]这一行 + while (rMinIndex <= rMaxIndex) { + rMidIndex = rMinIndex + (rMaxIndex - rMinIndex) / 2; + if (matrix[rMidIndex][0] == target) { + return true; + } else if (matrix[rMidIndex][0] < target) { + rMinIndex = rMidIndex + 1; + } else { + rMaxIndex = rMidIndex - 1; + } + } + int cMinIndex = 0; + int cMaxIndex = matrix[0].length - 1; + int cMidIndex = 0; + while (cMinIndex <= cMaxIndex) { + cMidIndex = cMinIndex + (cMaxIndex - cMinIndex) / 2; + if (matrix[rMaxIndex][cMidIndex] == target) { + return true; + } else if (matrix[rMaxIndex][cMidIndex] < target) { + cMinIndex = cMidIndex + 1; + } else { + cMaxIndex = cMidIndex - 1; + } + } + + return false; + } +} diff --git a/Week 03/id_371/Leetcode_860_371.java b/Week 03/id_371/Leetcode_860_371.java new file mode 100644 index 000000000..d06cc9c7a --- /dev/null +++ b/Week 03/id_371/Leetcode_860_371.java @@ -0,0 +1,83 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-31 19:50 + **/ + +public class Leetcode_860_371 { + public static void main(String[] args) { + int[] bills = {5, 5, 5, 5, 20, 20, 5, 5, 20, 5}; +// int[] bills = {5, 5, 10, 10, 20}; + System.out.println(lemonadeChange2(bills)); + + } + /** + * 优化 + * @author Shaobo.Qian + * @date 2019/11/1 + */ + public static boolean lemonadeChange2(int[] bills) { + + int fiveCnts = 0, tenCnts = 0; + + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + fiveCnts++; + } else if (bills[i] == 10) { + if (fiveCnts == 0) return false; + fiveCnts--; + tenCnts++; + } else { + if (tenCnts > 0 && fiveCnts > 0) { + fiveCnts--; + tenCnts--; + } else if (fiveCnts >= 3) { + fiveCnts -= 3; + } else { + return false; + } + } + } + return true; + } + + /** + * 原解1:贪心法+map + * + * @author Shaobo.Qian + * @date 2019/10/31 + */ + public static boolean lemonadeChange1(int[] bills) { + //对10来讲,5是可用的对20来件10和5是可用的 + Map map = new HashMap<>(); + map.put(5, 0); + map.put(10, 0); + Integer fiveCnts = map.get(5); + Integer tenCnts = map.get(10); + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + map.put(5, fiveCnts++); + } else if (bills[i] == 10) { + if (fiveCnts == 0) return false; + map.put(5, fiveCnts--); + map.put(10, tenCnts++); + } else { + if (tenCnts == 0) { + if (fiveCnts < 3) return false; + fiveCnts = fiveCnts - 3; + map.put(5, fiveCnts); + } else { + if (fiveCnts == 0) return false; + map.put(10, tenCnts--); + map.put(5, fiveCnts--); + } + } + } + return true; + } + +} diff --git a/Week 03/id_371/Leetcode_874_371.java b/Week 03/id_371/Leetcode_874_371.java new file mode 100644 index 000000000..8b57341dd --- /dev/null +++ b/Week 03/id_371/Leetcode_874_371.java @@ -0,0 +1,129 @@ +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-02 11:59 + **/ + +public class Leetcode_874_371 { + public static void main(String[] args) { + int[] commands = {-2, -1, 8, 9, 6}; +// int[] commands = {4, -1, 3}; +// int[] commands = {4, -1, 4, -2, 4}; +// int[][] obstacles = {{2, 4}}; + int[][] obstacles = {{-1, 3}, {0, 1}, {-1, 5}, {-2, -4}, {5, 4}, {-2, -3}, {5, -1}, {1, -1}, {5, 5}, {5, 2}}; + int res = robotSim2(commands, obstacles); + System.out.println("res = " + res); + } + + /** + * 防解1:模拟法 + * + * @author Shaobo.Qian + * @date 2019/11/3 + * @link https://leetcode.com/problems/walking-robot-simulation/discuss/152322/Maximum!-This-is-crazy! + */ + public static int robotSim2(int[] commands, int[][] obstacles) { + //1.存入所有障碍物坐标 + Set set = new HashSet<>(); + for (int[] obstacle : obstacles) { + set.add(obstacle[0] + "," + obstacle[1]); + } + + //2.模拟在坐标系四个方向上(上,右,下,左) + int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + //dir对应 二维数组dirs的索引,(现实含义:将要在某个方向前进一步) + int dir = 0, x = 0, y = 0, result = 0; + for (int c : commands) { + if (c == -1) { + dir++; + if (dir == 4) {//转换后,才能在 dirs 中取到值 + dir = 0; + } + } else if (c == -2) { + dir--; + if (dir == -1) {//转换后,才能在 dirs 中取到值 + dir = 3; + } + } else { + while (c-- > 0 && !set.contains((x + dirs[dir][0]) + "," + (y + dirs[dir][1]))) { + x += dirs[dir][0]; + y += dirs[dir][1]; + } + } + result = Math.max(result, x * x + y * y); + } + return result; + } + + /** + * 原解1:模拟(未解出) + * + * @author Shaobo.Qian + * @date 2019/11/2 + */ + public static int robotSim1(int[] commands, int[][] obstacles) { + + //定义横坐标 x,纵坐标 y,找到 x,y 的最大距离 + int x = 0, y = 0; + //y轴上的障碍物 + List yList = new ArrayList<>(); + //x轴上的障碍物 + List xList = new ArrayList<>(); + //2.根据障碍物,真实在 x,y 上的最大距离 + if (obstacles != null && obstacles.length > 0) { + for (int i = 0; i < obstacles.length; i++) { + //判断是否能遇到障碍物 + xList.add(obstacles[i][0]); + yList.add(obstacles[i][1]); + } + } + + boolean xFlag = true; + //1.假设没有障碍物的情况下x,y 的最大距离 + for (int i = 0; i < commands.length; i++) { + if (xFlag) { + x += commands[i]; + } else { + y += commands[i]; + } + if (commands[i] == -1 && yList.contains(y)) { + //在x轴上前进,判断是否会遇见障碍物 + //看当前的y是否在ySet中 + for (int j = 0; j < xList.size(); j++) { + Integer lowLimit = xList.get(j); + if (x >= xList.get(j)) { + xList.remove(lowLimit); + j--; + } else { + x = Math.min(x += commands[i], lowLimit - 1); + } + } + } else if (commands[i] == -2 && xList.contains(x)) { + //在y 轴上前进,判断是否会遇见障碍物 + for (int j = 0; j < yList.size(); j++) { + Integer lowLimit = yList.get(j); + if (y >= yList.get(j)) { + yList.remove(lowLimit); + j--; + } else { + y = Math.min(y += commands[i], lowLimit - 1); + } + } + xFlag = false; + } else { + if (xFlag) { + x += commands[i]; + } else { + y += commands[i]; + } + } + } + return x * x + y * y; + } +} diff --git a/Week 03/id_381/leetcode-455.py b/Week 03/id_381/leetcode-455.py new file mode 100644 index 000000000..e7065bcb9 --- /dev/null +++ b/Week 03/id_381/leetcode-455.py @@ -0,0 +1,15 @@ + +# 贪心算法 +# 先给g和s排序,这是首要做的,这一步很重要 +# 通过遍历循环s,从s中找到大于g中的元素,统计出最终找到的j的个数即可! +class Solution: + def findContentChildren(self, g, s) -> int: + g.sort() + s.sort() + j = 0 + for i in range(len(s)): + if j >= len(g): + break + if s[i] >= g[j]: + j += 1 + return j diff --git a/Week 03/id_381/leetcode-55.py b/Week 03/id_381/leetcode-55.py new file mode 100644 index 000000000..59a99a7a9 --- /dev/null +++ b/Week 03/id_381/leetcode-55.py @@ -0,0 +1,11 @@ + +# 从右往左贪心 +class Solution: + def canJump(self, nums) -> bool: + end = len(nums) - 1 + for i in range(len(nums)-1, 0-1, -1): + if nums[i] + i >= end: + end = i + if end == 0: + return True + return end == 0 diff --git a/Week 03/id_381/leetcode-860.py b/Week 03/id_381/leetcode-860.py new file mode 100644 index 000000000..f15c4cd0a --- /dev/null +++ b/Week 03/id_381/leetcode-860.py @@ -0,0 +1,18 @@ +""" +这个题在解决的时候,顾客给5的时候最好解决了,直接加上就行,10的时候也很好解决, +只有一种找钱的方式就是找5元返给顾客(注意five-1了,ten要+1)。需要注意的是,顾客给20元的时候, +最优的理解为给10+5,但是这也不是一定的,如果没有10却有3个5, 那么就需要考虑到了。 +需要注意20的找钱方式 +""" + +class Solution: + def lemonadeChange(self, bills) -> bool: + five, ten = 0, 0 + for bill in bills: + if bill == 5: five += 1 + elif bill == 10: five, ten = five-1, ten+1 + elif ten: five, ten = five-1, ten-1 + else: five -= 3 + if five < 0: + return False + return True diff --git a/Week 03/id_381/leetcode-874.py b/Week 03/id_381/leetcode-874.py new file mode 100644 index 000000000..7887870de --- /dev/null +++ b/Week 03/id_381/leetcode-874.py @@ -0,0 +1,26 @@ + +# 最开始是向北而行,x上的速度为0,y上的速度为1,x=0,y=1 +# 左转就变为x=-1,y=0,得出结论:dx, dy = -dy, dx +# 验证,每个轴都验证一遍,可行! +# 向右转也是类似的方式 +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + dx, dy, x, y = 0, 1, 0, 0 + distance = 0 + obs_dict = {} + for obs in obstacles: + obs_dict[tuple(obs)] = 0 + for com in commands: + if com == -2: + dx, dy = -dy, dx + elif com == -1: + dx, dy = dy, -dx + else: + for j in range(com): + next_x = x + dx + next_y = y + dy + if (next_x, next_y) in obs_dict: + break + x, y = next_x, next_y + distance = max(distance, x*x + y*y) + return distance diff --git a/Week 03/id_386/LeetCode_153_386.java b/Week 03/id_386/LeetCode_153_386.java new file mode 100644 index 000000000..fdb95a661 --- /dev/null +++ b/Week 03/id_386/LeetCode_153_386.java @@ -0,0 +1,8 @@ +import java.util.Arrays; + +class Solution { + public int findMin(int[] nums) { + Arrays.sort(nums); + return nums[0]; + } +} diff --git a/Week 03/id_386/LeetCode_455_386.java b/Week 03/id_386/LeetCode_455_386.java new file mode 100644 index 000000000..2a0302a99 --- /dev/null +++ b/Week 03/id_386/LeetCode_455_386.java @@ -0,0 +1,28 @@ +import java.util.Arrays; + +class Solution { + public int findContentChildren(int[] g, int[] s) { + int res = 0; + + if(g == null || s == null) { + return res; + } + + Arrays.sort(g); + Arrays.sort(s); + + for (int i=0, j = 0; i < g.length && j < s.length;) { + + if (g[i] <= s[j]) { + i++; + j++; + res++; + } else { + j++; + } + + } + + return res; + } +} diff --git a/Week 03/id_386/LeetCode_860_386.java b/Week 03/id_386/LeetCode_860_386.java new file mode 100644 index 000000000..7d2bc3ca9 --- /dev/null +++ b/Week 03/id_386/LeetCode_860_386.java @@ -0,0 +1,66 @@ +import java.util.HashMap; + +class Solution { + public boolean lemonadeChange(int[] bills) { + Map dollarsMap = new HashMap(); + boolean status = false; + int change = 0; + + dollarsMap.put(5, 0); + dollarsMap.put(10, 0); + + + if (bills[0] == 10 || bills[0] == 20) { + return status; + } + + for (int i = 0; i < bills.length; i++) { + System.out.println(bills[i]); + if (bills[i] == 5) { + dollarsMap.put(5, dollarsMap.get(5) + 1); + status = true; + } + + if (bills[i] == 10) { + + dollarsMap.put(10, dollarsMap.get(10) + 1); + + if (dollarsMap.get(5) == 0) { + return false; + } else if (dollarsMap.get(5) - 1 >= 0) { + dollarsMap.put(5, dollarsMap.get(5) - 1); + status = true; + } + + } + + if (bills[i] == 20) { + + + // System.out.println("5+, " + dollarsMap.get(5)); + // System.out.println("10+, " + dollarsMap.get(10)); + + if (dollarsMap.get(5) == 0) { + return false; + } + + if (dollarsMap.get(5) >= 3 && dollarsMap.get(10) == 0) { + dollarsMap.put(5, dollarsMap.get(5) - 3); + status = true; + } else if (dollarsMap.get(5) < 3 && dollarsMap.get(10) == 0) { + return false; + } + + + if (dollarsMap.get(5) >= 1 && dollarsMap.get(10) >=1) { + dollarsMap.put(5, dollarsMap.get(5) - 1); + dollarsMap.put(10, dollarsMap.get(10) - 1); + status = true; + } else { + status = false; + } + } + } + return status; + } +} diff --git a/Week 03/id_396/LeetCode_153_396.swift b/Week 03/id_396/LeetCode_153_396.swift new file mode 100644 index 000000000..db1df7234 --- /dev/null +++ b/Week 03/id_396/LeetCode_153_396.swift @@ -0,0 +1,30 @@ +// +// LeetCode_242_396.swift +// +// +// Created by chenjunzhi on 2019/10/27. +// + + +import UIKit + +// 寻找旋转排序数组中的最小值 +class Solution { + func findMin(_ nums: [Int]) -> Int { + if(nums.first! < nums.last!) { + return nums.first! + } + + var left = 0 + var right = nums.count - 1 + while left < right-1 { + let mid = right - (right - left) / 2 + if nums[left] > nums[mid] { //无序在左右,所以最小的点的左边 + right = mid //不能为mid-1 因为有可能mid就是最小的点 + } else { + left = mid + } + } + return nums[right] + } +} diff --git a/Week 03/id_396/LeetCode_33_396.swift b/Week 03/id_396/LeetCode_33_396.swift new file mode 100644 index 000000000..3ccd3d44c --- /dev/null +++ b/Week 03/id_396/LeetCode_33_396.swift @@ -0,0 +1,49 @@ +// +// LeetCode_242_396.swift +// +// +// Created by chenjunzhi on 2019/10/27. +// + + +import UIKit + +// 搜索旋转排序数组 +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + + var left = 0 + var right = nums.count - 1 + var result = -1 + while left <= right { + let mid = right - (right - left) / 2 + if target == nums[mid] { + return mid + } + + if target == nums[left] { + return left + } + + if target == nums[right] { + return right + } + + if nums[left] < nums[mid] { + if target < nums[mid] && target > nums[left] { + right = mid - 1 + } else { + left = mid + 1 + } + } else { + if target < nums[right] && target > nums[mid] { + left = mid + 1 + } else { + right = mid - 1 + } + } + } + return result; + } + +} diff --git a/Week 03/id_401/122.best-time-to-buy-and-sell-stock-ii.js b/Week 03/id_401/122.best-time-to-buy-and-sell-stock-ii.js new file mode 100644 index 000000000..810a6cdf5 --- /dev/null +++ b/Week 03/id_401/122.best-time-to-buy-and-sell-stock-ii.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + var valley = prices[0]; + var peak = prices[0]; + var maxProfit = 0; + var lenNeed = prices.length - 1; + var i = 0; + while(i < lenNeed){ + while(i < lenNeed && prices[i] > prices[i+1]){ + i++; + } + valley = prices[i]; + while(i < lenNeed && prices[i] <= prices[i+1]){ + i++; + } + peak = prices[i]; + maxProfit += peak - valley; + } + return maxProfit; +}; \ No newline at end of file diff --git a/Week 03/id_401/860.lemonade-change.js b/Week 03/id_401/860.lemonade-change.js new file mode 100644 index 000000000..80d0fff03 --- /dev/null +++ b/Week 03/id_401/860.lemonade-change.js @@ -0,0 +1,26 @@ +var lemonadeChange = function(bills) { + var five = 0; + var ten = 0; + var len = bills.length; + for(var i = 0;i 0 && five > 0){ + ten--; + five--; + }else if(five >= 3){ + five -= 3; + }else{ + return false; + } + } + } + return true; +}; diff --git a/Week 03/id_406/LeetCode_126_406.py b/Week 03/id_406/LeetCode_126_406.py new file mode 100644 index 000000000..bf856587a --- /dev/null +++ b/Week 03/id_406/LeetCode_126_406.py @@ -0,0 +1,35 @@ +class Solution: + def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]: + wordset = set(wordList) + wordset.discard(beginWord) + if endWord not in wordset: + return [] + k = 1 + bfs = {beginWord} + d = {} + d[beginWord]=[[beginWord]] + while len(bfs)>0: + if endWord in bfs: + break + bfs1 = set() + next1 = wordset.copy() + for word in bfs: + for i in range(len(word)): + for c in "abcdefghijklmnopqrstuvwxyz": + newWord = word[:i] + c + word[i + 1:] + if newWord in wordset and newWord != word: + if newWord not in d: + d[newWord] = [] + for obj in d[word]: + d[newWord].append(obj+[newWord]) + else: + for obj in d[word]: + d[newWord].append(obj+[newWord]) + if k==1: + wordset.remove(newWord) + next1.discard(newWord) + bfs1.add(newWord) + bfs = bfs1 + wordset = next1 + k += 1 + return d.get(endWord, []) \ No newline at end of file diff --git a/Week 03/id_406/LeetCode_455_406.py b/Week 03/id_406/LeetCode_455_406.py new file mode 100644 index 000000000..431ea8489 --- /dev/null +++ b/Week 03/id_406/LeetCode_455_406.py @@ -0,0 +1,20 @@ +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + res = 0 + g.sort() + s.sort() + + g_length = len(g) + s_length = len(s) + + i = 0 + j = 0 + + while i < g_length and j < s_length: + if g[i] <= s[j]: + res += 1 + i += 1 + j += 1 + else: + j += 1 + return res \ No newline at end of file diff --git a/Week 03/id_406/LeetCode_74_406.py b/Week 03/id_406/LeetCode_74_406.py new file mode 100644 index 000000000..b774c09df --- /dev/null +++ b/Week 03/id_406/LeetCode_74_406.py @@ -0,0 +1,19 @@ +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + m = len(matrix) + if m == 0: + return False + n = len(matrix[0]) + + left, right = 0, m * n - 1 + while left <= right: + pivot_idx = (left + right) // 2 + pivot_element = matrix[pivot_idx // n][pivot_idx % n] + if target == pivot_element: + return True + else: + if target < pivot_element: + right = pivot_idx - 1 + else: + left = pivot_idx + 1 + return False \ No newline at end of file diff --git a/Week 03/id_406/NOTE.md b/Week 03/id_406/NOTE.md index a6321d6e2..9a6bba070 100644 --- a/Week 03/id_406/NOTE.md +++ b/Week 03/id_406/NOTE.md @@ -1,4 +1,17 @@ # NOTE +贪心算法 +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法 +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能 +二分查找模板 +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 diff --git a/Week 03/id_416/LeetCode_102_416.java b/Week 03/id_416/LeetCode_102_416.java index 09576593a..a94f58ee2 100644 --- a/Week 03/id_416/LeetCode_102_416.java +++ b/Week 03/id_416/LeetCode_102_416.java @@ -57,7 +57,7 @@ public List> levelOrder(TreeNode root) { while(!queue.isEmpty()) { List lis = new ArrayList(); int size = queue.size(); - for(int i =0;i 0) { TreeNode currNode = queue.pop(); lis.add(currNode.val); if(null != currNode.left) queue.offer(currNode.left); diff --git a/Week 03/id_416/LeetCode_122_416.java b/Week 03/id_416/LeetCode_122_416.java new file mode 100644 index 000000000..96338bf14 --- /dev/null +++ b/Week 03/id_416/LeetCode_122_416.java @@ -0,0 +1,47 @@ +/** + 给定一个数组,它的第 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。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + /** + * 最大的利润就是:第二天比第一天价格高,那么就卖掉。否则就不买卖. + * 题意注意点:就是当天的可以进行多次交易,也就是当天可以卖掉也可以重新买入。 + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + int maxprofit = 0; + for(int i = 1;i < prices.length;i++) { + if(prices[i] > prices[i - 1]) { + maxprofit += (prices[i] - prices[i - 1]); + } + } + return maxprofit; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_127_416.java b/Week 03/id_416/LeetCode_127_416.java new file mode 100644 index 000000000..11402ac4b --- /dev/null +++ b/Week 03/id_416/LeetCode_127_416.java @@ -0,0 +1,85 @@ +/** + * 给定两个单词(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" 不在字典中,所以无法进行转换。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/word-ladder + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + /** + * BFS:广度优先搜索 + * @param n + * @return + */ + public int ladderLength(String beginWord, String endWord, List wordList) { + if(null == wordList) return 0; + int len = beginWord.length(); + Map> allDict = new HashMap<>(); + //改变形态,用HashMap散列表模拟二叉树形态 + wordList.forEach(word -> { + for(int i = 0;i < len;i++) { + String commonStatus = word.substring(0,i)+ "*" + word.substring(i+1,len); + if(!allDict.containsKey(commonStatus)) { + allDict.put(commonStatus,new ArrayList<>()); + } + allDict.get(commonStatus).add(word); + } + }); + Queue> q = new LinkedList<>(); + q.offer(new javafx.util.Pair(beginWord,0)); + HashMap visited = new HashMap(); + visited.put(beginWord, true); + while (!q.isEmpty()) { + javafx.util.Pair cur = q.poll(); + String curWord = cur.getKey(); + Integer level = cur.getValue(); + if(curWord.equals(endWord)) { + return level + 1; + } + for(int i = 0;i < len;i++) { + String commonStatus = curWord.substring(0,i)+ "*" + curWord.substring(i+1,len); + List curCommonStatus = allDict.get(commonStatus); + if(null != curCommonStatus && curCommonStatus.size() > 0 ) { + curCommonStatus.forEach(str -> { + if (!visited.containsKey(str)) { + visited.put(str, true); + q.offer(new javafx.util.Pair(str,level + 1)); + } + }); + } + } + } + return 0; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_135_416.java b/Week 03/id_416/LeetCode_135_416.java new file mode 100644 index 000000000..e2d818950 --- /dev/null +++ b/Week 03/id_416/LeetCode_135_416.java @@ -0,0 +1,37 @@ +/** + 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + + ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + + 请找出其中最小的元素。 + + 你可以假设数组中不存在重复元素。 + + 示例 1: + + 输入: [3,4,5,1,2] + 输出: 1 + 示例 2: + + 输入: [4,5,6,7,0,1,2] + 输出: 0 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while(left < right) { + int mid = left + (right - left) / 2; + if(nums[mid] > nums[right]) { + left = mid + 1; + }else{ + right = mid; + } + } + return nums[left]; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_33_416.java b/Week 03/id_416/LeetCode_33_416.java new file mode 100644 index 000000000..d8ef397df --- /dev/null +++ b/Week 03/id_416/LeetCode_33_416.java @@ -0,0 +1,48 @@ +/** + 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + + ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + + 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + + 你可以假设数组中不存在重复的元素。 + + 你的算法时间复杂度必须是 O(log n) 级别。 + + 示例 1: + + 输入: nums = [4,5,6,7,0,1,2], target = 0 + 输出: 4 + 示例 2: + + 输入: nums = [4,5,6,7,0,1,2], target = 3 + 输出: -1 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + public int search(int[] nums, int target) { + int lo = 0; + int hi = nums.length - 1; + while(lo <= hi) { + int mid = lo + (hi - lo) / 2; + int num = nums[mid]; + if( (nums[mid] < nums[0]) == (target < nums[0])) {//在左边的顺中 + num = nums[mid]; + } else { + num = target < nums[0]? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + + if(num < target) { + lo = mid + 1; + } else if(num > target){ + hi = mid - 1; + }else{ + return mid; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_455_416.java b/Week 03/id_416/LeetCode_455_416.java new file mode 100644 index 000000000..5b7e25cf3 --- /dev/null +++ b/Week 03/id_416/LeetCode_455_416.java @@ -0,0 +1,48 @@ +/** + 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + + 注意: + + 你可以假设胃口值为正。 + 一个小朋友最多只能拥有一块饼干。 + + 示例 1: + + 输入: [1,2,3], [1,1] + + 输出: 1 + + 解释: + 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + 所以你应该输出1。 + 示例 2: + + 输入: [1,2], [1,2,3] + + 输出: 2 + + 解释: + 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + 所以你应该输出2. + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/assign-cookies + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + /** + * 最小的饼干,满足最小的胃口 + * @param prices + * @return + */ + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g);Arrays.sort(s); + int i = 0,j = 0; + while(i < g.length && j < s.length) { + if(g[i] <= s[j]){i++} j++; + } + return i; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_515_416.java b/Week 03/id_416/LeetCode_515_416.java new file mode 100644 index 000000000..ca0be96aa --- /dev/null +++ b/Week 03/id_416/LeetCode_515_416.java @@ -0,0 +1,40 @@ +/** + * 您需要在二叉树的每一行中找到最大的值。 + * + * 示例: + * + * 输入: + * + * 1 + * / \ + * 3 2 + * / \ \ + * 5 3 9 + * + * 输出: [1, 3, 9] + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + public List largestValues(TreeNode root) { + Deque deque = new LinkedList(); + List list = new ArrayList(); + if(null == root) return list; + deque.offer(root); + while(!deque.isEmpty()) { + int len = deque.size(); + int max = Integer.MIN_VALUE; + while(len-- > 0){ + TreeNode treeNode = deque.pop(); + int cur = treeNode.val; + if(cur > max) max = cur; + if(null != treeNode.left) deque.offer(treeNode.left); + if(null != treeNode.right) deque.offer(treeNode.right); + } + list.add(max); + } + return list; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_69_416.java b/Week 03/id_416/LeetCode_69_416.java new file mode 100644 index 000000000..6e27bccea --- /dev/null +++ b/Week 03/id_416/LeetCode_69_416.java @@ -0,0 +1,39 @@ +/** + 实现 int sqrt(int x) 函数。 + + 计算并返回 x 的平方根,其中 x 是非负整数。 + + 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 + + 示例 1: + + 输入: 4 + 输出: 2 + 示例 2: + + 输入: 8 + 输出: 2 + 说明: 8 的平方根是 2.82842..., +   由于返回类型是整数,小数部分将被舍去。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/sqrtx + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + //1、3、4、7、9、33 + public int mySqrt(int x) { + long left = 0; + long right = x/2 + 1; + while(left < right) { + long mid = (left + right + 1) >>> 1; + long square = mid * mid; + if(square > x) { + right = mid - 1; + } else { + left = mid ; + } + } + return (int)left; + } +} \ No newline at end of file diff --git a/Week 03/id_416/LeetCode_860_416.java b/Week 03/id_416/LeetCode_860_416.java new file mode 100644 index 000000000..a21490255 --- /dev/null +++ b/Week 03/id_416/LeetCode_860_416.java @@ -0,0 +1,69 @@ +/** + 在柠檬水摊上,每一杯柠檬水的售价为 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  + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/lemonade-change + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_22_416{ + //这道题目是在贪心的科目下面,一开始也不明白为什么是贪心,贪心的意思是:当前是最优解,最后我好像有点明白了,在写代码的过程中,如果当前是最优解那么就返回 + //复习了一下switch的用法,break必须要加上,如果bill=5,如果在case = 5的情况下,不加入break,下面的所有case都会执行,所以swtich case语句是直接跳到指定参数值以后的地方,如果不加break的话 + public boolean lemonadeChange(int[] bills) { + int five = 0,ten = 0; + for (int bill : bills){ + switch(bill) { + case 5: + five++;break; + case 10: + if(five-- == 0) return false; + ten++;break; + case 20: + if(ten >= 1 && five >= 1) {five--;ten++;break;} + if(five >= 3) {five = five - 3;break;} + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 03/id_416/NOTE.md b/Week 03/id_416/NOTE.md index a6321d6e2..da4371a63 100644 --- a/Week 03/id_416/NOTE.md +++ b/Week 03/id_416/NOTE.md @@ -1,4 +1,7 @@ -# NOTE +# 第三周笔记 +##深度优先搜索模板 + +##广度优先搜索 diff --git a/Week 03/id_431/LeetCode_102_431.java b/Week 03/id_431/LeetCode_102_431.java new file mode 100644 index 000000000..7bb3b78a1 --- /dev/null +++ b/Week 03/id_431/LeetCode_102_431.java @@ -0,0 +1,65 @@ +package medium; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/10/31 + */ +public class BinaryTreeLevelOrderTraversal { + + /** + * 使用队列先进先出进行层次遍历 + * @param root + * @return + */ +// public List> levelOrder(TreeNode root) { +// List> result = new ArrayList<>(); +// if (root == null) return result; +// Deque deque = new LinkedList<>(); +// deque.addLast(root); +// while (!deque.isEmpty()) { +// List list = new ArrayList<>(deque.size()); +// int count = deque.size(); +// while (count-- > 0) { +// TreeNode node = deque.removeFirst(); +// list.add(node.val); +// if (node.left != null) deque.addLast(node.left); +// if (node.right != null) deque.addLast(node.right); +// } +// result.add(list); +// } +// return result; +// } + + /** + * 使用先序遍历 + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + traversal(result, root, 0); + return result; + } + + private void traversal(List> result, TreeNode node, int deep) { + if (node == null) return; + if (result.size() < deep + 1) { + result.add(new ArrayList<>()); + } + result.get(deep).add(node.val); + traversal(result, node.left, deep + 1); + traversal(result, node.right, deep + 1); + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week 03/id_431/LeetCode_122_431.java b/Week 03/id_431/LeetCode_122_431.java new file mode 100644 index 000000000..a7ee304b7 --- /dev/null +++ b/Week 03/id_431/LeetCode_122_431.java @@ -0,0 +1,20 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/3 + */ +public class BestTimeToBuyAndSellStockII { + public int maxProfit(int[] prices) { + int profit = 0, i = 0; + while (i < prices.length) { + // find next local minimum + while (i < prices.length-1 && prices[i+1] <= prices[i]) i++; + int min = prices[i++]; // need increment to avoid infinite loop for "[1]" + // find next local maximum + while (i < prices.length-1 && prices[i+1] >= prices[i]) i++; + profit += i < prices.length ? prices[i++] - min : 0; + } + return profit; + } +} diff --git a/Week 03/id_431/LeetCode_127_431.java b/Week 03/id_431/LeetCode_127_431.java new file mode 100644 index 000000000..0e1eacf40 --- /dev/null +++ b/Week 03/id_431/LeetCode_127_431.java @@ -0,0 +1,53 @@ +package medium; + +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/1 + */ +public class WordLadder { + /** + * BFS + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength(String beginWord, String endWord, List wordList) { + int level = 0; + Set visited = new HashSet<>(); + Deque deque = new LinkedList<>(); + Set wordSet = new HashSet<>(wordList); + deque.addLast(beginWord); + visited.add(beginWord); + while (!deque.isEmpty()) { + int size = deque.size(); + level++; + while (size-- > 0) { + String current = deque.removeFirst(); + if (current.equals(endWord)) return level; + char[] curChar = current.toCharArray(); + for (int i = 0; i < curChar.length; i++) { + char old = curChar[i]; + for (char c = 'a'; c < 'z'; c++) { + if (old != c) { + curChar[i] = c; + String tmp = new String(curChar); + if (!visited.contains(tmp) && wordSet.contains(tmp)) { + deque.addLast(tmp); + visited.add(tmp); + } + } + } + curChar[i] = old; + } + } + } + return 0; + } +} diff --git a/Week 03/id_431/LeetCode_200_431.java b/Week 03/id_431/LeetCode_200_431.java new file mode 100644 index 000000000..df39a21a9 --- /dev/null +++ b/Week 03/id_431/LeetCode_200_431.java @@ -0,0 +1,41 @@ +package medium; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/1 + */ +public class NumberOfIslands { + /** + * DFS + * @param grid + * @return + */ + public int numIslands(char[][] grid) { + if (grid.length <= 0) return 0; + int num = 0; +// Set visited = new HashSet<>(); + int length = grid.length; + int height = grid[0].length; + for (int i = 0; i < length; i++) { + for (int j = 0; j < height; j++) { + if (grid[i][j] == '1') { + DFS(grid, i, j, length, height); + num++; + } + } + } + return num; + } + + public void DFS(char[][] grid, int i, int j, int length, int height){ + if (i < 0 || j < 0 || i > length - 1 || j > height - 1 || grid[i][j] == '0') return; + grid[i][j] = '0'; + DFS(grid, i - 1, j, length, height); + DFS(grid, i + 1, j, length, height); + DFS(grid, i, j - 1, length, height); + DFS(grid, i, j + 1, length, height); + } +} diff --git a/Week 03/id_431/LeetCode_33_431.java b/Week 03/id_431/LeetCode_33_431.java new file mode 100644 index 000000000..9f28ddbc5 --- /dev/null +++ b/Week 03/id_431/LeetCode_33_431.java @@ -0,0 +1,71 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/5 + */ +public class SearchInRotatedSortedArray { +// public int search(int[] nums, int target) { +// if (nums.length == 0) return -1; +// if (nums.length == 1) return nums[0] == target ? 0 : -1; +// int maxBroad = getBroad(nums); +// if (maxBroad == -1) return _binarySearch(nums, 0, nums.length - 1, target); +// if (target == nums[0]) return 0; +// else if (target > nums[0]) return _binarySearch(nums, 0, maxBroad, target); +// else return _binarySearch(nums, maxBroad + 1, nums.length - 1, target); +// } +// +// private int getBroad(int[] nums) { +// int left = 0, right = nums.length - 1; +// if (nums[left] < nums[right]) return -1; +// while (right - left > 1) { +// int mid = (left + right) / 2; +// if (nums[mid] > nums[left]) left = mid; +// else right = mid; +// } +// if (nums[left] > nums[right]) return left; +// else return right; +// } +// +// private int _binarySearch(int[] nums, int left, int right, int target) { +// if (nums[left] == target) return left; +// if (nums[right] == target) return right; +// while (left < right) { +// if (nums[left] == target) return left; +// if (nums[right] == target) return right; +// int mid = (left + right) / 2; +// if (nums[mid] > target) right = mid - 1; +// else if (nums[mid] < target) left = mid + 1; +// else return mid; +// } +// return -1; +// } + + /** + * 思路:例子数组[6,7,8,1,2,3,4,5],target为7,可以把数组看成[6,7,8,Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE] + * 如果target为3,可以把数组看成[Integer.MIN_VALUE,Integer.MIN_VALUE,Integer.MIN_VALUE,1,2,3,4,5] + * @param nums + * @param target + * @return + */ + public int search(int[] nums, int target) { + int left = 0, right = nums.length; + while (left < right) { + int mid = (left + right) / 2; + int num = target > nums[left] && nums[mid] > nums[left] + ? nums[mid] : target > nums[0] + ? Integer.MAX_VALUE : Integer.MIN_VALUE; + if (num < target) left = mid + 1; + else if (num > target) right = mid; + else return mid; + } + return -1; + } + + public static void main(String[] args) { + int[] nums = new int[]{4,5,6,7,0,1,2}; + int target = 0; + SearchInRotatedSortedArray s = new SearchInRotatedSortedArray(); + s.search(nums, target); + } +} diff --git a/Week 03/id_431/LeetCode_367_431.java b/Week 03/id_431/LeetCode_367_431.java new file mode 100644 index 000000000..f8cdddc23 --- /dev/null +++ b/Week 03/id_431/LeetCode_367_431.java @@ -0,0 +1,15 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/5 + */ +public class ValidPerfectSquare { + public boolean isPerfectSquare(int num) { + long cur = num; + while (cur * cur > num) { + cur = (cur + num /cur) / 2; + } + return cur * cur == num; + } +} diff --git a/Week 03/id_431/LeetCode_433_431.java b/Week 03/id_431/LeetCode_433_431.java new file mode 100644 index 000000000..28187820b --- /dev/null +++ b/Week 03/id_431/LeetCode_433_431.java @@ -0,0 +1,61 @@ +package medium; + +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/10/31 + */ +public class MinimumGeneticMutation { + + /** + * 使用广度优先搜索 + * @param start + * @param end + * @param bank + * @return + */ + public int minMutation(String start, String end, String[] bank) { + if (start.equals(end)) return 0; + Set bankSet = new HashSet<>(bank.length); + int level = 0; //突变次数 + for (String b : bank) bankSet.add(b); + char[] chars = new char[]{'A', 'C', 'G', 'T'}; + //设置队列存储值 + Deque deque = new LinkedList<>(); + //访问的数组 + Set visited = new HashSet<>(); + //设置初始值 + deque.addLast(start); + visited.add(start); + //广度优先遍历 + while (!deque.isEmpty()) { + int size = deque.size(); + while (size-- > 0) { + String str = deque.removeFirst(); + //如果与最后的基因相等,直接返回 + if (str.equals(end)) return level; + char[] charArray = str.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char old = charArray[i]; + for (char c : chars) { + charArray[i] = c; + String newStr = new String(charArray); + // 如果当前不是访问过的且在基因库中,进行存放 + if (!visited.contains(newStr) && bankSet.contains(newStr)) { + deque.addLast(newStr); + visited.add(newStr); + } + } + charArray[i] = old; //还原 + } + } + level++; + } + return -1; + } +} diff --git a/Week 03/id_431/LeetCode_455_431.java b/Week 03/id_431/LeetCode_455_431.java new file mode 100644 index 000000000..3d4fd1faf --- /dev/null +++ b/Week 03/id_431/LeetCode_455_431.java @@ -0,0 +1,24 @@ +package easy; + +import java.util.Arrays; + +/** + * @author 潘磊明 + * @date 2019/11/4 + */ +public class AssignCookies { + public int findContentChildren(int[] g, int[] s) { + int children = 0; + // 对数组进行排序 + Arrays.sort(g); + Arrays.sort(s); + int i = 0, j = 0; + for (;i < g.length; i++) { + for (; j < s.length; j++){ + if (j > s.length - 1) return children; + if (s[j] >= g[i]) {children++; j++; break;} + } + } + return children; + } +} diff --git a/Week 03/id_431/LeetCode_45_431.java b/Week 03/id_431/LeetCode_45_431.java new file mode 100644 index 000000000..5c5658046 --- /dev/null +++ b/Week 03/id_431/LeetCode_45_431.java @@ -0,0 +1,23 @@ +package hard; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * @author 潘磊明 + * @date 2019/11/5 + */ +public class JumpGameII { + public int jump(int[] nums) { + int end = 0, maxIndex = 0, jump = 0; + for (int i = 0; i < nums.length - 1; i++) { + maxIndex = Math.max(maxIndex, i + nums[i]); + if (i == end) { + end = maxIndex; + jump++; + } + } + return jump; + } + +} diff --git a/Week 03/id_431/LeetCode_515_431.java b/Week 03/id_431/LeetCode_515_431.java new file mode 100644 index 000000000..463259700 --- /dev/null +++ b/Week 03/id_431/LeetCode_515_431.java @@ -0,0 +1,68 @@ +package medium; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/10/31 + */ +public class FindLargestValueInEachTreeRow { + + /** + * 广度优先搜索 + * @param root + * @return + */ +// public List largestValues(TreeNode root) { +// if (root == null) return Collections.emptyList(); +// Deque deque = new LinkedList<>(); +// deque.addLast(root); +// List list = new ArrayList<>(); +// while (!deque.isEmpty()) { +// int size = deque.size(); +// int max = Integer.MIN_VALUE; +// while (size-- > 0) { +// TreeNode node = deque.removeFirst(); +// max = Math.max(max, node.val); +// if (node.left != null) deque.addLast(node.left); +// if (node.right != null) deque.addLast(node.right); +// } +// list.add(max); +// } +// return list; +// } + + /** + * 深度优先搜索 + * @param root + * @return + */ + public List largestValues(TreeNode root) { + List list = new ArrayList<>(); + traversal(root, list, 1); + return list; + } + + /** + * 深度优先遍历 DFS + * @param node + */ + public void traversal(TreeNode node, List list, int deep){ + if (node == null) return; + if (list.size() < deep) list.add(node.val); + else list.set(deep - 1, Math.max(node.val, list.get(deep - 1))); + traversal(node.left, list, deep + 1); + traversal(node.right, list, deep + 1); + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week 03/id_431/LeetCode_529_431.java b/Week 03/id_431/LeetCode_529_431.java new file mode 100644 index 000000000..8ce140b44 --- /dev/null +++ b/Week 03/id_431/LeetCode_529_431.java @@ -0,0 +1,61 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/4 + */ +public class Minesweeper { + public char[][] updateBoard(char[][] board, int[] click) { + // 如果点到雷就返回 + if (board[click[0]][click[1]] == 'M') { + board[click[0]][click[1]] = 'X'; + return board; + } + // 否则进行遍历 + dfs(board, click[0], click[1]); + return board; + } + + private void dfs(char[][] board, int i, int j){ + int width = board.length; + int height = board[0].length; + if (i < 0 || i > width - 1 || j < 0 || j > height - 1 || board[i][j] != 'E') return; + // 周围没有雷就进行深度遍历 + if (!surrentMine(board, i, j, width, height)) { + dfs(board, i - 1, j - 1); + dfs(board, i - 1, j); + dfs(board, i - 1, j + 1); + dfs(board, i, j - 1); + dfs(board, i, j + 1); + dfs(board, i + 1, j - 1); + dfs(board, i + 1, j); + dfs(board, i + 1, j + 1); + } + } + + /** + * 判断周围是否有雷 + * @param board + * @param i + * @param j + * @return + */ + private boolean surrentMine(char[][] board, int i, int j, int width, int height) { + int count = 48; // 周围地雷数量 + if (i - 1 > -1 && j - 1 > -1 && board[i - 1][j - 1] == 'M') count++; + if (i - 1 > -1 && board[i - 1][j] == 'M') count++; + if (i - 1 > -1 && j + 1 < height && board[i - 1][j + 1] == 'M') count++; + if (j - 1 > -1 && board[i][j - 1] == 'M') count++; + if (i + 1 < width && j - 1 > -1 && board[i + 1][j - 1] == 'M') count++; + if (j + 1 < height && board[i][j + 1] == 'M') count++; + if (i + 1 48) { + board[i][j] = (char)count; + return true; + } else { + board[i][j] = 'B'; + return false; + } + } +} diff --git a/Week 03/id_431/LeetCode_55_431.java b/Week 03/id_431/LeetCode_55_431.java new file mode 100644 index 000000000..d03881601 --- /dev/null +++ b/Week 03/id_431/LeetCode_55_431.java @@ -0,0 +1,44 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/5 + */ +public class JumpGame { +// /** +// * Time limit +// * @param nums +// * @return +// */ +// public boolean canJump(int[] nums) { +// return _canJump(nums, 0); +// } +// +// private boolean _canJump(int[] nums, int index){ +// if (index < nums.length && nums.length - 1 - index <= nums[index]) { +// return true; +// } +// int val = nums[index]; +// while (val > 0) { +// boolean flag = _canJump(nums, index + val); +// if (flag) return true; +// else val--; +// } +// return false; +// } + + /** + * 循环nums判断当前的最大值是否大于等于数组的索引 + * @param nums + * @return + */ + public boolean canJump(int[] nums) { + int max = 0; + for (int i = 0; i <= max; i++) { + max = Math.max(max, i + nums[i]); + if (max >= nums.length - 1) return true; + } + return false; + } + +} diff --git a/Week 03/id_431/LeetCode_69_431.java b/Week 03/id_431/LeetCode_69_431.java new file mode 100644 index 000000000..777e47b4a --- /dev/null +++ b/Week 03/id_431/LeetCode_69_431.java @@ -0,0 +1,20 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/5 + */ +public class Sqrt_x { + /** + * 二分查找 + * @param x + * @return + */ + public int mySqrt(int x) { + long cur = x; + while (cur * cur > x) { + cur = (cur + x / cur) / 2; + } + return (int)cur; + } +} diff --git a/Week 03/id_431/LeetCode_860_431.java b/Week 03/id_431/LeetCode_860_431.java new file mode 100644 index 000000000..f60bb1420 --- /dev/null +++ b/Week 03/id_431/LeetCode_860_431.java @@ -0,0 +1,19 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/3 + */ +public class LemonadeChange { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) {five--; ten++;} + else if (ten > 0) {ten--; five--;} + else five -= 3; + if (five < 0) return false; + } + return true; + } +} diff --git a/Week 03/id_431/LeetCode_874_431.java b/Week 03/id_431/LeetCode_874_431.java new file mode 100644 index 000000000..5e46d7c91 --- /dev/null +++ b/Week 03/id_431/LeetCode_874_431.java @@ -0,0 +1,99 @@ +package easy; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/4 + */ +public class WalkingRobotSimulation { + public int robotSim(int[] commands, int[][] obstacles) { + int direction = 0; //机器人前行的方向 0-right, 1-down, 2-left, 3-up + Set obstaclesSet = obstracles2Set(obstacles); + int i = 0, j = 0; + int distance = 0; + int max = 0; + for (int x = 0; x < commands.length; x++) { + if (isDirection(commands[x])) direction = getDirection(commands[x], direction); + else { + if (direction == 0) j = moveRight(obstaclesSet, i, j, commands[x]); + else if (direction == 1) i = moveDown(obstaclesSet, i, j, commands[x]); + else if (direction == 2) j = moveLeft(obstaclesSet, i, j, commands[x]); + else i = moveUp(obstaclesSet, i, j, commands[x]); + max = Math.max(max, i * i + j * j); + } + } + return max; + } + + private Set obstracles2Set(int[][] obstacles){ + Set set = new HashSet<>(); + for (int i = 0; i < obstacles.length; i++) { + set.add(obstacles[i][0] + "@" + obstacles[i][1]); + } + return set; + } + + private boolean isDirection(int value){ + return value < 0; + } + + /** + * 获取当前机器人行走的方向 + * @param direct + * @return + */ + private int getDirection(int direct, int direction){ + if (direct == -1) direction++; + else if (direct == -2) direction--; + if (direction > 3) return direction - 4; + else if (direction < 0) return direction + 4; + else return direction; + } + + private int moveRight(Set set, int i, int j, int distance) { + for (int x = 1; x < distance + 1; x++) { + if (set.contains(i + "@" + (j + x))) { + return x + j - 1; + } + } + return j + distance; + } + + private int moveLeft(Set set, int i, int j, int distance) { + for (int x = 1; x < distance + 1; x++) { + if (set.contains(i + "@" + (j - x))) { + return j - x + 1; + } + } + return j - distance; + } + + private int moveUp(Set set, int i, int j, int distance) { + for (int x = 1; x < distance + 1; x++) { + if (set.contains((i - x) + "@" + j)) { + return i - x + 1; + } + } + return i - distance; + } + + private int moveDown(Set set, int i, int j, int distance) { + for (int x = 1; x < distance + 1; x++) { + if (set.contains((i + x) + "@" + j)) { + return i + x - 1; + } + } + return i + distance; + } + + public static void main(String[] args) { + WalkingRobotSimulation w = new WalkingRobotSimulation(); + int[] commands = new int[]{4, -1, 4, -2, 4}; + int[][] obstacles = new int[][]{ + new int[]{2,4} + }; + w.robotSim(commands, obstacles); + } +} diff --git a/Week 03/id_431/NOTE.md b/Week 03/id_431/NOTE.md index a6321d6e2..4ca233c90 100644 --- a/Week 03/id_431/NOTE.md +++ b/Week 03/id_431/NOTE.md @@ -2,3 +2,29 @@ +# 目录 + +* 刷题时间表 + + + +# 第三周刷题时间表 + +题目名称|难易度|第一遍时间|第二遍时间|第三遍时间|第四遍时间|第五遍时间|地址 +:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-: +Binary Tree Level Order Traversal|Medium|2019-10-31|||||https://leetcode.com/problems/binary-tree-level-order-traversal/ +Minimum Genetic Mutation|Medium|2019-10-31|||||https://leetcode.com/problems/minimum-genetic-mutation/ +Find Largest Value in Each Tree Row|medium|2019-10-31|||||https://leetcode.com/problems/find-largest-value-in-each-tree-row +Word Ladder|Medium|2019-11-01|||||https://leetcode.com/problems/word-ladder/ +Number of Islands|Medium|2019-11-01|||||https://leetcode.com/problems/number-of-islands/ +Word Ladder II|Hard|2019-11-02|||||https://leetcode.com/problems/word-ladder-ii/description/ +Minesweeper|Medium|2019-11-04|||||https://leetcode.com/problems/minesweeper/description/ +Lemonade Change|Easy|2019-11-04|||||https://leetcode.com/problems/lemonade-change/ +Best Time to Buy and Sell Stock II|Easy|2019-11-04|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ +Assign Cookies|Easy|2019-11-04|||||https://leetcode.com/problems/assign-cookies/ +Walking Robot Simulation|Easy|2019-11-05|||||https://leetcode.com/problems/walking-robot-simulation/ +Jump Game|Medium|2019-11-05|||||https://leetcode.com/problems/jump-game/ +Jump Game II|Hard|2019-11-05|||||https://leetcode.com/problems/jump-game-ii/ +Sqrt(x)|Easy|2019-11-05|||||https://leetcode.com/problems/sqrtx/ +Valid Perfect Square|Easy|2019-11-05|||||https://leetcode.com/problems/valid-perfect-square/ +Search in Rotated Sorted Array|Medium|2019-11-05|||||https://leetcode.com/problems/search-in-rotated-sorted-array/ \ No newline at end of file diff --git a/Week 03/id_436/Leetcode_127_436.java b/Week 03/id_436/Leetcode_127_436.java new file mode 100644 index 000000000..d6b7f5cce --- /dev/null +++ b/Week 03/id_436/Leetcode_127_436.java @@ -0,0 +1,61 @@ +import java.util.*; +public class Leetcode_127_436 { + public int ladderLength(String start, String end, List wordList){ + Set dict = new HashSet<>(); + for (String word : wordList) { //将wordList中的单词加入dict + dict.add(word); + } + + if (start.equals(end)) { + return 1; + } + + HashSet hash = new HashSet(); + Queue queue = new LinkedList(); + queue.offer(start); + hash.add(start); + + int length = 1; + while(!queue.isEmpty()){ + length++; + int size = queue.size(); + for(int i = 0; i < size; i++){ + String word = queue.poll(); + for(String nextWord: getNextWords(word, dict)){ + if(hash.contains(nextWord)){ + continue; + } + if(nextWord.equals(end)){ + return length; + } + hash.add(nextWord); + queue.offer(nextWord); + } + } + } + return 0; + } + private String replace(String s, int index, char c){ + char[] chars = s.toCharArray(); + chars[index] = c; + return new String(chars); + } + // get connections with given word. + // for example, given word = 'hot', dict = {'hot', 'hit', 'hog'} + // it will return ['hit', 'hog'] + private ArrayList getNextWords(String word, Set dict){ + ArrayList nextWords = new ArrayList(); + for(char c = 'a'; c <= 'z'; c++){ //枚举当前替换字母 + for(int i = 0; i < word.length(); i++){ //枚举替换位置 + if(c == word.charAt(i)){ + continue; + } + String nextWord = replace(word,i,c); + if(dict.contains(nextWord)){ + nextWords.add(nextWord); + } + } + } + return nextWords; + } +} \ No newline at end of file diff --git a/Week 03/id_436/Leetcode_33_436.java b/Week 03/id_436/Leetcode_33_436.java new file mode 100644 index 000000000..e4bc8a5d1 --- /dev/null +++ b/Week 03/id_436/Leetcode_33_436.java @@ -0,0 +1,39 @@ +class Leetcode_33_436 { + public int search(int[] nums, int target) { + int start = 0; int end = nums.length - 1; + if(nums.length == 0 || nums == null){ + return -1; + } + int mid = 0; + while(start + 1 < end){ + mid = start + (end - start) / 2; + if(nums[mid] == target){ + return mid; + } + //判断具体位置,看看是在排序好的部分还是翻转后的部分 + if(nums[start] < nums[mid]){ + if(nums[start] <= target && target <= nums[mid]){ + end = mid; + } + else{ + start = mid; + } + } + else{ + if(nums[mid] <= target && target <= nums[end]){ + start = mid; + } + else{ + end = mid; + } + } + } + if(nums[start] == target){ + return start; + } + if(nums[end] == target){ + return end; + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_441/NOTE.md b/Week 03/id_441/NOTE.md index a6321d6e2..ede2f73b4 100644 --- a/Week 03/id_441/NOTE.md +++ b/Week 03/id_441/NOTE.md @@ -1,4 +1,122 @@ # NOTE - +## 深度优先和广度优先 +之前对于深度优先遍历和广度优先遍历的了解。利用while可以实现广度优先遍历,利用递归可以实现深度优先遍历。 + +## 启发式搜索 + +优先级优先的搜索,推荐算法。快手,抖音的推荐算法。 + +### js中的深拷贝涉及到的深度优先遍历 + +```js + +export const deepCopy = (obj) => { + if(obj = null) return obj; + if(obj instanceof Date) return new Date(obj); + if(obj instanceof RegExp) return new RegExp(obj); + if(typeof obj !== 'object') return obj; + let newObj = new obj.constructor(); + for( let k in obj){ + newObj[key] = deepCopy(obj[key]) + } + return obj +} + +``` + +## 深度优先搜索的代码模板 + +深度优先遍历通常是递归或者使用栈的方式来解决。 + +### python + +```python + +// 二叉树 + +def dfs(node): + + if node in visited: + return + visited.add(node) + defs(node.left) + defs(node.right) + +// 普适对象 + +visited = set(); +def dfs(node, visited): + visited.add(node) + + for next_node in node.children(): + if not next_node in visited: + defs(next_node, visited) + +// 普遍递归思路 + +visited = set() +def dfs(node, visited): + if node in visited: + return + visited.add(node) + + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +// 非递归写法 + +def DFS (self, tree): + if tree.root is None: + return []; + + visited, stack =[], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + + stadk.push(nodes) + +``` + +## 广度优先的代码模板 + +一般使用while或者队列来实现。 + +```python + +def BFS(graph ,start , end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + +``` + +## 贪心算法 +在每一步选择中都采取当前状态下最优的选择。从而希望全局最优。和动态规划不同的地方在于,对每一个子问题都有决策,不能回退。而动态规划则会保存以前的计算结果,根据历史计算结果对当前做出选择。有回退的功能。最优状态的回溯就叫做动态规划。 +贪心算法可以在某一步使用,并且配合动态规划或者递归来达到解决问题的目的。 +贪心算法一般用来处理最优最好的情况。如:图中最小的树,哈夫曼编码等。但是在工程中和生活中并不能起到作用。 +另外就是作为辅助算法来进行解决实际问题。 +使用场景: +1:问题比较特殊(比如:整除关系。) +2:问题能够分为子问题 + +## 二分查找 + +1:单调性 +2:存在边界(上下界) +3:索引访问 \ No newline at end of file diff --git a/Week 03/id_441/assign-cookies.js b/Week 03/id_441/assign-cookies.js new file mode 100644 index 000000000..67f90bbd4 --- /dev/null +++ b/Week 03/id_441/assign-cookies.js @@ -0,0 +1,38 @@ +// https://leetcode-cn.com/problems/assign-cookies/ +var findContentChildren = function (g, s) { + let res = 0; + s = s.sort((a, b) => a - b) + + g = g.sort((a, b) => a - b) + + g.forEach(item => { + while (s.length) { + if (item <= s.shift()) { + res++ + break + } + } + }) + return res +} + +var findContentChildren = function (g, s) { + s = s.sort((a, b) => a - b) + + g = g.sort((a, b) => a - b) + + let g_i = 0; + let s_i = 0; + let count = 0; + while (g_i < g.length && s_i < s.length) { + if (g[g_i] <= s[s_i]) { + g_i++; + s_i++; + count += 1 + } else { + s_i++ + } + } + + return count +} \ No newline at end of file diff --git a/Week 03/id_441/binary-tree-level-order-traversal.js b/Week 03/id_441/binary-tree-level-order-traversal.js new file mode 100644 index 000000000..cc877310a --- /dev/null +++ b/Week 03/id_441/binary-tree-level-order-traversal.js @@ -0,0 +1,38 @@ +// https://leetcode-cn.com/problems/binary-tree-level-order-traversal/#/description +// 二叉树的层次遍历 +// 1.广度优先遍历 +var levelOrder = function (root) { + if (!root) return [] + let res = [], + queue = [root] + while (queue.length) { + let arr = [], + nextNode = [] + while (queue.length) { + let curr = queue.shift() + arr.push(curr.val) + if (curr.left) nextNode.push(curr.left) + if (curr.right) nextNode.push(curr.right) + } + queue = nextNode + res.push(arr) + } + return res +} +//2.深度优先遍历,记录每一层来进行访问 +var levelOrder = function (root) { + if(!root) return []; + const result = []; + return levelOrder([root.left,root.right]) +} + +function serach(layers,node,k) { + if(node === null) return ; + if(!layers[k]){ + layers[k] = [node.val] + }else{ + layers[k].push(node.val) + } + serach(layers, node.left, k+1) + serach(layers, node.right, k+1) +} diff --git a/Week 03/id_441/coin-change.js b/Week 03/id_441/coin-change.js new file mode 100644 index 000000000..2004339a1 --- /dev/null +++ b/Week 03/id_441/coin-change.js @@ -0,0 +1,6 @@ +// https://leetcode-cn.com/problems/coin-change/ +// 零钱兑换的算法 +// 暴力解法 +var coinChange = function(coins, amount) { + +} \ No newline at end of file diff --git a/Week 03/id_446/LeetCode_127_446.cpp b/Week 03/id_446/LeetCode_127_446.cpp new file mode 100644 index 000000000..abd219f63 --- /dev/null +++ b/Week 03/id_446/LeetCode_127_446.cpp @@ -0,0 +1,42 @@ +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail; + if (dict.find(endWord) == dict.end()) { + return 0; + } + head.insert(beginWord); + tail.insert(endWord); + int ladder = 2; + while (!head.empty() && !tail.empty()) { + if (head.size() < tail.size()) { + phead = &head; + ptail = &tail; + } else { + phead = &tail; + ptail = &head; + } + unordered_set temp; + for (auto it = phead -> begin(); it != phead -> end(); it++) { + string word = *it; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (ptail -> find(word) != ptail -> end()) { + return ladder; + } + if (dict.find(word) != dict.end()) { + temp.insert(word); + dict.erase(word); + } + } + word[i] = t; + } + } + ladder++; + phead -> swap(temp); + } + return 0; + } +}; \ No newline at end of file diff --git a/Week 03/id_446/LeetCode_200_446.cpp b/Week 03/id_446/LeetCode_200_446.cpp new file mode 100644 index 000000000..4b45f4cfc --- /dev/null +++ b/Week 03/id_446/LeetCode_200_446.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int numIslands(vector>& grid) { + int row = grid.size(); + if(row == 0) return 0; + int col = grid[0].size(); + int islands = 0; + for(int i = 0; i < row; ++i){ + for(int j = 0; j < col; ++j){ + if(grid[i][j] == '1') islands++; + dfs(grid, i, j); + } + } + return islands; + } + + void dfs(vector>& grid, int i, int j){ + int row = grid.size(); + int col = grid[0].size(); + if((i < 0) || (j < 0) || (i >= row) || (j >= col) || (grid[i][j] == '0')) return; + grid[i][j] = '0'; + dfs(grid, i - 1, j); + dfs(grid, i + 1, j); + dfs(grid, i , j - 1); + dfs(grid, i , j + 1); + } +}; \ No newline at end of file diff --git a/Week 03/id_446/LeetCode_455_446.cpp b/Week 03/id_446/LeetCode_455_446.cpp new file mode 100644 index 000000000..6056751e0 --- /dev/null +++ b/Week 03/id_446/LeetCode_455_446.cpp @@ -0,0 +1,19 @@ +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + int indexG = 0; + int indexS = 0; + while(indexG < g.size() && indexS < s.size()){ + if(g[indexG] <= s[indexS]){ + indexG++; + indexS++; + } + else{ + indexS++; + } + } + return indexG; + } +}; \ No newline at end of file diff --git a/Week 03/id_446/LeetCode_860_446.cpp b/Week 03/id_446/LeetCode_860_446.cpp new file mode 100644 index 000000000..9f9fd7af3 --- /dev/null +++ b/Week 03/id_446/LeetCode_860_446.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0; + int ten = 0; + for(int i = 0; i < bills.size(); ++i){ + int current_order = bills[i]; + if(current_order == 5){ + five++; + } + else if(current_order == 10){ + five--; + ten++; + } + else if(ten > 0){ + ten-- ; + five--; + } + else{ + five -= 3; + } + + if(five < 0) return false; + } + return true; + } +}; \ No newline at end of file diff --git a/Week 03/id_451/LeetCode_153_451.go b/Week 03/id_451/LeetCode_153_451.go new file mode 100644 index 000000000..9d1e92c33 --- /dev/null +++ b/Week 03/id_451/LeetCode_153_451.go @@ -0,0 +1,26 @@ +func findMin(nums []int) int { + if len(nums) == 0 { + return 1<<32 - 1 + } + if len(nums) == 1 { + return nums[0] + } + if len(nums) == 2 { + if nums[0] < nums[1] { + return nums[0] + } + return nums[1] + } + r := len(nums) - 1 + mid := r / 2 + if nums[0] < nums[mid] && nums[mid] < nums[r] { + return nums[0] + } + if nums[0] > nums[mid] { + return findMin(nums[0 : mid+1]) + } + if nums[mid] > nums[r] { + return findMin(nums[mid : r+1]) + } + return math.MinInt64 +} diff --git a/Week 03/id_451/LeetCode_154_451.go b/Week 03/id_451/LeetCode_154_451.go new file mode 100644 index 000000000..37c3b7672 --- /dev/null +++ b/Week 03/id_451/LeetCode_154_451.go @@ -0,0 +1,32 @@ +func min(a, b int) int { + if a > b { + return b + } + return a +} +func findMin(nums []int) int { + if len(nums) == 0 { + return 1<<32 - 1 + } + if len(nums) == 1 { + return nums[0] + } + if len(nums) == 2 { + if nums[0] < nums[1] { + return nums[0] + } + return nums[1] + } + r := len(nums) - 1 + mid := r / 2 + if nums[0] < nums[mid] && nums[mid] < nums[r] { + return nums[0] + } + if nums[0] > nums[mid] { + return findMin(nums[0 : mid+1]) + } + if nums[mid] > nums[r] { + return findMin(nums[mid : r+1]) + } + return min(findMin(nums[0:mid]), findMin(nums[mid:r+1])) +} diff --git a/Week 03/id_451/LeetCode_33_451.go b/Week 03/id_451/LeetCode_33_451.go new file mode 100644 index 000000000..9b97ee4f8 --- /dev/null +++ b/Week 03/id_451/LeetCode_33_451.go @@ -0,0 +1,44 @@ +func _search(nums []int, l, r, t int) int { + + if r-l == 0 { + if nums[r] == t { + return r + } + return -1 + } + + if r-l == 1 { + if nums[r] == t { + return r + } + if nums[l] == t { + return l + } + return -1 + } + m := (l + r) / 2 + if nums[l] <= nums[m] && nums[m] < nums[r] { + if t >= nums[l] && t <= nums[r] { + if t >= nums[m] { + return _search(nums, m, r, t) + } + return _search(nums, l, m, t) + } + } + + a := _search(nums, l, m, t) + if a != -1 { + return a + } + b := _search(nums, m, r, t) + if b != -1 { + return b + } + return -1 +} +func search(nums []int, target int) int { + if len(nums) == 0 { + return -1 + } + return _search(nums, 0, len(nums)-1, target) +} diff --git a/Week 03/id_451/LeetCode_45_451.go b/Week 03/id_451/LeetCode_45_451.go new file mode 100644 index 000000000..ec677aa94 --- /dev/null +++ b/Week 03/id_451/LeetCode_45_451.go @@ -0,0 +1,22 @@ +func min(ns ...int) int { + t := 1<<32 - 1 + for _, n := range ns { + if n < t { + t = n + } + } + return t +} +func jump(nums []int) int { + l := len(nums) + dp := make([]int, l) + dp[l-1] = 0 + for i := l - 2; i >= 0; i-- { + n := nums[i] + dp[i] = 1<<32 - 1 + for j := i + 1; j <= l-1 && j <= i+n; j++ { + dp[i] = min(dp[i], dp[j]+1) + } + } + return dp[0] +} diff --git a/Week 03/id_451/LeetCode_860_451.go b/Week 03/id_451/LeetCode_860_451.go new file mode 100644 index 000000000..a69b67a0f --- /dev/null +++ b/Week 03/id_451/LeetCode_860_451.go @@ -0,0 +1,28 @@ +func lemonadeChange(bills []int) bool { + sum := make(map[int]int) + for _, b := range bills { + switch b { + case 5: + sum[5] += 1 + case 10: + sum[10] += 1 + if sum[5] <= 0 { + return false + } + sum[5] -= 1 + case 20: + sum[20] += 1 + if sum[10] > 0 && sum[5] > 0 { + sum[10] -= 1 + sum[5] -= 1 + } else if sum[5] >= 3 { + sum[5] -= 3 + } else { + return false + } + default: + panic("never") + } + } + return true +} diff --git a/Week 03/id_466/LeetCode_122_466.java b/Week 03/id_466/LeetCode_122_466.java new file mode 100644 index 000000000..f972c6f01 --- /dev/null +++ b/Week 03/id_466/LeetCode_122_466.java @@ -0,0 +1,67 @@ +//给定一个数组,它的第 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。 +// Related Topics 贪心算法 数组 +package com.aseara.leetcode.editor.cn.a122; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 122.买卖股票的最佳时机 II
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class BestTimeToBuyAndSellStockIi { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(7, solution.maxProfit(new int[] {7,1,5,3,6,4})); + assertEquals(4, solution.maxProfit(new int[] {1,2,3,4,5})); + assertEquals(0, solution.maxProfit(new int[] {7,6,4,3,1})); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (prices[i + 1] > prices[i]) { + profit += prices[i + 1] - prices[i]; + } + } + return profit; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_466/LeetCode_126_466.java b/Week 03/id_466/LeetCode_126_466.java new file mode 100644 index 000000000..0161f1e86 --- /dev/null +++ b/Week 03/id_466/LeetCode_126_466.java @@ -0,0 +1,215 @@ +//给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则: +// +// +// 每次转换只能改变一个字母。 +// 转换过程中的中间单词必须是字典中的单词。 +// +// +// 说明: +// +// +// 如果不存在这样的转换序列,返回一个空列表。 +// 所有单词具有相同的长度。 +// 所有单词只由小写字母组成。 +// 字典中不存在重复的单词。 +// 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +// +// +// 示例 1: +// +// 输入: +//beginWord = "hit", +//endWord = "cog", +//wordList = ["hot","dot","dog","lot","log","cog"] +// +//输出: +//[ +// ["hit","hot","dot","dog","cog"], +//  ["hit","hot","lot","log","cog"] +//] +// +// +// 示例 2: +// +// 输入: +//beginWord = "hit" +//endWord = "cog" +//wordList = ["hot","dot","dog","lot","log"] +// +//输出: [] +// +//解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。 +// Related Topics 广度优先搜索 数组 字符串 回溯算法 +package com.aseara.leetcode.editor.cn.a126; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +/** + * desc: 126.单词接龙 II
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class WordLadderIi { + private Solution solution = new Solution(); + + @Test + void test1() { + String begin = "hit"; + String end = "cog"; + List dict = Arrays.asList("hot","dot","dog","lot","log","cog"); + Set> expected = new HashSet<>(Arrays.asList( + Arrays.asList("hit","hot","lot","log","cog"), + Arrays.asList("hit","hot","dot","dog","cog"))); + + assertIterableEquals(expected, new HashSet<>(solution.path2(begin, end, dict))); + + // [["red","ted","tad","tax"],["red","ted","tex","tax"],["red","rex","tex","tax"]] + begin = "red"; + end = "tax"; + dict = Arrays.asList("ted","tex","red","tax","tad","den","rex","pee"); + expected = new HashSet<>(Arrays.asList( + Arrays.asList("red","ted","tad","tax"), + Arrays.asList("red","ted","tex","tax"), + Arrays.asList("red","rex","tex","tax"))); + + assertIterableEquals(expected, new HashSet<>(solution.path2(begin, end, dict))); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + return path2(beginWord, endWord, wordList); + } + + + List> path1(String beginWord, String endWord, List wordList) { + + return Collections.emptyList(); + } + + + + + List> path2(String beginWord, String endWord, List wordList) { + Set dict = new HashSet<>(wordList); + if (!dict.contains(endWord)) { + return Collections.emptyList(); + } + + Map>> travelSet = new HashMap<>(); + travelSet.put(beginWord, new LinkedList<>()); + travelSet.get(beginWord).add(new LinkedList<>(Collections.singleton(beginWord))); + Map>> checkSet = new HashMap<>(); + checkSet.put(endWord, new LinkedList<>()); + checkSet.get(endWord).add(new LinkedList<>(Collections.singleton(endWord))); + + return bfs1(dict, travelSet, checkSet, true); + } + + private List> bfs1(Set dict, + Map>> travelSet, + Map>> checkSet, + boolean dir) { + if (travelSet.isEmpty()) { + return Collections.emptyList(); + } + + Map>> nextSet = new HashMap<>(); + + List> result = null; + + for (Map.Entry>> node : travelSet.entrySet()) { + String word = node.getKey(); + dict.remove(word); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + for (char j = 'a'; j <= 'z'; j++) { + if (temp == j) { + continue; + } + arr[i] = j; + String next = String.valueOf(arr); + arr[i] = temp; + + if (checkSet.containsKey(next)) { + if (result == null) { + result = new LinkedList<>(); + } + result.addAll(getPath(node.getValue(), checkSet.get(next), dir)); + + + } else if (dict.contains(next)){ + LinkedList> paths = + nextSet.computeIfAbsent(next, k -> new LinkedList<>()); + for (LinkedList path : node.getValue()) { + LinkedList newPath = new LinkedList<>(path); + newPath.add(next); + paths.add(newPath); + } + } + } + } + } + + if (result != null) { + return result; + } + + if (nextSet.size() >= checkSet.size()) { + return bfs1(dict, nextSet, checkSet, dir); + } else { + return bfs1(dict, checkSet, nextSet, !dir); + } + } + + private List> getPath(LinkedList> head, + LinkedList> tail, + boolean dir) { + if (dir) { + System.out.println(head); + System.out.println(tail); + List> paths = new LinkedList<>(); + for (LinkedList headP : head) { + for (LinkedList tailP : tail) { + paths.add(getPath(headP, tailP)); + } + } + System.out.println(paths); + System.out.println(); + return paths; + } + return getPath(tail, head, true); + } + + private LinkedList getPath(LinkedList head, + LinkedList tail) { + LinkedList path = new LinkedList<>(head); + + Iterator iter = tail.descendingIterator(); + while (iter.hasNext()) { + path.add(iter.next()); + } + + return path; + } + + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_466/LeetCode_127_466.java b/Week 03/id_466/LeetCode_127_466.java new file mode 100644 index 000000000..5828504b0 --- /dev/null +++ b/Week 03/id_466/LeetCode_127_466.java @@ -0,0 +1,785 @@ +//给定两个单词(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 广度优先搜索 +package com.aseara.leetcode.editor.cn.a127; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 127.单词接龙
+ * Date: 2019/10/31
+ * + * @author qiujingde + */ +class WordLadder { + private Solution solution = new Solution(); + + @Test + void test1() { + String begin = "hit"; + String end = "cog"; + List dict = Arrays.asList("hot","dot","dog","lot","log","cog"); + assertEquals(5, solution.ladderLength(begin, end, dict)); + + begin = "hit"; + end = "cog"; + dict = Arrays.asList("hot","dot","dog","lot","log"); + assertEquals(0, solution.ladderLength(begin, end, dict)); + + begin = "hot"; + end = "dot"; + dict = Arrays.asList("hot", "dog", "dot"); + assertEquals(2, solution.ladderLength(begin, end, dict)); + } + +} + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public int ladderLength(String beginWord, String endWord, List wordList) { + return path10(beginWord, endWord, wordList); + } + + private int path1(String beginWord, String endWord, List wordList) { + LinkedList checkList = new LinkedList<>(); + for (String w : wordList) { + if (!w.equals(endWord)) { + checkList.add(w); + } + } + + if (checkList.size() == wordList.size()) { + return 0; + } + + LinkedList queue = new LinkedList<>(); + queue.add(beginWord); + + int step = 1; + while (!queue.isEmpty() && !wordList.isEmpty()) { + step ++; + int batch = queue.size(); + for (int i = 0; i < batch; i++) { + String crt = queue.poll(); + if (canGo(crt, endWord)) { + return step; + } + int checkSize = checkList.size(); + for (int j = 0; j < checkSize; j++) { + String next = checkList.poll(); + if (canGo(crt, next)) { + queue.add(next); + } else { + checkList.add(next); + } + } + } + } + + return 0; + } + + private boolean canGo(String a, String b) { + int diff = 0; + for (int i = 0; i < a.length(); i++) { + diff += a.charAt(i) == b.charAt(i) ? 0 : 1; + if (diff > 1) { + return false; + } + } + return diff == 1; + } + + private int path2(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillMap(map1, map2, word); + } + fillMap(map1, map2, beginWord); + + if (map1.get(endWord) == null) { + return 0; + } + + // endWord -> *bc, a*c, ab* + Set checkSet = new HashSet<>(map1.remove(endWord)); + + LinkedList queue = new LinkedList<>(); + queue.add(beginWord); + + int step = 1; + while (!queue.isEmpty() && !map1.isEmpty()) { + step++; + int batch = queue.size(); + for (int i = 0; i < batch; i++) { + String crt = queue.poll(); + List paths = map1.remove(crt); + if (paths == null) { + continue; + } + for (String path: paths) { + if (checkSet.contains(path)) { + return step; + } + for (String next : map2.get(path)) { + if (map1.containsKey(next)) { + queue.add(next); + } + } + } + } + } + return 0; + } + + private void fillMap(Map> map1, Map> map2, String word) { + for (int i = 0; i < word.length(); i++) { + String pathWord = word.substring(0, i) + '*' + word.substring(i + 1); + map1.computeIfAbsent(word, k -> new LinkedList<>()).add(pathWord); + map2.computeIfAbsent(pathWord, k -> new LinkedList<>()).add(word); + } + } + + // 双向BFS + private int path3(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + for (String path : map1.get(beginWord)) { + if (map2.get(path).size() > 1) { + beginSet.add(path); + } + } + Set endSet = new HashSet<>(map1.get(endWord)); + for (String path : map1.get(endWord)) { + if (map2.get(path).size() > 1) { + endSet.add(path); + } + } + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + for (String path : beginSet) { + if (endSet.contains(path)) { + return step; + } + Set nextWords = map2.get(path); + if (nextWords != null) { + for (String nextWord : nextWords) { + if (!visited.contains(nextWord)) { + visited.add(nextWord); + for (String nextPath : map1.get(nextWord)) { + if (map2.get(nextPath).size() > 1) { + tempSet.add(nextPath); + } + } + } + } + } + } + beginSet = endSet; + endSet = tempSet; + } + + return 0; + } + + // 双向BFS 超出时间限制 + private int path4(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + fillNextLevelSet(map1, map2, beginSet, beginWord); + Set endSet = new HashSet<>(); + fillNextLevelSet(map1, map2, endSet, endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + System.out.println(beginSet); + System.out.println(endSet); + System.out.println(); + + step ++; + Set tempSet = new HashSet<>(); + + for (String path : beginSet) { + if (endSet.contains(path)) { + return step; + } + + for (String word : map2.get(path)) { + for (String nextPath : map1.get(word)) { + if (!path.equals(nextPath)) { + tempSet.add(nextPath); + } + } + } + } + beginSet = endSet; + endSet = tempSet; + } + + return 0; + } + + private void fillNextLevelSet( + Map> map1, + Map> map2, + Set tempSet, String word) { + for (String nextPath : map1.get(word)) { + Set words = map2.get(nextPath); + tempSet.add(nextPath); + } + } + + // 双向BFS + private int path5(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + for (int i = 0; i < word.length(); i++) { + String path = word.substring(0, i) + '*' + word.substring(i + 1); + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + for (int i = 0; i < beginWord.length(); i++) { + String pathWord = beginWord.substring(0, i) + '*' + beginWord.substring(i + 1); + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp; + if (beginSet.size() < endSet.size()) { + temp = beginSet; + beginSet = endSet; + endSet = temp; + } + temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + endSet = temp; + } + + return 0; + } + + // 双向BFS 当前最优实现 33ms + private int path6(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + if (word.equals(beginWord)) { + continue; + } + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp; + if (beginSet.size() < endSet.size()) { + temp = beginSet; + beginSet = endSet; + endSet = temp; + } + temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + endSet = temp; + } + + return 0; + } + + // 双向BFS 递归实现 + private int path7(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(endWord); + + return getStep(wordMap, beginSet, endSet, visited, 1); + } + + private int getStep(Map> wordMap, + Set beginSet, Set endSet, + Set visited, int step) { + + Set temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step + 1; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + if (temp.isEmpty()) { + return 0; + } + + if (beginSet.size() < temp.size()) { + endSet = beginSet; + beginSet = temp; + } else { + endSet = temp; + } + + return getStep(wordMap, beginSet, endSet, visited, step + 1); + } + + // 双向BFS 使用 meets + private int path8(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for (String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set meets = new HashSet<>(wordList); + + Set beginSet = new HashSet<>(); + beginSet.add(beginWord); + Set endSet = new HashSet<>(); + endSet.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + meets.removeAll(beginSet); + for (String word : beginSet) { + for (String path: map1.get(word)) { + for (String nextWord : map2.get(path)) { + if (meets.contains(nextWord)) { + if (endSet.contains(nextWord)) { + return step; + } + tempSet.add(nextWord); + } + } + } + } + if (endSet.size() < tempSet.size()) { + beginSet = tempSet; + } else { + beginSet = endSet; + endSet = tempSet; + } + } + + return 0; + } + + private void fillSetMap(Map> map1, Map> map2, String word) { + Set paths = map1.computeIfAbsent(word, k -> new HashSet<>()); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = String.valueOf(arr); + arr[i] = temp; + paths.add(pathWord); + map2.computeIfAbsent(pathWord, k -> new HashSet<>()).add(word); + } + } + + // 双向BFS 使用 meets 按字符遍历 + private int path9(String beginWord, String endWord, List wordList) { + Set meets = new HashSet<>(wordList); + if (!meets.contains(endWord)) { + return 0; + } + + int length = beginWord.length(); + + Set beginSet = new HashSet<>(); + beginSet.add(beginWord); + Set endSet = new HashSet<>(); + endSet.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + meets.removeAll(beginSet); + for (String word : beginSet) { + char[] arr = word.toCharArray(); + for (int i = 0; i < length; i++) { + char temp = arr[i]; + for (char j = 'a'; j <= 'z'; j++) { + if (temp == j) { + continue; + } + arr[i] = j; + String nextWord = String.valueOf(arr); + if (meets.contains(nextWord)) { + if (endSet.contains(nextWord)) { + return step; + } + tempSet.add(nextWord); + } + } + arr[i] = temp; + } + } + if (endSet.size() < tempSet.size()) { + beginSet = tempSet; + } else { + beginSet = endSet; + endSet = tempSet; + } + } + + return 0; + } + + + + // 双向BFS + private int path10(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set meets = new HashSet<>(wordList); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + meets.remove(word); + for (String nextWord : wordMap.get(word)) { + if (meets.contains(nextWord)) { + temp.add(nextWord); + } + } + } + + if (temp.size() > beginSet.size()) { + endSet = temp; + } else { + endSet = beginSet; + beginSet = temp; + } + } + + return 0; + } + + private int path11(String beginWord, String endWord, List wordList) { + if (wordList == null || wordList.size() == 0) return 0; + HashSet start = new HashSet<>(); + HashSet end = new HashSet<>(); + HashSet dic = new HashSet<>(wordList); + start.add(beginWord); + end.add(endWord); + if (!dic.contains(endWord)) return 0; + return bfs(start, end, dic, 2); + } + + private int bfs(HashSet st, HashSet ed, HashSet dic, int l) { + //双端查找的时候,若是有任意一段出现了“断裂”,也就是说明不存在能够连上的路径,则直接返回0 + if (st.size() == 0) return 0; + if (st.size() > ed.size()) {//双端查找,为了优化时间,永远用少的去找多的,比如开始的时候塞进了1000个,而结尾只有3个,则肯定是从少的那一端开始走比较好 + return bfs(ed, st, dic, l); + } + //BFS的标记行为,即使用过的不重复使用 + dic.removeAll(st); + //收集下一层临近点 + HashSet next = new HashSet<>(); + for (String s : st) { + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char tmp = arr[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (tmp == c) continue; + arr[i] = c ; + String nstr = new String(arr); + if (dic.contains(nstr)) { + if (ed.contains(nstr)) return l; + else next.add(nstr); + } + } + arr[i] = tmp; + } + } + return bfs(next, ed, dic, l + 1); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_466/LeetCode_153_466.java b/Week 03/id_466/LeetCode_153_466.java new file mode 100644 index 000000000..421510aee --- /dev/null +++ b/Week 03/id_466/LeetCode_153_466.java @@ -0,0 +1,84 @@ +//假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +// +// ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +// +// 请找出其中最小的元素。 +// +// 你可以假设数组中不存在重复元素。 +// +// 示例 1: +// +// 输入: [3,4,5,1,2] +//输出: 1 +// +// 示例 2: +// +// 输入: [4,5,6,7,0,1,2] +//输出: 0 +// Related Topics 数组 二分查找 +package com.aseara.leetcode.editor.cn.a153; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 153.寻找旋转排序数组中的最小值
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class FindMinimumInRotatedSortedArray { + private Solution solution = new Solution(); + + @Test + void test1() { + int[] test = new int[] {3,4,5,1,2}; + assertEquals(1, solution.findMin(test)); + + test = new int[] {4,5,6,7,0,1,2}; + assertEquals(0, solution.findMin(test)); + + test = new int[] {1,2,3}; + assertEquals(1, solution.findMin(test)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int findMin(int[] nums) { + int index = binarySearch(nums, 0, nums.length - 1); + return nums[index]; + } + + private int binarySearch(int[] nums, int start, int end) { + if (start == end) { + return end; + } + + if (end - start == 1) { + if (nums[start] > nums[end]) { + return end; + } + return 0; + } + + int mid = start + (end - start) / 2; + // 从 mid 到 end 正序 + if (nums[mid] < nums[end]) { + if (nums[mid - 1] > nums[mid]) { + return mid; + } + end = mid - 1; + } else { + if (nums[mid] > nums[mid + 1]) { + return mid + 1; + } + start = mid + 1; + } + return binarySearch(nums, start, end); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_466/LeetCode_200_466.java b/Week 03/id_466/LeetCode_200_466.java new file mode 100644 index 000000000..8530ec96c --- /dev/null +++ b/Week 03/id_466/LeetCode_200_466.java @@ -0,0 +1,99 @@ +//给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 +// +// 示例 1: +// +// 输入: +//11110 +//11010 +//11000 +//00000 +// +//输出: 1 +// +// +// 示例 2: +// +// 输入: +//11000 +//11000 +//00100 +//00011 +// +//输出: 3 +// +// Related Topics 深度优先搜索 广度优先搜索 并查集 +package com.aseara.leetcode.editor.cn.a200; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 200.岛屿数量
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class NumberOfIslands { + private Solution solution = new Solution(); + + @Test + void test1() { + char[][] island = new char[][] { + new char[] {'1','1','1','1','0'}, + new char[] {'1','1','0','1','0'}, + new char[] {'1','1','0','0','0'}, + new char[] {'0','0','0','0','0'} + }; + assertEquals(1, solution.numIslands(island)); + + island = new char[][] { + new char[] {'1','1','0','0','0'}, + new char[] {'1','1','0','0','0'}, + new char[] {'0','0','1','0','0'}, + new char[] {'0','0','0','1','1'} + }; + assertEquals(3, solution.numIslands(island)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public int numIslands(char[][] grid) { + int cnt = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + cnt ++; + destroyIsland(grid, i, j); + } + } + } + return cnt; + } + + private void destroyIsland(char[][] grid, int x, int y) { + grid[x][y] = '0'; + + if (x - 1 >= 0 && grid[x - 1][y] == '1') { + destroyIsland(grid, x - 1, y); + } + + if (x + 1 < grid.length && grid[x + 1][y] == '1') { + destroyIsland(grid, x + 1, y); + } + + if (y - 1 >= 0 && grid[x][y - 1] == '1') { + destroyIsland(grid, x, y - 1); + } + + if (y + 1 < grid[x].length && grid[x][y + 1] == '1') { + destroyIsland(grid, x, y + 1); + } + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_466/LeetCode_860_466.java b/Week 03/id_466/LeetCode_860_466.java new file mode 100644 index 000000000..a937ddaab --- /dev/null +++ b/Week 03/id_466/LeetCode_860_466.java @@ -0,0 +1,115 @@ +//在柠檬水摊上,每一杯柠檬水的售价为 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 贪心算法 +package com.aseara.leetcode.editor.cn.a860; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * desc: 860.柠檬水找零
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class LemonadeChange { + private Solution solution = new Solution(); + + @Test + void test1() { + assertTrue(solution.lemonadeChange(new int[] {5,5,5,10,20})); + assertTrue(solution.lemonadeChange(new int[] {5,5,10})); + assertFalse(solution.lemonadeChange(new int[] {10,10})); + assertFalse(solution.lemonadeChange(new int[] {5,5,10,10,20})); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean lemonadeChange(int[] bills) { + // 各种钱的数量 5 10 20 + int[] cnt = new int[2]; + + for (int bill : bills) { + if (bill == 5) { + cnt[0] ++; + } else if (bill == 10) { + if (cnt[0] == 0) { + return false; + } + cnt[0] --; + cnt[1] ++; + } else if (bill == 20) { + if (cnt[0] == 0) { + return false; + } + if (cnt[0] < 3 && cnt[1] == 0) { + return false; + } + if (cnt[1] > 0) { + cnt[1] --; + cnt[0] --; + } else { + cnt[0] = cnt[0] -3; + } + } + } + + return true; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_471/LeetCode_122_471.java b/Week 03/id_471/LeetCode_122_471.java new file mode 100644 index 000000000..d749c8f48 --- /dev/null +++ b/Week 03/id_471/LeetCode_122_471.java @@ -0,0 +1,19 @@ +class Solution { + public int maxProfit(int[] prices) { + + if (prices.length == 0) { + return 0; + } + + int sale = 0; + int hold = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + int tempSale = sale; + sale = Math.max(sale, hold + prices[i]); + hold = Math.max(hold, tempSale - prices[i]); + } + + return sale; + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_127_471.java b/Week 03/id_471/LeetCode_127_471.java new file mode 100644 index 000000000..2c0c5dc95 --- /dev/null +++ b/Week 03/id_471/LeetCode_127_471.java @@ -0,0 +1,52 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + Set wordSet = new HashSet<>(); + Set visited = new HashSet<>(); + int level = 1; + + for (String word : wordList) { + wordSet.add(word); + } + + if (!wordSet.contains(endWord)) { + return 0; + } + beginSet.add(beginWord); + endSet.add(endWord); + + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + if (beginSet.size() > endSet.size()) { + Set temp = beginSet; + beginSet = endSet; + endSet = temp; + } + Set tempSet = new HashSet<>(); + for (String word : beginSet) { + char[] wordArray = word.toCharArray(); + for (int i = 0; i < wordArray.length; i++) { + char oldChar = wordArray[i]; + for (int j = 0; j < 26; j++) { + wordArray[i] = (char)('a' + j); + String wordString = String.valueOf(wordArray); + if (endSet.contains(wordString)) { + return level + 1; + } + if (!visited.contains(wordString) && wordList.contains(wordString)) { + //System.out.println(wordString); + + visited.add(wordString); + tempSet.add(wordString); + } + } + wordArray[i] = oldChar; + } + } + beginSet = tempSet; + level++; + } + + return 0; + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_200_471.java b/Week 03/id_471/LeetCode_200_471.java new file mode 100644 index 000000000..0fb5fb902 --- /dev/null +++ b/Week 03/id_471/LeetCode_200_471.java @@ -0,0 +1,28 @@ +class Solution { + public int numIslands(char[][] grid) { + int num = 0; + int path[][] = new int[][]{{0, -1}, {0,1}, {1,0}, {-1,0}}; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + num++; + dfs(i, j, grid, path); + } + } + } + + return num; + } + + public void dfs(int x, int y, char[][] grid, int[][] path) { + //terminator + if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == '0') { + return; + } + grid[x][y] = '0'; + for (int i = 0; i < path.length; i++){ + dfs(x + path[i][0], y + path[i][1], grid, path); + } + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_33_471.java b/Week 03/id_471/LeetCode_33_471.java new file mode 100644 index 000000000..9a6d9a41c --- /dev/null +++ b/Week 03/id_471/LeetCode_33_471.java @@ -0,0 +1,39 @@ +class Solution { + public int search(int[] nums, int target) { + int left = 0, right = nums.length-1; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[left] <= nums[mid]) { + if (target >= nums[left] && target <= nums[mid]) { + return binarySearch(left, mid, nums, target); + } else { + left = mid + 1; + } + } else { + if (target >= nums[mid] && target <= nums[right]) { + return binarySearch(mid, right, nums, target); + } else { + right = mid - 1; + } + } + } + + return -1; + } + + public int binarySearch(int left, int right, int[] nums, int target) { + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_455_471.java b/Week 03/id_471/LeetCode_455_471.java new file mode 100644 index 000000000..c751470fb --- /dev/null +++ b/Week 03/id_471/LeetCode_455_471.java @@ -0,0 +1,15 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + + int i = 0, j = 0; + while (i < g.length && j < s.length) { + if (g[i] <= s[j++]) { + i++; + } + } + + return i; + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_529_471.java b/Week 03/id_471/LeetCode_529_471.java new file mode 100644 index 000000000..78bceb3c1 --- /dev/null +++ b/Week 03/id_471/LeetCode_529_471.java @@ -0,0 +1,48 @@ +class Solution { + public char[][] updateBoard(char[][] board, int[] click) { + int x = click[0], y = click[1]; + if (board[x][y] == 'M') { + board[x][y] = 'X'; + return board; + } + + dfs(x, y, board); + + return board; + } + + public void dfs(int x, int y, char[][] board) { + if (x < 0 || x >= board.length || y < 0 || y >= board[x].length || board[x][y] != 'E') { + return; + } + + int num = findMines(x, y, board); + if (num != 0) { + board[x][y] = (char)('0'+num); + return; + + } + + board[x][y] = 'B'; + + int path[][] = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + for (int i = 0; i < path.length; i++) { + dfs(x + path[i][0], y + path[i][1], board); + } + } + + public int findMines(int x, int y, char[][] board) { + int num = 0; + int tempx = x; + int tempy = y; + int path[][] = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + for (int i = 0; i < path.length; i++) { + x = tempx + path[i][0]; + y = tempy + path[i][1]; + if (x >= 0 && x < board.length && y >= 0 && y < board[x].length && board[x][y] == 'M') { + num++; + } + } + return num; + } +} \ No newline at end of file diff --git a/Week 03/id_471/LeetCode_860_471.java b/Week 03/id_471/LeetCode_860_471.java new file mode 100644 index 000000000..167c6c512 --- /dev/null +++ b/Week 03/id_471/LeetCode_860_471.java @@ -0,0 +1,28 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0, twenty = 0; + + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 20) { + if (ten > 0) { + ten--; + five--; + } else { + five -= 3; + } + + } else if (bills[i] == 10) { + five--; + ten++; + } else { + five++; + } + + if (five < 0) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_153_476.java b/Week 03/id_476/LeetCode_153_476.java new file mode 100644 index 000000000..30d79dc1d --- /dev/null +++ b/Week 03/id_476/LeetCode_153_476.java @@ -0,0 +1,24 @@ +public class LeetCode_153_FindMinimumInRotatedSortedArray { + public static void main(String[] args) { + Solution solution = new LeetCode_153_FindMinimumInRotatedSortedArray().new Solution(); + } + + + class Solution { + public int findMin(int[] nums) { + int low = 0; + int high = nums.length - 1; + while (low < high) { + // 左中位数 + int middle = low + (high - low) / 2; + if (nums[middle] > nums[high]) { + low = middle + 1; + } else { + high = middle; + } + } + return low == high ? nums[low] : null; + } + } + +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_200_476.java b/Week 03/id_476/LeetCode_200_476.java new file mode 100644 index 000000000..7125a12ce --- /dev/null +++ b/Week 03/id_476/LeetCode_200_476.java @@ -0,0 +1,110 @@ +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_200_NumberOfIslands { + public static void main(String[] args) { + Solution solution = new LeetCode_200_NumberOfIslands().new Solution(); + char[][] grid = new char[][]{{'1', '1', '0', '0', '0'}, {'1', '1', '0', '0', '0'}, {'0', '0', '1', '0', '0'}, {'0', '0', '0', '1', '1'}}; + assert solution.numIslands(grid) == 3; + grid = new char[][] { + {'1','0','0','1','1','1','0','1','1','0','0','0','0','0','0','0','0','0','0','0'}, + {'1','0','0','1','1','0','0','1','0','0','0','1','0','1','0','1','0','0','1','0'}, + {'0','0','0','1','1','1','1','0','1','0','1','1','0','0','0','0','1','0','1','0'}, + {'0','0','0','1','1','0','0','1','0','0','0','1','1','1','0','0','1','0','0','1'}, + {'0','0','0','0','0','0','0','1','1','1','0','0','0','0','0','0','0','0','0','0'}, + {'1','0','0','0','0','1','0','1','0','1','1','0','0','0','0','0','0','1','0','1'}, + {'0','0','0','1','0','0','0','1','0','1','0','1','0','1','0','1','0','1','0','1'}, + {'0','0','0','1','0','1','0','0','1','1','0','1','0','1','1','0','1','1','1','0'}, + {'0','0','0','0','1','0','0','1','1','0','0','0','0','1','0','0','0','1','0','1'}, + {'0','0','1','0','0','1','0','0','0','0','0','1','0','0','1','0','0','0','1','0'}, + {'1','0','0','1','0','0','0','0','0','0','0','1','0','0','1','0','1','0','1','0'}, + {'0','1','0','0','0','1','0','1','0','1','1','0','1','1','1','0','1','1','0','0'}, + {'1','1','0','1','0','0','0','0','1','0','0','0','0','0','0','1','0','0','0','1'}, + {'0','1','0','0','1','1','1','0','0','0','1','1','1','1','1','0','1','0','0','0'}, + {'0','0','1','1','1','0','0','0','1','1','0','0','0','1','0','1','0','0','0','0'}, + {'1','0','0','1','0','1','0','0','0','0','1','0','0','0','1','0','1','0','1','1'}, + {'1','0','1','0','0','0','0','0','0','1','0','0','0','1','0','1','0','0','0','0'}, + {'0','1','1','0','0','0','1','1','1','0','1','0','1','0','1','1','1','1','0','0'}, + {'0','1','0','0','0','0','1','1','0','0','1','0','1','0','0','1','0','0','1','1'}, + {'0','0','0','0','0','0','1','1','1','1','0','1','0','0','0','1','1','0','0','0'} + }; + assert solution.numIslands(grid) == 58; + // TODO bfs 的解法,结果比答案少一个,不知道错在什么地方。老师看到了烦请指点一下。 + // TODO bfs 的解法,结果比答案少一个,不知道错在什么地方。老师看到了烦请指点一下。 + // TODO bfs 的解法,结果比答案少一个,不知道错在什么地方。老师看到了烦请指点一下。 + } + + + class Solution { + public int numIslands(char[][] grid) { + + if (grid == null || grid.length == 0) return 0; + + int res = 0; + + int height = grid.length; + int width = grid[0].length; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (grid[i][j] == '1') { + bfs(i, j, width, height, grid); + res++; + } + } + } + return res; + } + + private void bfs(int i, int j, int width, int height, char[][] grid) { + + Queue queue = new LinkedList<>(); + queue.add(i * width + j); + while (!queue.isEmpty()) { + Integer index = queue.poll(); + int x = index / width; + int y = index % width; + if (x < height && x >= 0 && width > y && y >= 0 && grid[x][y] == '1') { + grid[x][y] = '0'; + queue.add((x + 1) * width + y); + queue.add(x * width + y + 1); + queue.add((x - 1) * width + y); + queue.add(x * width + y - 1); + } + } + } + } + + class Solution1 { + public int numIslands(char[][] grid) { + + if (grid == null || grid.length == 0) return 0; + + int res = 0; + + int height = grid.length; + int width = grid[0].length; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (grid[i][j] == '1') { + dfs(i, j, width, height, grid); + res++; + } + } + } + return res; + } + + private void dfs(int x, int y, int width, int height, char[][] grid) { + + if (x == height || x < 0 || width == y || y < 0 || grid[x][y] == '0') { + return; + } + grid[x][y] = '0'; + dfs(x + 1, y, width, height, grid); + dfs(x, y + 1, width, height, grid); + dfs(x - 1, y, width, height, grid); + dfs(x, y - 1, width, height, grid); + } + } + +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_33_476.java b/Week 03/id_476/LeetCode_33_476.java new file mode 100644 index 000000000..4a907f80d --- /dev/null +++ b/Week 03/id_476/LeetCode_33_476.java @@ -0,0 +1,108 @@ +public class LeetCode_33_SearchInRotatedSortedArray { + public static void main(String[] args) { + Solution solution = new LeetCode_33_SearchInRotatedSortedArray().new Solution(); + int res; + res = solution.search(new int[]{1}, 1); + assert res == 0; + res = solution.search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0); + assert res == 4; + res = solution.search(new int[]{4, 5, 6, 7, 0, 1, 2}, 3); + assert res == -1; + } + + + class Solution4 { + public int search(int[] nums, int target) { + + int low = 0; + int high = nums.length - 1; + while (low < high) { + int middle = low + (high - low + 1) / 2; + if ((nums[0] <= target && target < nums[middle]) || (nums[0] > nums[middle] && nums[middle] > target) || (nums[middle] < nums[0] && nums[0] <= target)) { + high = middle - 1; + } else { + low = middle; + } + } + + return low == high && nums[low] == target ? low : -1; + } + } + + class Solution { + public int search(int[] nums, int target) { + + if (nums.length == 0) return -1; + + // 找到旋转点 + int minIndex = findMinIndex(nums); + if (nums[minIndex] == target) return minIndex; + int low = 0; + int high = nums.length - 1; + if (target > nums[high]) { + high = minIndex - 1; + } else { + low = minIndex; + } + // 二分查找 + while (low < high) { + int middle = low + (high - low) / 2; + if (target > nums[middle]) { + low = middle + 1; + } else { + high = middle; + } + } + + return low == high && nums[low] == target ? low : -1; + } + + private int findMinIndex(int[] nums) { + + int low = 0; + int high = nums.length - 1; + while (low < high) { + // 左中位数 + int middle = low + (high - low) / 2; + if (nums[middle] > nums[high]) { + low = middle + 1; + } else { + high = middle; + } + } + return low; + } + } + + class Solutio2 { + public int search(int[] nums, int target) { + + int low = 0; + int high = nums.length - 1; + while (low < high) { + int middle = low + (high - low) / 2; + if ((nums[0] > target) ^ (nums[0] > nums[middle]) ^ (target > nums[middle])) { + low = middle + 1; + } else { + high = middle; + } + } + + return low == high && nums[low] == target ? low : -1; + } + } + + class Solution1 { + public int search(int[] nums, int target) { + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == target) { + return i; + } + } + + return -1; + } + } + +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_45_476.java b/Week 03/id_476/LeetCode_45_476.java new file mode 100644 index 000000000..a6c6ce1fe --- /dev/null +++ b/Week 03/id_476/LeetCode_45_476.java @@ -0,0 +1,27 @@ +public class LeetCode_45_JumpGameIi { + public static void main(String[] args) { + Solution solution = new LeetCode_45_JumpGameIi().new Solution(); + } + + + class Solution { + public int jump(int[] nums) { + + int steps = 0; + // 当前点能到达的最远距离 + int curEnd = 0; + // 当前点能到达的范围内的点能到达的最远距离 + int curFarthest = 0; + // 贪心算法,每次跳到当前点能到达的范围内能跳最远距离的点 + for (int i = 0; i < nums.length - 1; i++) { + curFarthest = Math.max(curFarthest, nums[i] + i); + if (curEnd == i) { + steps++; + curEnd = curFarthest; + } + } + return steps; + } + } + +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_74_476.java b/Week 03/id_476/LeetCode_74_476.java new file mode 100644 index 000000000..21cadb6a1 --- /dev/null +++ b/Week 03/id_476/LeetCode_74_476.java @@ -0,0 +1,31 @@ +public class LeetCode_74_SearchA2dMatrix { + public static void main(String[] args) { + Solution solution = new LeetCode_74_SearchA2dMatrix().new Solution(); + assert !solution.searchMatrix(new int[][]{{1}, {3}}, 2); + } + + + class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + + if (matrix.length == 0 || matrix[0].length == 0) return false; + int height = matrix.length; + int width = matrix[0].length; + + int low = 0; + int high = height * width - 1; + while (low < high) { + int middle = low + (high - low) / 2; + int x = middle / width; + int y = middle % width; + if (matrix[x][y] < target) { + low = middle + 1; + } else { + high = middle; + } + } + return matrix[low / width][low % width] == target; + } + } + +} \ No newline at end of file diff --git a/Week 03/id_476/LeetCode_860_476.java b/Week 03/id_476/LeetCode_860_476.java new file mode 100644 index 000000000..977500838 --- /dev/null +++ b/Week 03/id_476/LeetCode_860_476.java @@ -0,0 +1,29 @@ +public class LeetCode_860_LemonadeChange { + public static void main(String[] args) { + Solution solution = new LeetCode_860_LemonadeChange().new Solution(); + } + + + class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for (int bill : bills) { + if (bill == 5) { + five++; + } else if (bill == 10) { + five--; + ten++; + } else if (ten > 0) { + ten--; + five--; + } else { + five -= 3; + } + if (five < 0) return false; + } + return true; + } + } + +} \ No newline at end of file diff --git a/Week 03/id_481/leetcode_33_481.java b/Week 03/id_481/leetcode_33_481.java new file mode 100644 index 000000000..c5eda2888 --- /dev/null +++ b/Week 03/id_481/leetcode_33_481.java @@ -0,0 +1,66 @@ +//假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +// +// ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +// +// 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +// +// 你可以假设数组中不存在重复的元素。 +// +// 你的算法时间复杂度必须是 O(log n) 级别。 +// +// 示例 1: +// +// 输入: nums = [4,5,6,7,0,1,2], target = 0 +//输出: 4 +// +// +// 示例 2: +// +// 输入: nums = [4,5,6,7,0,1,2], target = 3 +//输出: -1 +// Related Topics 数组 二分查找 + +package leetcode.editor.cn; + +//Java:搜索旋转排序数组 +public class P33SearchInRotatedSortedArray { + public static void main(String[] args) { + Solution solution = new P33SearchInRotatedSortedArray().new Solution(); + // TO TEST + int[] arr = {4, 5, -2, -1, 0, 1, 2}; + //int[] arr = {-5, -1, 0, 2, 4, 5, 6, 7, 0, 1, 2}; + System.out.println(solution.search2(arr, -2)); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public int search2(int[] nums , int target){ + int left = 0; + int right = nums.length - 1; + while (left <= right){ + int mid = (left + right) / 2; + if(target == nums[mid]){ + return mid; + } + if(nums[left] <= nums[mid]){ + if(target >= nums[left] && target < nums[mid]){ + right = mid - 1; + } else { + left = mid + 1; + } + } else { + if(target > nums[mid] && target <= nums[right]){ + left = mid + 1; + } else { + right = mid - 1; + } + } + } + return -1; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week 03/id_481/leetcode_74_481.java b/Week 03/id_481/leetcode_74_481.java new file mode 100644 index 000000000..91ca5f943 --- /dev/null +++ b/Week 03/id_481/leetcode_74_481.java @@ -0,0 +1,67 @@ +//编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: +// +// +// 每行中的整数从左到右按升序排列。 +// 每行的第一个整数大于前一行的最后一个整数。 +// +// +// 示例 1: +// +// 输入: +//matrix = [ +// [1, 3, 5, 7], +// [10, 11, 16, 20], +// [23, 30, 34, 50] +//] +//target = 3 +//输出: true +// +// +// 示例 2: +// +// 输入: +//matrix = [ +// [1, 3, 5, 7], +// [10, 11, 16, 20], +// [23, 30, 34, 50] +//] +//target = 13 +//输出: false +// Related Topics 数组 二分查找 + +package leetcode.editor.cn; +//Java:搜索二维矩阵 +public class P74SearchA2dMatrix{ + public static void main(String[] args) { + Solution solution = new P74SearchA2dMatrix().new Solution(); + int[][] matrix = { + { 1, 2, 3, 4 , 20 }, + { 5, 6, 7, 10 , 21 }, + { 9, 10, 11, 12 , 22 }, + { 13, 14, 15, 16 , 23 } + }; + System.out.println(solution.searchMatrix(matrix,7)); + // TO TEST + } + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int row = 0; + int col = matrix[0].length-1; + while (row < matrix.length && col >= 0){ + if(matrix[row][col] == target){ + return true; + } else if(matrix[row][col] > target){ + col--; + } else { + row++; + } + } + return false; + } +} +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week 03/id_491/LeetCode_122_491.java b/Week 03/id_491/LeetCode_122_491.java new file mode 100644 index 000000000..b7cae53a2 --- /dev/null +++ b/Week 03/id_491/LeetCode_122_491.java @@ -0,0 +1,18 @@ +class Solution { + public int maxProfit(int[] prices) { + int result = 0; + int beginInt = 0; + for(int i = 0; i < prices.length; i ++){ + if(i == 0){ + beginInt = prices[i]; + } else if (prices[i] <= beginInt){ + beginInt = prices[i]; + } else { + result += prices[i] - beginInt; + beginInt = prices[i]; + } + } + + return result; + } +} diff --git a/Week 03/id_491/LeetCode_126_491.java b/Week 03/id_491/LeetCode_126_491.java new file mode 100644 index 000000000..275c877f4 --- /dev/null +++ b/Week 03/id_491/LeetCode_126_491.java @@ -0,0 +1,130 @@ +class Solution { + private Set visited = new HashSet<>(); + private List> stepList = new ArrayList<>(); + private List> stepListEnd = new ArrayList<>(); + private Set wordListSet; + private int min = 0; + + public List> findLadders(String beginWord, String endWord, List wordList) { + wordListSet = new HashSet<>(wordList); + if (!wordList.contains(endWord)) { + return this.stepList; + } + + List temp = new ArrayList<>(); + temp.add(beginWord); + stepList.add(temp); + + List tempEnd = new ArrayList<>(); + tempEnd.add(endWord); + stepListEnd.add(tempEnd); + + for (int k = 0; k < beginWord.length(); k++) { + if (beginWord.charAt(k) != endWord.charAt(k)) { + this.min++; + } + } + + mutation(wordList, 0, 0); + return stepList; + } + + private boolean found(int begin, int end) { + + if (begin + end < this.min) { + return false; + } + + boolean foundResult = false; + List> foundList = new ArrayList<>(); + for (int i = 0; i < stepList.size(); i++) { + String beginWord = stepList.get(i).get(begin); + for (int j = 0; j < stepListEnd.size(); j++) { + String endWord = stepListEnd.get(j).get(end); + if (beginWord.equals(endWord)) { + List tempFound = new ArrayList<>(); + tempFound.addAll(stepList.get(i)); + if (stepListEnd.get(j).size() > 1) { + for (int a = stepListEnd.get(j).size() - 2; a >= 0; a--) { + tempFound.add(stepListEnd.get(j).get(a)); + } + } + + foundList.add(tempFound); + foundResult = true; + } + } + } + + if (foundList.size() > 0) { + this.stepList = foundList; + } + + return foundResult; + } + + public void mutation(List wordList, int stepBegin, int stepEnd) { + List> tempSteps = new ArrayList<>(); + boolean foundResult = this.found(stepBegin, stepEnd); + if (foundResult) { + return; + } else { + if (stepBegin <= stepEnd) { + for (int i = 0; i < stepList.size(); i++) { + char[] chars = stepList.get(i).get(stepBegin).toCharArray(); + for (int j = 0; j < chars.length; j++) { + chars = stepList.get(i).get(stepBegin).toCharArray(); + for (char ch = 'a'; ch <= 'z'; ch++) { + chars[j] = ch; + String tmp = new String(chars); + if (wordListSet.contains(tmp)) { + if (visited.contains(tmp)) { + continue; + } + List tempTemp = new ArrayList(stepList.get(i)); + tempTemp.add(tmp); + tempSteps.add(tempTemp); + } + } + } + visited.add(stepList.get(i).get(stepBegin)); + } + stepList = tempSteps; + if (tempSteps.size() == 0 || stepBegin + 1 > wordList.size()) { + return; + } + + stepBegin++; + } else { + for (int i = 0; i < stepListEnd.size(); i++) { + char[] chars = stepListEnd.get(i).get(stepEnd).toCharArray(); + for (int j = 0; j < chars.length; j++) { + chars = stepListEnd.get(i).get(stepEnd).toCharArray(); + for (char ch = 'a'; ch <= 'z'; ch++) { + chars[j] = ch; + String tmp = new String(chars); + if (wordListSet.contains(tmp)) { + if (visited.contains(tmp)) { + continue; + } + + List tempTemp = new ArrayList(stepListEnd.get(i)); + tempTemp.add(tmp); + tempSteps.add(tempTemp); + } + } + } + visited.add(stepListEnd.get(i).get(stepEnd)); + } + stepListEnd = tempSteps; + if (tempSteps.size() == 0 || stepEnd + 1 > wordList.size()) { + return; + } + + stepEnd++; + } + + mutation(wordList, stepBegin, stepEnd); + } + } +} diff --git a/Week 03/id_491/LeetCode_127_491.java b/Week 03/id_491/LeetCode_127_491.java new file mode 100644 index 000000000..3dd0a2e12 --- /dev/null +++ b/Week 03/id_491/LeetCode_127_491.java @@ -0,0 +1,49 @@ +class Solution { + + private int min; + + private Set visited = new HashSet<>(); + + public int ladderLength(String beginWord, String endWord, List wordList) { + List temp = new ArrayList<>(); + temp.add(beginWord); + mutation(temp, endWord, wordList); + return this.min + 1; + } + + public void mutation(List beginWordList, String endWord, List wordList) { + List temp = new ArrayList<>(); + for (int i = 0; i < beginWordList.size(); i++) { + if (beginWordList.get(i).equals(endWord)) { + return; + } + for (int j = 0; j < wordList.size(); j++) { + if(visited.contains(wordList.get(j))){ + continue; + } + int steps = 0; + for (int k = 0; k < wordList.get(j).length(); k++) { + if (beginWordList.get(i).charAt(k) != wordList.get(j).charAt(k)) { + steps++; + } + + if (steps > 1) { + break; + } + } + + if (steps == 1) { + temp.add(wordList.get(j)); + visited.add(wordList.get(j)); + } + } + } + + this.min++; + if(temp.size() == 0 || this.min > wordList.size()){ + this.min = -1; + return; + } + mutation(temp, endWord, wordList); + } +} diff --git a/Week 03/id_491/LeetCode_153_491.java b/Week 03/id_491/LeetCode_153_491.java new file mode 100644 index 000000000..56db6ee59 --- /dev/null +++ b/Week 03/id_491/LeetCode_153_491.java @@ -0,0 +1,20 @@ +class Solution { + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while(left <= right) { + int mid = (left + right) / 2; + if(nums[left] <= nums[mid] && nums[mid] <= nums[right]) { + return nums[left]; + } else if(nums[left] >= nums[mid] && nums[mid] >= nums[right]) { + return nums[right]; + } else if(nums[left] <= nums[mid] && nums[mid] >= nums[right]) { + left = mid; + } else { + right = mid; + } + } + + return nums[left]; + } +} diff --git a/Week 03/id_491/LeetCode_200_491.java b/Week 03/id_491/LeetCode_200_491.java new file mode 100644 index 000000000..782e09459 --- /dev/null +++ b/Week 03/id_491/LeetCode_200_491.java @@ -0,0 +1,37 @@ +class Solution { + public int numIslands(char[][] grid) { + if(grid == null || grid.length == 0 || grid[0].length == 0){ + return 0; + } + int result = 0; + for(int i = 0; i < grid.length; i ++) { + for(int j = 0; j < grid[0].length; j ++) { + if(grid[i][j] == '1'){ + result++; + dfs(i, j, grid); + } + } + } + + return result; + } + + private void dfs(int row, int column, char[][] grid) { + grid[row][column] = 1; + if(row > 0 && grid[row - 1][column] == '1') { + dfs(row - 1, column, grid); + } + + if(row < grid.length - 1 && grid[row + 1][column] == '1') { + dfs(row + 1, column, grid); + } + + if(column > 0 && grid[row][column - 1] == '1') { + dfs(row, column - 1, grid); + } + + if(column < grid[0].length - 1 && grid[row][column + 1] == '1') { + dfs(row , column + 1, grid); + } + } +} diff --git a/Week 03/id_491/LeetCode_33_491.java b/Week 03/id_491/LeetCode_33_491.java new file mode 100644 index 000000000..655e7da8e --- /dev/null +++ b/Week 03/id_491/LeetCode_33_491.java @@ -0,0 +1,44 @@ +class Solution { + public int search(int[] nums, int target) { + int minIndex = findMin(nums); + int steps = nums.length - minIndex; + int left = 0; + int right = nums.length - 1; + while(left <= right) { + int mid = (left + right) / 2; + int realMid = getRealIndex(nums.length, steps, mid); + if(nums[realMid] < target){ + left = mid + 1; + } else if(nums[realMid] > target) { + right = mid - 1; + } else { + return realMid; + } + } + + return -1; + } + + private int getRealIndex(int length, int steps, int index) { + return (index - steps + length) % length; + } + + private int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while(left <= right) { + int mid = (left + right) / 2; + if(nums[left] <= nums[mid] && nums[mid] <= nums[right]) { + return left; + } else if(nums[left] >= nums[mid] && nums[mid] >= nums[right]) { + return right; + } else if(nums[left] <= nums[mid] && nums[mid] >= nums[right]) { + left = mid; + } else { + right = mid; + } + } + + return left; + } +} diff --git a/Week 03/id_491/LeetCode_455_491.java b/Week 03/id_491/LeetCode_455_491.java new file mode 100644 index 000000000..02d2378b8 --- /dev/null +++ b/Week 03/id_491/LeetCode_455_491.java @@ -0,0 +1,20 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int j = 0; + int i = 0; + int result = 0; + while(i < g.length && j < s.length){ + if(g[i] <= s[j]) { + i++; + j++; + result++; + } else { + j++; + } + } + + return result; + } +} diff --git a/Week 03/id_491/LeetCode_45_491.java b/Week 03/id_491/LeetCode_45_491.java new file mode 100644 index 000000000..caa76ad33 --- /dev/null +++ b/Week 03/id_491/LeetCode_45_491.java @@ -0,0 +1,31 @@ +class Solution { + public int jump(int[] nums) { + if(nums.length == 1){ + return 0; + } + + int steps = 0; + List stepsList = new ArrayList<>(); + stepsList.add(0); + int maxIndex = 0; + while(steps < nums.length - 1 && stepsList.size() > 0) { + steps++; + List tempList = new ArrayList<>(); + for(int j = 0; j < stepsList.size(); j++) { + int index = stepsList.get(j); + for(int i = nums[index]; i + index > maxIndex; i--) { + if(index + i >= nums.length - 1){ + return steps; + } + + tempList.add(index + i); + } + maxIndex = nums[index] + index; + } + + stepsList = tempList; + } + + return -1; + } +} diff --git a/Week 03/id_491/LeetCode_529_491.java b/Week 03/id_491/LeetCode_529_491.java new file mode 100644 index 000000000..e143a0491 --- /dev/null +++ b/Week 03/id_491/LeetCode_529_491.java @@ -0,0 +1,51 @@ +class Solution { + + public char[][] updateBoard(char[][] board, int[] click) { + if(board[click[0]][click[1]] == 'M') { + board[click[0]][click[1]] = 'X'; + return board; + } else { + // 深度优先搜索 + dfs(board, click[0], click[1]); + } + + return board; + } + + private void dfs(char[][] board, int row, int column) { + int m = 0; + boolean hasB = false; + for(int j = - 1; j <= 1; j++){ + for(int k = - 1; k <= 1; k++){ + if(row + j >= 0 && row + j < board.length + && column + k >= 0 && column + k < board[0].length) { + if(board[row + j][column + k] == 'M') { + m++; + } + + if(board[row + j][column + k] == 'B'){ + hasB = true; + } + } + } + } + + if(m > 0){ + board[row][column] = (char) ( m + '0'); + } else { + board[row][column] = 'B'; + for(int j = - 1; j <= 1; j++){ + for(int k = - 1; k <= 1; k++){ + if(row + j >= 0 && row + j < board.length + && column + k >= 0 && column + k < board[0].length) { + if(board[row + j][column + k] == 'E') { + dfs(board, row + j, column + k); + } + } + } + } + } + + + } +} diff --git a/Week 03/id_491/LeetCode_55_491.java b/Week 03/id_491/LeetCode_55_491.java new file mode 100644 index 000000000..f23a8d569 --- /dev/null +++ b/Week 03/id_491/LeetCode_55_491.java @@ -0,0 +1,25 @@ +class Solution { + public boolean canJump(int[] nums) { + if(nums.length == 1){ + return true; + } + + for (int i = nums.length - 1; i >= 0; i--) { + if (nums[i] == 0) { + boolean canReach = false; + for(int j = i - 1; j >= 0; j-- ){ + if(nums[j] + j > i || nums[j] + j == nums.length - 1){ + canReach = true; + break; + } + } + + if(!canReach) { + return false; + } + } + } + + return true; + } +} diff --git a/Week 03/id_491/LeetCode_74_491.java b/Week 03/id_491/LeetCode_74_491.java new file mode 100644 index 000000000..8033cac20 --- /dev/null +++ b/Week 03/id_491/LeetCode_74_491.java @@ -0,0 +1,23 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if(matrix.length == 0 || matrix[0].length == 0) { + return false; + } + int left = 0; + int right = matrix.length * matrix[0].length - 1; + while(left <= right) { + int mid = (left + right) / 2; + int row = mid / matrix[0].length; + int column = mid % matrix[0].length; + if(matrix[row][column] < target){ + left = mid + 1; + } else if(matrix[row][column] > target) { + right = mid - 1; + } else { + return true; + } + } + + return false; + } +} diff --git a/Week 03/id_491/LeetCode_860_491.java b/Week 03/id_491/LeetCode_860_491.java new file mode 100644 index 000000000..5aa2c81b1 --- /dev/null +++ b/Week 03/id_491/LeetCode_860_491.java @@ -0,0 +1,29 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int fiveBank = 0; + int tenBanke = 0; + for(int i = 0; i < bills.length; i++){ + if(bills[i] == 5){ + fiveBank++; + } else if(bills[i] == 10){ + if(fiveBank > 0) { + fiveBank--; + tenBanke++; + } else { + return false; + } + } else { + if(tenBanke > 0 && fiveBank > 0) { + fiveBank--; + tenBanke--; + } else if(fiveBank > 2){ + fiveBank -= 3; + } else { + return false; + } + } + } + + return true; + } +} diff --git a/Week 03/id_491/LeetCode_874_491.java b/Week 03/id_491/LeetCode_874_491.java new file mode 100644 index 000000000..6dc22d01e --- /dev/null +++ b/Week 03/id_491/LeetCode_874_491.java @@ -0,0 +1,109 @@ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + Map> row = new HashMap<>(); + Map> column = new HashMap<>(); + int x = 0; + int y = 0; + int result = 0; + for(int i = 0; i < obstacles.length; i++) { + int tempRow = obstacles[i][0]; + int tempColumn = obstacles[i][1]; + + if(tempRow == 0 && tempColumn == 0){ + continue; + } + + if(!row.containsKey(tempRow)) { + row.put(tempRow, new ArrayList<>()); + } + row.get(tempRow).add(tempColumn); + + if(!column.containsKey(tempColumn)) { + column.put(tempColumn, new ArrayList<>()); + } + column.get(tempColumn).add(tempRow); + } + + int direction = 0; + for(int i = 0 ; i < commands.length; i++) { + if(commands[i] == -1) { + direction = (direction + 1) % 4; + } else if(commands[i] == -2) { + direction = (direction - 1 + 4) % 4; + } else { + int begin = 0; + int end = 0; + switch(direction) { + case 0: + begin = y; + end = y += commands[i]; + if(row.containsKey(x)){ + int stop = end; + for(int k = 0; k < row.get(x).size(); k++){ + if(row.get(x).get(k) > begin && row.get(x).get(k) <= end){ + if(stop >= row.get(x).get(k)){ + stop = row.get(x).get(k) - 1; + } + } + } + y = stop; + } + break; + case 1: + begin = x; + end = x += commands[i]; + if(column.containsKey(y)){ + int stop = end; + for(int k = 0; k < column.get(y).size(); k++){ + if(column.get(y).get(k) > begin && column.get(y).get(k) <= end){ + if(stop >= column.get(y).get(k)){ + stop = column.get(y).get(k) - 1; + } + } + } + x = stop; + } + break; + case 2: + begin = y; + end = y -= commands[i]; + if(row.containsKey(x)){ + int stop = end; + for(int k = 0; k < row.get(x).size(); k++){ + if(row.get(x).get(k) >= end && row.get(x).get(k) < begin){ + if(stop <= row.get(x).get(k)){ + stop = row.get(x).get(k) + 1; + } + } + } + y = stop; + } + break; + case 3: + begin = x; + end = x -= commands[i]; + if(column.containsKey(y)){ + int stop = end; + for(int k = 0; k < column.get(y).size(); k++){ + if(column.get(y).get(k) >= end && column.get(y).get(k) < begin){ + if(stop <= column.get(y).get(k)){ + stop = column.get(y).get(k) + 1; + } + } + } + x = stop; + } + break; + } + + int tempResult = x * x + y * y; + if(tempResult > result) { + result = tempResult; + } + } + + + } + return result; + } +} diff --git a/Week 03/id_501/LeetCode_122_501.java b/Week 03/id_501/LeetCode_122_501.java new file mode 100644 index 000000000..66c1f8973 --- /dev/null +++ b/Week 03/id_501/LeetCode_122_501.java @@ -0,0 +1,27 @@ +package homework.week03; + +/** + * 122. 买卖股票的最佳时机 II + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii + */ +public class LeetCode_122_501{ + /** + * 思路:涨的话交易,跌就不交易 + * @param prices + * @return + */ + public static int maxProfit(int[] prices) { + int sum = 0; + for(int i = 1;i < prices.length; i ++){ + int val = prices[i] - prices[i-1]; + if(val > 0){ + sum += val; + } + } + return sum; + } + + public static void main(String[] args) { + System.out.println(maxProfit(new int[]{7,1,5,3,6,4})); + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_127_501.java b/Week 03/id_501/LeetCode_127_501.java new file mode 100644 index 000000000..8fa5b8527 --- /dev/null +++ b/Week 03/id_501/LeetCode_127_501.java @@ -0,0 +1,70 @@ +package homework.week03; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +import javafx.util.Pair; + +/** + * 127. 单词接龙 https://leetcode-cn.com/problems/word-ladder/description/ + */ +public class LeetCode_127_501{ + /** + * 思路: + * 1、预处理,把单词表中所有改变一次后的相同的单词关联起来。dog dig 都对应d*g + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength(String beginWord, String endWord, List wordList) { + if(!wordList.contains(endWord)){ + return 0; + } + int L = beginWord.length(); + Map> dic = new HashMap<>(); + + // 预处理 + for(String word : wordList){ + for(int i = 0;i < L; i++){ + String newWord = word.substring(0,i) + '*' + word.substring(i + 1,L); + List formatList = dic.getOrDefault(newWord, new ArrayList<>()); + formatList.add(word); + dic.put(newWord, formatList); + } + } + + // bfs + Queue> Q = new LinkedList>(); + Q.add(new Pair(beginWord,1)); + + Map visited = new HashMap<>(); + visited.put(beginWord, true); + + while(!Q.isEmpty()){ + Pair node = Q.remove(); + String word = node.getKey(); + int level = node.getValue(); + for(int i = 0;i < L;i++){ + String newWord = word.substring(0,i) + '*' + word.substring(i + 1,L); + for(String adjacentWord : dic.getOrDefault(newWord, new ArrayList())){ + if(adjacentWord.equals(endWord)){ + return level + 1; + } + if(!visited.containsKey(adjacentWord)){ + visited.put(adjacentWord, true); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + } + return 0; + } + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_153_501.java b/Week 03/id_501/LeetCode_153_501.java new file mode 100644 index 000000000..60522e83c --- /dev/null +++ b/Week 03/id_501/LeetCode_153_501.java @@ -0,0 +1,41 @@ +package homework.week03; + +/** + * 153. 寻找旋转排序数组中的最小值 + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + */ +public class LeetCode_153_501{ + /** + * 暴力遍历 + * @param nums + * @return + */ + public int findMin(int[] nums) { + int min = nums[0]; + + for(int i = 1;i < nums.length ; i ++){ + if(nums[i] < min){ + min = nums[i]; + } + } + return min; + } + + /** + * 二分法 + * @param nums + * @return + */ + public int findMin2(int[] nums){ + int left = 0,right = nums.length - 1; + while(left < right){ + int mid = (left + right)/2; + if(nums[mid] > nums[right]){ + left = mid + 1; + }else{ + right = mid; + } + } + return nums[left]; + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_200_501.java b/Week 03/id_501/LeetCode_200_501.java new file mode 100644 index 000000000..e4309f5fa --- /dev/null +++ b/Week 03/id_501/LeetCode_200_501.java @@ -0,0 +1,38 @@ +package homework.week03; + +/** + * 200. 岛屿数量 + * https://leetcode-cn.com/problems/number-of-islands/ + */ +public class LeetCode_200_501{ + public int numIslands(char[][] grid) { + if(grid == null || grid.length == 0){ + return 0; + } + int nr = grid.length; + int nc = grid[0].length; + int nums_islands = 0; + for(int r = 0;r < nr;++r){ + for(int c = 0;c < nc;++c){ + if(grid[r][c] == '1'){ + ++ nums_islands; + dfs(grid, r, c); + } + } + } + return nums_islands; + } + + public void dfs(char[][] grid,int r,int c){ + int nr = grid.length; + int nc = grid[0].length; + if(r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0'){ + return; + } + grid[r][c] = '0'; + dfs(grid,r - 1,c); + dfs(grid,r + 1,c); + dfs(grid,r,c - 1); + dfs(grid,r,c + 1); + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_33_501.java b/Week 03/id_501/LeetCode_33_501.java new file mode 100644 index 000000000..2b14b9ada --- /dev/null +++ b/Week 03/id_501/LeetCode_33_501.java @@ -0,0 +1,42 @@ +package homework.week03; + +/** + * 33. 搜索旋转排序数组 + * https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + */ +public class LeetCode_33_501{ + public int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + + // 找到最大值的数据下标 + while (start < end){ + int mid = Math.round(((float)start + end) / 2); + if(nums[mid] < nums[start]){ + end = mid - 1; + }else{ + start = mid; + } + } + + int n = nums.length; + int bias = (start + n) - (n -1); + start = 0; + end = nums.length - 1; + while(start <= end){ + int mid = (start + end) /2 ; + int mid_change = (mid + bias) % nums.length; + int value = nums[mid_change]; + + if(target == value){ + return mid_change; + } + if(target < value){ + end = mid - 1; + }else{ + start = mid + 1; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_55_501.java b/Week 03/id_501/LeetCode_55_501.java new file mode 100644 index 000000000..3d44b8320 --- /dev/null +++ b/Week 03/id_501/LeetCode_55_501.java @@ -0,0 +1,26 @@ +package homework.week03; + +/** + * 55. 跳跃游戏 + * https://leetcode-cn.com/problems/jump-game/ + */ +public class LeetCode_55_501{ + /** + * 思路: + * 从后往前遍历,当前索引 + 当前值 >= 最大索引,就把最大索引定义为当前索引,当前端索引为0,就到第一个元素了。 + * @param nums + * @return + */ + public static boolean canJump(int[] nums) { + int lastIndex = nums.length - 1; + for(int i = nums.length -1;i >=0; i--){ + if(i + nums[i] >= lastIndex){ + lastIndex = i; + } + } + return lastIndex == 0; + } + public static void main(String[] args) { + System.out.println(canJump(new int[]{3,2,1,0,4})); + } +} \ No newline at end of file diff --git a/Week 03/id_501/LeetCode_806_501.java b/Week 03/id_501/LeetCode_806_501.java new file mode 100644 index 000000000..5d7c4d150 --- /dev/null +++ b/Week 03/id_501/LeetCode_806_501.java @@ -0,0 +1,34 @@ +package homework.week03; + +/** + * 860. 柠檬水找零 + * https://leetcode-cn.com/problems/lemonade-change + */ +public class LeetCode_806_501{ + public static 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; + } + ten ++ ; + }else{ + if(five > 0 && ten > 0){ + five --; + ten --; + }else if(five > 2){ + five -= 3; + }else{ + return false; + } + } + } + return true; + } + public static void main(String[] args) { + System.out.println(lemonadeChange(new int[]{5,10})); + } +} \ No newline at end of file diff --git a/Week 03/id_506/LeetCode_127_506.java b/Week 03/id_506/LeetCode_127_506.java new file mode 100644 index 000000000..4f5cc9896 --- /dev/null +++ b/Week 03/id_506/LeetCode_127_506.java @@ -0,0 +1,102 @@ +class Solution { + + int count = 0; + + public int ladderLength(String beginWord, String endWord, List wordList) { + + + + if (beginWord.length() == 0 || endWord.length() == 0 || wordList.size() == 0){ + return 0; + } + + boolean result = false; + for (String s: wordList) { + + if (s.equals(endWord)){ + result = true; + } + } + + if (!result){ + return 0; + } + + + return bfs(beginWord, endWord, wordList); + + } + + public boolean isOne(String now, String next){ + + if (now.length() != next.length()){ + return false; + } + + char[] nowArray = now.toCharArray(); + char[] nextArray = next.toCharArray(); + int num = 0; + for (int i = 0; i < now.length(); i++){ + + if (nowArray[i] != nextArray[i]){ + num++; + } + } + if (num == 1){ + return true; + } + return false; + + } + + int bfs(String start, String end, List wordList){ + + List queue = new ArrayList<>(); + + Set visit = new HashSet<>(); + + queue.add(start); + visit.add(start); + + int step = 1; + while (!queue.isEmpty()){ + step ++; + + List now = new ArrayList<>(); + for (String s: queue) { + now.add(s); + } + queue.clear(); + for (String tmp: now + ) { + + + for (int i = 0; i < wordList.size(); i++) { + + if (!visit.contains(wordList.get(i))) { + + if (isOne(tmp, wordList.get(i))) { + + if (end.equals(wordList.get(i))) { + return step; + } + + queue.add(wordList.get(i)); + visit.add(wordList.get(i)); + + } + } + } + + } + + + } + + return 0; + + + } + + +} \ No newline at end of file diff --git a/Week 03/id_506/LeetCode_455_506.java b/Week 03/id_506/LeetCode_455_506.java new file mode 100644 index 000000000..da737ba13 --- /dev/null +++ b/Week 03/id_506/LeetCode_455_506.java @@ -0,0 +1,34 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + + + if (s.length == 0 || g.length == 0){ + return 0; + } + Arrays.sort(g); + Arrays.sort(s); + + int count = 0; + + int gPos = g.length -1; + for (int j = s.length -1; j >= 0 && gPos >= 0; j--){ + + + while(s[j] < g[gPos]){ + + + gPos --; + if (gPos < 0){ + return count; + } + } + count ++; + gPos --; + + } + return count; + + + + } +} \ No newline at end of file diff --git a/Week 03/id_506/LeetCode_860_506.java b/Week 03/id_506/LeetCode_860_506.java new file mode 100644 index 000000000..07695503c --- /dev/null +++ b/Week 03/id_506/LeetCode_860_506.java @@ -0,0 +1,52 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int fives = 0; + int tens = 0; + + for(int i : bills){ + + if (i == 5){ + fives++; + } + + if (i == 10){ + + if (fives < 1){ + return false; + } + + tens ++; + fives --; + + } + + if (i == 20){ + + if (tens == 0){ + if (fives < 3){ + return false; + } + } + if (tens > 0){ + if (fives < 1){ + return false; + } + } + + + if (tens > 0){ + tens --; + fives --; + + }else{ + fives -= 3; + } + + + } + + } + return true; + + } +} \ No newline at end of file diff --git a/Week 03/id_511/LeetCode_102_511.java b/Week 03/id_511/LeetCode_102_511.java new file mode 100644 index 000000000..c333a87b1 --- /dev/null +++ b/Week 03/id_511/LeetCode_102_511.java @@ -0,0 +1,93 @@ +package id_511; + +import java.util.ArrayList; +import java.util.List; + +/** + * @version 1.0 + * @Description: 二叉树的层次遍历 + * @author: bingyu + * @date: 2019/11/3 22:20 + */ +public class LeetCode_102_511 { + + public static class TreeNode{ + public int val; + public TreeNode left,right; + + public TreeNode(int val){ + this.val = val; + this.left = null; + this.right = null; + } + } + + List> levels = new ArrayList>(); + + //DFS递归 + //自己写不出来,目前反复看题解: + public void helper(TreeNode node, int level) { + // start the current level + if (levels.size() == level) + levels.add(new ArrayList()); + + // fulfil the current level + levels.get(level).add(node.val); + + // process child nodes for the next level + if (node.left != null) + helper(node.left, level + 1); + if (node.right != null) + helper(node.right, level + 1); + } + + public List> levelOrder(TreeNode root) { + if (root == null) return levels; + helper(root, 0); + return levels; + } + + + + + /*public static void inOrder(TreeNode root) { + + TreeNode cur = root; + // terminator 1.终止条件 + if (cur == null) { + // process result + return; + } + + // process current logic + if (cur.left != null) { + inOrder(cur.left); + } + + System.out.print(cur.val + ","); + + // drill down 进入下一层 + if (cur.right != null) { + inOrder(cur.right); + } + + }*/ + + //DFS + public static int numIslands(char[][] grid) { + + return 0; + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(3); + TreeNode a = new TreeNode(9); + TreeNode b = new TreeNode(20); + TreeNode c = new TreeNode(15); + TreeNode d = new TreeNode(7); + root.left = a; + root.right = b; + root.right.left = c; + root.right.right = d; + } +} diff --git a/Week 03/id_511/LeetCode_200_511.java b/Week 03/id_511/LeetCode_200_511.java new file mode 100644 index 000000000..10b9601a1 --- /dev/null +++ b/Week 03/id_511/LeetCode_200_511.java @@ -0,0 +1,50 @@ +package id_511; + +import java.util.ArrayList; +import java.util.List; + +/** + * @version 1.0 + * @Description: 岛屿数量 + * @author: bingyu + * @date: 2019/11/3 23:11 + */ +public class LeetCode_200_511 { + + //深度优先遍历 + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } + +} diff --git a/Week 03/id_511/NOTE.md b/Week 03/id_511/NOTE.md index a6321d6e2..09fb5094b 100644 --- a/Week 03/id_511/NOTE.md +++ b/Week 03/id_511/NOTE.md @@ -1,4 +1,8 @@ -# NOTE - - - +这周自己学习的感触 : +1.深度优先搜索DFS和广度优先搜索,经过老师讲解知道了两者其实就是对树的一种遍历方式,看似两个高大上的名词,最终还是需要回归粗暴的遍历循环 +2.再求解看似巨大的问题时,都将其分解成最大的重复子问题,这与分治和递归是殊途同归,分治只是比递归多了合并结果,本质都是一样的,而DFS也是可以用 +递归实现的;这周其实大部分都是在学习递归的思想。 +3.这周仍然以看代码为主,理解老师讲的内容。 + + + diff --git a/Week 03/id_516/LeetCode_126_516.java b/Week 03/id_516/LeetCode_126_516.java new file mode 100644 index 000000000..ca7596625 --- /dev/null +++ b/Week 03/id_516/LeetCode_126_516.java @@ -0,0 +1,76 @@ +package cn.jomoon.nov03; + +import java.util.*; + +public class LeetCode126 { + public List> findLadders(String beginWord, String endWord, List wordList) { + Set meets = new HashSet<>(wordList); + if (!meets.contains(endWord)) return Collections.emptyList(); + Set begin = new HashSet<>(Collections.singleton(beginWord)); + Set end = new HashSet<>(Collections.singleton(endWord)); + + Map> neighborsMap = new HashMap<>(); + if (!doubleDfs(begin,end,neighborsMap,true,meets)) return Collections.emptyList(); + + List> result = new ArrayList<>(); + dfs(neighborsMap,result,beginWord,endWord,new LinkedList<>()); + return result; + } + + + private boolean doubleDfs(Set begin, Set end, Map> neighborsMap, boolean isFromBeginToEnd, Set meets) { + if (begin.size() == 0) return false; + + meets.removeAll(begin); + + boolean isMeetInCurrLevel = false; + + Set nextLevels = new HashSet<>(); + + for (String beginWord : begin) { + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char swap = arr[i]; + for (char j = 'a'; j <= 'z'; j++) { + arr[i] = j; + String newWord = String.valueOf(arr); + if (!meets.contains(newWord)) continue; + + nextLevels.add(newWord); + + String key = isFromBeginToEnd ? newWord : beginWord; + String neighbor = isFromBeginToEnd ? newWord : beginWord; + if (!neighborsMap.containsKey(key)) neighborsMap.put(key,new ArrayList<>()); + neighborsMap.get(key).add(neighbor); + + if (end.contains(newWord)) isMeetInCurrLevel = true; + } + arr[i] = swap; + } + } + + if (isMeetInCurrLevel) return true; + + if (nextLevels.size() > end.size()) return doubleDfs(end,nextLevels,neighborsMap,!isFromBeginToEnd,meets); + else return doubleDfs(nextLevels,end,neighborsMap,isFromBeginToEnd,meets); + } + + private void dfs(Map> neighborsMap, List> res, String beginWord, String endWord, Deque path) { + if (res.size() > 0 && path.size() == 0) return; + path.addLast(beginWord); + + if (beginWord.equals(endWord)) { + res.add(new ArrayList<>(path)); + } else if (neighborsMap.containsKey(beginWord)) { + for (String neighbor : neighborsMap.get(beginWord)) { + dfs(neighborsMap,res,neighbor,endWord,path); + } + } + + path.removeLast(); + } + + + + +} diff --git a/Week 03/id_516/LeetCode_200_516.java b/Week 03/id_516/LeetCode_200_516.java new file mode 100644 index 000000000..087d6c87d --- /dev/null +++ b/Week 03/id_516/LeetCode_200_516.java @@ -0,0 +1,65 @@ +package com.hjj.leetcode.nov02; + +public class LeetCode200 { + + + private int n; + private int m; + + public int numIslands2(char[][] grid) { + int count = 0; + n = grid.length; + if (n == 0) return 0; + m = grid[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + DFSMarking(grid, i, j); + ++count; + } + } + } + return count; + } + + private void DFSMarking(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return; + grid[i][j] = '0'; + DFSMarking(grid, i + 1, j); + DFSMarking(grid, i - 1, j); + DFSMarking(grid, i, j + 1); + DFSMarking(grid, i, j - 1); + } + + + int dx[] = {-1, 1, 0, 0}; + int dy[] = {0, 0, -1, 1}; + char[][] g; + + public int numIslands(char[][] grid) { + g = grid; + int islands = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '0') continue; + islands += sink(i, j); + } + } + return islands; + } + + private int sink(int i, int j) { + if (g[i][j] == '0') { + return 0; + } + g[i][j] = '0'; + for (int k = 0; k < dx.length; k++) { + int x = i + dx[k], y = j + dy[k]; + if (x >= 0 && x <= g.length && y >= 0 && y <= g[x].length) { + if (g[x][y] == '0') continue; + sink(x, y); + } + } + return 1; + } +} diff --git a/Week 03/id_516/LeetCode_455_516.java b/Week 03/id_516/LeetCode_455_516.java new file mode 100644 index 000000000..f4cfff396 --- /dev/null +++ b/Week 03/id_516/LeetCode_455_516.java @@ -0,0 +1,40 @@ +package cn.jomoon.nov03; + +import java.util.Arrays; + +public class LeetCode455 { + public static void main(String[] args) { + new LeetCode455().findContentChildren(new int[]{1,2,3},new int[]{3}); + } + + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int res = 0; + int usedIndex = 0; + for (int i = 0; i < g.length; i++) { + int greedy = g[i]; + for (; usedIndex < s.length;) { + if (s[usedIndex++] >= greedy) { + res++; + break; + } + } + } + return res; + } + + + public int findContentChildren2(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int gi = 0,si = 0; + while (gi < g.length && si < s.length) { + if (g[gi] <= s[si]) { + gi++; + } + si++; + } + return gi; + } +} diff --git a/Week 03/id_516/NOTE.md b/Week 03/id_516/NOTE.md index a6321d6e2..b7a676dc3 100644 --- a/Week 03/id_516/NOTE.md +++ b/Week 03/id_516/NOTE.md @@ -1,4 +1,151 @@ -# NOTE +## 代码模板 - + +## DFS + +```java +private static Set visited = new HashSet<>(); + public void dfs(TreeNode node) { + // terminator + if (node == null || visited.contains(node)) { + return; + } + visited.add(node); + // process + process(node); + // drill down + dfs(node.left); + dfs(node.right); + // reverse state + } + + private void process(TreeNode node) { + System.out.println(node.val); + } +``` + + + + + +## BFS + + + +```java +private static Set visited = new HashSet<>(); +public void bfs(TreeNode node) { + Deque> queue = new ArrayDeque<>(); + queue.push(Arrays.asList(node)); + visited.add(node); + List toVisit; + while ((toVisit = queue.pollFirst()).size() > 0) { + for (TreeNode treeNode : toVisit) { + visited.add(treeNode); + + process(treeNode); + + List relatedNodes = generateRelatedNodes(treeNode); + + queue.push(relatedNodes); + } + + } +} + +private List generateRelatedNodes(TreeNode node) { + List res = new ArrayList<>(); + if (node.left != null) { + res.add(node.left); + } + if (node.right != null) { + res.add(node.right); + } + return res; +} + +private void process(TreeNode node) { + System.out.println(node.val); +} +``` + +```java + public List> levelOrder(TreeNode root) { + List> ansList = new ArrayList<>(); + if (root == null) { + return ansList; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + List ans = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + ans.add(node.val); + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + } + ansList.add(ans); + } + return ansList; + } +``` + + + +### 二分查找模板 + +```java +public int search(int[] nums) { + int left = 0,right = nums.length - 1; + while (left <= right) { + mid = (left + right) / 2; + if (nums[mid] == target) { + // find the target break or return result; + return mid; + }else if (nums[mid] < target) { + left = mid + 1; + }else { + right = mid - 1; + } + } +} +``` + + + +## 总结 + +> 这周经过老师的线上答疑后,了解到自己的不足,我现在需要的仅仅是不停的汲取知识,将别人的完全理解后,写出来,这种反复。等自己有一定题目的积累后再考虑自己思路想法。 +> +> 这周遇到不会的题目先将其记住,反复敲代码,反复记忆。 +> +> 改善点: +> +> 1. 自己去看国外most votes 变得频繁,经常会觉得他们的思路很神奇 让自己觉得自愧不如且小上瘾。 +> 2. 也偶尔会去看一些 其他语言的代码是如何书写的 发现用java去按照他们的代码去写 有时真的非常丑陋 (ps 可能自己java的功底也不深) +> +> 二分查找中间无序的索引 +> +> ```java +> public int findIndex(int[] nums) { +> int left = 0, right = nums.length - 1; +> while (left <= right) { +> int mid = (left + right) / 2; +> if (nums[mid] > nums[mid + 1]) { +> return mid; +> } else { +> if (nums[mid] < nums[left]) right = mid - 1; +> else left = mid + 1; +> } +> } +> } +> ``` +> +> \ No newline at end of file diff --git "a/Week 03/id_521/102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.js" "b/Week 03/id_521/102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.js" new file mode 100644 index 000000000..496fedf5d --- /dev/null +++ "b/Week 03/id_521/102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.js" @@ -0,0 +1,23 @@ +// DFS: + + +var levelOrder = function(root) { + let visited = new Set(); + let ans = []; + + function DFS(node, visited, level) { + if (visited.has(node) || node === null) { + return; + } + if (ans[level] === undefined) { + ans[level] = []; + } + ans[level].push(node.val); + visited.add(node); + DFS(node.left, visited, level + 1); + + DFS(node.right, visited, level + 1); + } + DFS(root, visited, 0); + return ans; +}; diff --git "a/Week 03/id_521/33. \344\272\214\345\210\206\346\237\245\346\211\276.js" "b/Week 03/id_521/33. \344\272\214\345\210\206\346\237\245\346\211\276.js" new file mode 100644 index 000000000..8187716c0 --- /dev/null +++ "b/Week 03/id_521/33. \344\272\214\345\210\206\346\237\245\346\211\276.js" @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + * [4,5,6,7,0,1,2,3 4] + */ +var search = function(nums, target) { + let right = nums.length; + if(right === 0 ){ + return -1 + } + return recursion(0, right-1, nums, target) + + function recursion(left, right, nums, target) { + if(left > right ) return -1; + let mid = (left + right) / 2 | 0; + if (nums[mid] === target) { + return mid; + } + + if (nums[right] > nums[mid]) { //有序的 + if (nums[right] >= target && nums[mid] < target) { + return recursion(mid+1, right, nums, target); + } + return recursion(left, mid - 1, nums, target) + } else { + if (nums[left] <= target && nums[mid] > target) { + return recursion(left, mid - 1, nums, target); + } + return recursion(mid+1, right , nums, target) + } + + } +}; diff --git a/Week 03/id_521/Test.java b/Week 03/id_521/Test.java new file mode 100644 index 000000000..3c9cc8694 --- /dev/null +++ b/Week 03/id_521/Test.java @@ -0,0 +1,19 @@ +import java.util.LinkedList; +import java.util.Queue; + + +public class Test { + public static void main(String[] args) { + Queue queue = new LinkedList(); + Boolean b = queue.offer(1); + queue.offer(2); + queue.offer(3); + System.out.println(b); + System.out.println(queue); + Integer i = queue.poll(); + System.out.println(i); + // i = queue.poll(); + System.out.println(i); + System.out.println(queue.size()); + } +} \ No newline at end of file diff --git a/Week 03/id_521/note b/Week 03/id_521/note new file mode 100644 index 000000000..03e001fb3 --- /dev/null +++ b/Week 03/id_521/note @@ -0,0 +1,57 @@ + + +1. DFS搜索模板: + (主要用于图, 树建议使用前中后序遍历), 因为图是环状的,所以需要 + 使用visited标志位来判断是否已经访问过。而树是有终点的。 + 之前二叉树的前中后序遍历都是DFS的子集。只是二叉树的只有左右两个子节点。 + + + function wrap(root) { + let visited = new Set() + + function DFS(node, visited) { + if(visited.has(node)) { // 节点访问过就结束 + return + } + for(let node of node.children) { + DFS(node, visited) + } + } + } + + +2. BFS搜索模板; + 特点是需要根据节点(如果没有节点自己创造节点),来判断需不需要放入queue中处理,queue为空则说明没有更多节点,遍历结束 + + function BFS(root) { + let queue = [], ans = [] + queue.push(root) + while(queue.length) { + let node = queue.shift() + ans.push(node) + if(node.left !== null) { // 这里只是个判断放入queue的条件,可以自己创建节点包裹问题,创造条件 + queue.push(node.left) + } + if(node.right !== null) { + queue.push(node.right) + } + } + return ans + } + + 3. 二分查找: 针对有序,有界, 能通过索引访问。 数组, 链表等 + + function BinarySearch(list, target) { + let left = 0, right = list.length - 1 + + while(left <= right) { //是否等于,需要判断 + let mid = left + parseInt((right - left) / 2) + if(list[mid] === target) { + return mid + }else if(list[mid] < target) { + left = mid + 1 + }else { + right = mid - 1 + } + } + } diff --git a/Week 03/id_526/LeetCode_153_526 b/Week 03/id_526/LeetCode_153_526 new file mode 100644 index 000000000..72ce0e00b --- /dev/null +++ b/Week 03/id_526/LeetCode_153_526 @@ -0,0 +1,26 @@ +class Solution { + public int findMin(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + int left = 0, right = nums.length - 1; + if (nums[right] > nums[0]) { + return nums[0]; + } + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] > nums[mid + 1]) { + return nums[mid + 1]; + } + if (nums[mid - 1] > nums[mid]) { + return nums[mid]; + } + if (nums[mid] > nums[0]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_526/LeetCode_200_526 b/Week 03/id_526/LeetCode_200_526 new file mode 100644 index 000000000..d37f3590e --- /dev/null +++ b/Week 03/id_526/LeetCode_200_526 @@ -0,0 +1,26 @@ +class Solution { + public int numIslands(char[][] grid) { + int islandNum = 0; + for(int i = 0; i < grid.length; i++){ + for(int j = 0; j < grid[0].length; j++){ + if(grid[i][j] == '1'){ + infect(grid, i, j); + islandNum++; + } + } + } + return islandNum; + } + //感染函数 + public void infect(char[][] grid, int i, int j){ + if(i < 0 || i >= grid.length || + j < 0 || j >= grid[0].length || grid[i][j] != '1'){ + return; + } + grid[i][j] = '2'; + infect(grid, i + 1, j); + infect(grid, i - 1, j); + infect(grid, i, j + 1); + infect(grid, i, j - 1); + } +} \ No newline at end of file diff --git a/Week 03/id_526/LeetCode_33_526 b/Week 03/id_526/LeetCode_33_526 new file mode 100644 index 000000000..874d4f251 --- /dev/null +++ b/Week 03/id_526/LeetCode_33_526 @@ -0,0 +1,24 @@ +class Solution { + public int search(int[] nums, int target) { + int len = nums.length; + int left = 0, right = len-1; + while(left <= right){ + int mid = (left + right) / 2; + if(nums[mid] == target) + return mid; + else if(nums[mid] < nums[right]){ + if(nums[mid] < target && target <= nums[right]) + left = mid+1; + else + right = mid-1; + } + else{ + if(nums[left] <= target && target < nums[mid]) + right = mid-1; + else + left = mid+1; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_526/LeetCode_74_526 b/Week 03/id_526/LeetCode_74_526 new file mode 100644 index 000000000..b6c4842e9 --- /dev/null +++ b/Week 03/id_526/LeetCode_74_526 @@ -0,0 +1,30 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + //数组长度 + int m = matrix.length; + if (m == 0) { + return false; + } + //二位数组列的长度 + int n = matrix[0].length; + // 二分查找 + int left = 0, right = m * n - 1; + int pivotIdx; + int pivotElement; + + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if (target == pivotElement) { + return true; + }else { + if (target < pivotElement) { + right = pivotIdx - 1; + }else { + left = pivotIdx + 1; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Week 03/id_531/leetCode_127_531.go b/Week 03/id_531/leetCode_127_531.go new file mode 100644 index 000000000..b0c907b78 --- /dev/null +++ b/Week 03/id_531/leetCode_127_531.go @@ -0,0 +1,69 @@ +package id_531 + +//func ladderLength(beginWord string, endWord string, wordList []string) int { +// // 所有的单词都是一个长度 +// lth := len(beginWord) +// //通用状态树 +// grapMap := createStateGraph(wordList) +// +// return 0 +//} +// +//func createStateGraph(words []string) map[string][]string { +// result := make(map[string][]string) +// for _, word := range words { +// wordRune := []rune(word) +// for i := 0; i <= len(wordRune); i++ { +// +// } +// } +// return result +//} + +func ladderLength(beginWord string, endWord string, wordList []string) int { + dict := make(map[string]bool) // 把word存入字典 + for _, word := range wordList { + dict[word] = true // 可以利用字典快速添加、删除和查找单词 + } + if _, ok := dict[endWord]; !ok { + return 0 + } + + //题解,所有的单词都是一个长度 + lgt := len(beginWord) + var steps int + + var queue []string + queue = append(queue, beginWord) + + for len(queue) > 0 { + steps++ + size := len(queue) + for i := size; i > 0; i-- { // 当前层级节点 + // 原始单词,queue.pop() + word := queue[0] + queue = queue[1:] + chs := []rune(word) + for i := 0; i < lgt; i++ { // 对单词的每一位进行修改 + ch := chs[i] // 对当前单词的一位 + for c := 'a'; c <= 'z'; c++ { // 尝试从a-z + if c == ch { // 跳过本身比如hot修改为hot + continue + } + chs[i] = c + newWord := string(chs) + if newWord == endWord { // 找到结果 + return steps + 1 + } + if _, ok := dict[newWord]; !ok { // 不在dict中,跳过 + continue + } + delete(dict, newWord) // 从字典中删除该单词,因为已经访问过,若重复访问路径一定不是最短的 + queue = append(queue, newWord) // 将新的单词添加到队列 + } + chs[i] = ch // 单词的第i位复位,再进行下面的操作 + } + } + } + return 0 +} diff --git a/Week 03/id_531/leetCode_33_531.go b/Week 03/id_531/leetCode_33_531.go new file mode 100644 index 000000000..1cb265b9c --- /dev/null +++ b/Week 03/id_531/leetCode_33_531.go @@ -0,0 +1,60 @@ +package id_531 + +func search(nums []int, target int) int { + if len(nums) <= 0 { + return -1 + } + // 二分查找,单调性,边界,可索引 + bpIndex := findBreakPoint(nums) + var left, right int + if bpIndex == 0 { + left, right = 0, len(nums)-1 + } else { + if nums[0] == target { + return 0 + } + if nums[0] < target { + left, right = 0, bpIndex-1 + } else { + left, right = bpIndex, len(nums)-1 + } + } + + for left <= right { + mid := left + (right-left)>>1 + if nums[mid] == target { + return mid + } + if nums[mid] > target { + right = mid - 1 + } else { + left = mid + 1 + } + } + return -1 +} + +func findBreakPoint(nums []int) int { + bpIndex := 0 + count := len(nums) + for i := 1; i < count; i++ { + if nums[i] < nums[i-1] { + bpIndex = i + } + } + return bpIndex +} + +func BFindBreakPoint(nums []int) int { + left, right := 0, len(nums)-1 + lastElement := nums[right] + for left < right { + mid := left + (right-left)>>1 + if nums[mid] < lastElement { + right = mid + } else { + left = mid + 1 + } + } + return left +} diff --git a/Week 03/id_531/leetCode_33_531_test.go b/Week 03/id_531/leetCode_33_531_test.go new file mode 100644 index 000000000..a335b8c9e --- /dev/null +++ b/Week 03/id_531/leetCode_33_531_test.go @@ -0,0 +1,43 @@ +package id_531 + +import "testing" + +func TestBFindBreakPoint(t *testing.T) { + type args struct { + nums []int + } + tests := []struct { + name string + args args + want int + }{ + { + name: "test TestBFindBreakPoint", + args: args{ + nums: []int{4, 5, 6, 7, 0, 1, 2}, + }, + want: 4, + }, + { + name: "test TestBFindBreakPoint", + args: args{ + nums: []int{10, 11, 12, 14, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + want: 4, + }, + { + name: "test TestBFindBreakPoint", + args: args{ + nums: []int{10, 9}, + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := BFindBreakPoint(tt.args.nums); got != tt.want { + t.Errorf("BFindBreakPoint() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/Week 03/id_536/NOTE.md b/Week 03/id_536/NOTE.md index a6321d6e2..51e24736d 100644 --- a/Week 03/id_536/NOTE.md +++ b/Week 03/id_536/NOTE.md @@ -1,4 +1,36 @@ -# NOTE +第三周学习总结,将一些易忘的摘下。 +1.学习深度优先搜索、广度优先搜索算法。 + + 深度优先搜索:查找节点到节点,一条路径到终止节点之后再返回上一层继续查找其他分支,直至找到目标节点。回溯思想,比较多用递归实现。 + 广度优先搜索算法:地毯式逐层搜索,遍历得到的路径是起始点到终止节点的最短路径。借助队列实现。 +2.学习了贪心算法。 + + 贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止 +3.学习了二分查找算法。 + + (1)二分查找的核心三点 + 第一,右边界的确定 + 第二,循环的中止条件 + 第三,中位数在什么条件下等于结束或继续 + (2)二分查找模板: + int binarySearch(vector &num,int target) + int left = 0; + int right = ...;//右边界的确定 + while(...)//循环的中止条件 + { + int mid = (left + right)/2; + if(nums[mid] == target)//中位数在什么条件下等于结束或继续 + ... + else if(nums[mid] < target); + ... + else if(nums[mid] > target); + ... + } + return ...; + + +4、本周感想 + 参照代码模板多练习。 diff --git a/Week 03/id_536/leetcode_367_536.cpp b/Week 03/id_536/leetcode_367_536.cpp new file mode 100644 index 000000000..d256c31c2 --- /dev/null +++ b/Week 03/id_536/leetcode_367_536.cpp @@ -0,0 +1,41 @@ +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1ַͨ + ʱ临ӶȣO(logn),nΪnumֵ + ռ临ӶȣO(1) + *****/ + bool helper1(int num) { + long long left = 0; + long long right = num; + while(left <= right) + { + long long mid = left + (right - left)/2; + long long temp = mid*mid; + if(temp == num) + return true; + else if(temp < num) + left = mid + 1; + else + right = mid - 1; + } + return false; + } + bool isPerfectSquare(int num) { + return helper1(num); + } +}; + +int main() +{ + Solution s; + if(s.isPerfectSquare(13)) + cout << "True" << endl; + else + cout << "False" << endl; + return 0; +} diff --git a/Week 03/id_536/leetcode_69_536.cpp b/Week 03/id_536/leetcode_69_536.cpp new file mode 100644 index 000000000..a2a5d6378 --- /dev/null +++ b/Week 03/id_536/leetcode_69_536.cpp @@ -0,0 +1,90 @@ +#include + +using namespace std; + +class Solution { +public: + //ͨ + int binarySearch1(int x) + { + if(x == 0 || x ==1) + return x; + long left,right,mid,temp; + left = 0; + right = x; + while(left <= right) + { + mid = left + (right - left)/2; + temp = mid * mid; + if(temp == x) + return mid; + else if(temp < x) + left = mid + 1; + else + right = mid - 1; + } + return left-1;//ͨģ巵-1 + } + + //߽ + int binarySearch2(int x) { + if(x == 0 || x ==1) + return x; + long left,right,mid,temp; + left = 0; + right = x; + while(left < right) + { + mid = left + (right - left)/2; + temp = mid * mid; + if(temp == x) + right = mid; + else if(temp < x) + left = mid + 1; + else + right = mid; + } + if(left*left == x) + return left; + else + return left - 1;//ͨģ巵-1 + } + + //Ҳ߽ + int binarySearch3(int x) { + if(x == 0 || x ==1) + return x; + long left,right,mid,temp; + left = 0; + right = x; + while(left < right) + { + mid = left + (right - left)/2; + temp = mid * mid; + if(temp == x) + left = mid + 1; + else if(temp < x) + left = mid + 1; + else + right = mid; + } + return left-1; + } + + int mySqrt(int x) { + int res; + res = binarySearch1(x); + //res = binarySearch2(x); + //res = binarySearch3(x); + return res; + } +}; + +//ΪԴ +int main() +{ + Solution s; + cout << s.mySqrt(8) << endl; + cout << s.binarySearch4(8) << endl; + return 0; +} diff --git a/Week 03/id_536/leetcode_704_536.cpp b/Week 03/id_536/leetcode_704_536.cpp new file mode 100644 index 000000000..23a5b3af4 --- /dev/null +++ b/Week 03/id_536/leetcode_704_536.cpp @@ -0,0 +1,125 @@ +/*** + ֲģ壺 +int binarySearch(vector &num,int target) + int left = 0; + int right = ...; + while(...) + { + int mid = (left + right)/2; + if(nums[mid] == target) + ... + else if(nums[mid] < target); + ... + else if(nums[mid] > target); + ... + } + return ...; +***/ +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1ͨ + ʱ临Ӷ:O(n) + ռ临Ӷ:O(1) + *****/ + int binarySearch1(vector& nums, int target) + { + int left = 0; + int right = nums.size() - 1; + while( left <= right ) + { + int mid = left + (right - left)/2; + if(nums[mid] == target) + return mid; + else if(nums[mid] < target) + left = mid + 1; + else if(nums[mid] > target) + right = mid - 1; + } + return -1; + } + + /****** + ⷨ2߽ + ʱ临Ӷ:O(n) + ռ临Ӷ:O(1) + *****/ + int binarySearch2(vector& nums, int target) + { + int left = 0; + int right = nums.size(); + while(left < right) + { + int mid = left + (right - left)/2; + if(nums[mid] == target) + right = mid; + else if(nums[mid] < target) + left = mid + 1; + else if(nums[mid] > target) + right = mid; + } + if(left == nums.size()) + return -1; + if(nums[left] == target) + return left; + else + return -1; + } + + /****** + ⷨ3Ҳ߽ + ʱ临Ӷ:O(n) + ռ临Ӷ:O(1) + *****/ + int binarySearch3(vector& nums, int target) + { + int left = 0; + int right = nums.size(); + while(left < right) + { + int mid = left + (right - left)/2; + if(nums[mid] == target) + left = mid + 1; + else if(nums[mid] < target) + left = mid + 1; + else if(nums[mid] > target) + right = mid; + } + if(left == 0) + return -1; + if(nums[left-1] == target) + return left-1; + else + return -1; + } + + int search(vector& nums, int target) { + int res; + res = binarySearch1(nums,target);//ͨ + //res = binarySearch2(nums,target);//߽ + //res = binarySearch3(nums,target);//Ҳ߽ + return res; + } +}; + +int main() +{ + Solution s; + vector nums; + int target = 9; + int res; + nums.push_back(-1); + nums.push_back(0); + nums.push_back(3); + nums.push_back(5); + nums.push_back(9); + nums.push_back(12); + res = s.search(nums,target); + cout < "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 +// +// +// 示例 2: +// +// 输入: +//beginWord = "hit" +//endWord = "cog" +//wordList = ["hot","dot","dog","lot","log"] +// +//输出: 0 +// +//解释: endWord "cog" 不在字典中,所以无法进行转换。 +// Related Topics 广度优先搜索 + +package leetcode.editor.cn; + +import java.util.*; + +//Java:单词接龙 +public class P127WordLadder{ + public static void main(String[] args) { + Solution solution = new P127WordLadder().new Solution(); + // TO TEST + String[] wordList = new String[]{"hot","dot","dog","lot","log","cog"}; + int a = solution.ladderLength("hit","cog", Arrays.asList(wordList)); + System.out.println(a); + } + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + //hit cog +// wordList = ["hot","dot","dog","lot","log","cog"] + //hit -> %s i t -> 0 +// -> h %s t -> hot -> -> %s o t -> lot/hot/hot -> log1 / lot2 / cog +// -> h i %s -> 0 -> h %s t -> hot +// -> h o %s -> hot + + int length = beginWord.length(); + int L = beginWord.length(); + Map> mapping = new HashMap>(); + HashMap> allComboDict = new HashMap>(); + Map visited = new HashMap(); + wordList.forEach( + word -> { + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + ArrayList transformations = + allComboDict.getOrDefault(newWord, new ArrayList()); + transformations.add(word); + allComboDict.put(newWord, transformations); + } + }); + //利用queue来进行广度优先遍历 + Queue queue = new LinkedList(); + queue.offer(new LevelNode(beginWord,1)); + while(!queue.isEmpty()){ + LevelNode word = queue.poll(); + for (int i = 0; i < length; i++) { + String key = word.node.substring(0,i) + "*" + word.node.substring(i+1,length); + if (visited.getOrDefault(key,false)){ + continue; + } + List subWord = allComboDict.getOrDefault(key,new ArrayList<>()); + for (String str : subWord) { //二级子节点 + if (str.equals(endWord)){ + return word.level+1; + } + if (!visited.getOrDefault(str,false)){ + visited.put(str,true); + queue.offer(new LevelNode(str,word.level+1)); + } + } + visited.put(key,true); + } + } + return 0; + } + + class LevelNode{ + private String node; + private int level; + + public LevelNode(String node, int level) { + this.node = node; + this.level = level; + } + } +} +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 03/id_546/LeetCode_122_546.cs b/Week 03/id_546/LeetCode_122_546.cs new file mode 100644 index 000000000..2742ca17f --- /dev/null +++ b/Week 03/id_546/LeetCode_122_546.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Easy +{ + /// + /// 122. 买卖股票的最佳时机 II + /// + public class BestTimeToBuyAndSellStockii + { + public int MaxProfit(int[] prices) + { + int total = 0; + for (int i = 0; i < prices.Length - 1; i++) + { + if (prices[i + 1] > prices[i]) + { + total += prices[i + 1] - prices[i]; + } + } + + return total; + } + } +} diff --git a/Week 03/id_546/LeetCode_127_546.cs b/Week 03/id_546/LeetCode_127_546.cs new file mode 100644 index 000000000..2f14dd4e1 --- /dev/null +++ b/Week 03/id_546/LeetCode_127_546.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 127. 单词接龙 + /// + public class WordLadder + { + + + public int LadderLength(String beginWord, String endWord, IList wordList) + { + if (!wordList.Contains(endWord)) return 0; + + HashSet beginSet = new HashSet(), endSet = new HashSet(); + + int len = 1; + int strLen = beginWord.Length; + HashSet visited = new HashSet(); + + beginSet.Add(beginWord); + endSet.Add(endWord); + while (beginSet.Any() && endSet.Any()) + { + if (beginSet.Count > endSet.Count) + { + HashSet set = beginSet; + beginSet = endSet; + endSet = set; + } + + HashSet temp = new HashSet(); + foreach (string word in beginSet) + { + char[] chs = word.ToCharArray(); + + for (int i = 0; i < chs.Length; i++) + { + for (char c = 'a'; c <= 'z'; c++) + { + char old = chs[i]; + chs[i] = c; + String target =new string( chs); + + if (endSet.Contains(target)) + { + return len + 1; + } + + if (!visited.Contains(target) && wordList.Contains(target)) + { + temp.Add(target); + visited.Add(target); + } + chs[i] = old; + } + } + } + + beginSet = temp; + len++; + } + + return 0; + } + + + + public int LadderLength2(string beginWord, string endWord, IList wordList) + { + // IList dict = new List(wordList); + IList qs = new List(); + IList qe = new List(); + IList vis = new List(); + + qs.Add(beginWord); + + if (wordList.Contains(endWord)) + qe.Add(endWord); + + for (int len = 2; qs.Any(); len++) + { + List nq = new List(); + foreach (string w in qs) + { + for (int j = 0; j < w.Length; j++) + { + char[] ch = w.ToCharArray(); + for (char c = 'a'; c <= 'z'; c++) + { + if (c == w[j]) + continue; + + ch[j] = c; + string nb = new string(ch); + + if (qe.Contains(nb)) + return len; + if (wordList.Contains(nb)) + { + vis.Add(nb); + nq.Add(nb); + } + } + } + } + qs = (nq.Count() < qe.Count()) ? nq : qe; + qe = (qs == nq) ? qe : nq; + } + return 0; + } + + + } +} diff --git a/Week 03/id_546/LeetCode_200_546.cs b/Week 03/id_546/LeetCode_200_546.cs new file mode 100644 index 000000000..e0b69c293 --- /dev/null +++ b/Week 03/id_546/LeetCode_200_546.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 200. 岛屿数量 + /// + public class NumberOfIslands + { + private int n; + private int m; + + public int NumIslands(char[][] grid) + { + int count = 0; + n = grid.Length; + if (n == 0) return 0; + m = grid[0].Length; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < m; j++) + if (grid[i][j] == '1') + { + DFSMarking(grid, i, j); + ++count; + } + } + return count; + } + + private void DFSMarking(char[][] grid, int i, int j) + { + if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return; + grid[i][j] = '0'; + DFSMarking(grid, i + 1, j); + DFSMarking(grid, i - 1, j); + DFSMarking(grid, i, j + 1); + DFSMarking(grid, i, j - 1); + } + } +} diff --git a/Week 03/id_546/LeetCode_33_546.cs b/Week 03/id_546/LeetCode_33_546.cs new file mode 100644 index 000000000..98a1719e8 --- /dev/null +++ b/Week 03/id_546/LeetCode_33_546.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 33. 搜索旋转排序数组 + /// + public class SearchInRotatedSortedArray + { + // 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 0->4 + + public int Search(int[] nums, int target) + { + int left = 0; + int right = nums.Length-1; + + while (left <= right) + { + + int mid = (left + right) / 2; + + int _num = 0; + + //如果第一个元素同时大于中间元素和target,或者第一个元素同时小于中间元素和target,就获取中间值 + if (nums[mid] < nums[0] == (target < nums[0])) + { + _num = nums[mid]; + } + else + { + //如果第一个元素大于指定的元素,指定其位最小值,否则指定为最大值,以便进行二分查找 + _num = target < nums[0] ? int.MinValue : int.MaxValue; + } + //进行二分查找 + if (_num < target) + left = mid + 1; + else if (_num > target) + right = mid-1; + else + return mid; + } + return -1; + + } + } +} diff --git a/Week 03/id_546/LeetCode_455_546.cs b/Week 03/id_546/LeetCode_455_546.cs new file mode 100644 index 000000000..bccdad890 --- /dev/null +++ b/Week 03/id_546/LeetCode_455_546.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Easy +{ + /// + /// 455. 分发饼干 + /// + public class AssignCookies + { + public int FindContentChildren(int[] g, int[] s) + { + Array.Sort(g); + Array.Sort(s); + int i = 0; + for (int j = 0; i < g.Length && j < s.Length; j++) + { + if (g[i] <= s[j]) + { + i++; + } + } + return i; + } + } +} diff --git a/Week 03/id_546/LeetCode_45_546.cs b/Week 03/id_546/LeetCode_45_546.cs new file mode 100644 index 000000000..313ddd29d --- /dev/null +++ b/Week 03/id_546/LeetCode_45_546.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hard +{ + /// + /// 45. 跳跃游戏 II + /// + public class JumpGameii + { + public int Jump(int[] nums) + { + int jumps = 0, curEnd = 0, curFarthest = 0; + for (int i = 0; i < nums.Length - 1; i++) + { + curFarthest = Math.Max(curFarthest, i + nums[i]); + if (i == curEnd) + { + jumps++; + curEnd = curFarthest; + } + } + return jumps; + + } + } +} diff --git a/Week 03/id_546/LeetCode_529_546.cs b/Week 03/id_546/LeetCode_529_546.cs new file mode 100644 index 000000000..2a3877c25 --- /dev/null +++ b/Week 03/id_546/LeetCode_529_546.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 529. 扫雷游戏 + /// + public class Minesweeper + { + + + /// + /// DFS + /// + /// + /// + /// + public char[][] UpdateBoard(char[][] board, int[] click) + { + int m = board.Length, n = board[0].Length; + int row = click[0], col = click[1]; + + if (board[row][col] == 'M') + { // Mine + board[row][col] = 'X'; + } + else + { // Empty + // Get number of mines first. + int count = 0; + for (int i = -1; i < 2; i++) + { + for (int j = -1; j < 2; j++) + { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + + if (count > 0) + { // If it is not a 'B', stop further DFS. + board[row][col] = (char)(count + '0'); + } + else + { // Continue DFS to adjacent cells. + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) + { + for (int j = -1; j < 2; j++) + { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'E') UpdateBoard(board, new int[] { r, c }); + } + } + } + } + + return board; + } + + /// + /// BFS + /// + /// + /// + /// + public char[][] UpdateBoard2(char[][] board, int[] click) + { + int m = board.Length, n = board[0].Length; + Queue queue = new Queue(); + queue.Enqueue(click); + + while (queue.Any()) + { + int[] cell = queue.Dequeue(); + int row = cell[0], col = cell[1]; + + if (board[row][col] == 'M') + { // Mine + board[row][col] = 'X'; + } + else + { // Empty + // Get number of mines first. + int count = 0; + for (int i = -1; i < 2; i++) + { + for (int j = -1; j < 2; j++) + { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + + if (count > 0) + { // If it is not a 'B', stop further BFS. + board[row][col] = (char)(count + '0'); + } + else + { // Continue BFS to adjacent cells. + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) + { + for (int j = -1; j < 2; j++) + { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'E') + { + queue.Enqueue(new int[] { r, c }); + board[r][c] = 'B'; + } + } + } + } + } + } + + return board; + } + } +} diff --git a/Week 03/id_546/LeetCode_55_546.cs b/Week 03/id_546/LeetCode_55_546.cs new file mode 100644 index 000000000..f01dd1e23 --- /dev/null +++ b/Week 03/id_546/LeetCode_55_546.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 55. 跳跃游戏 + /// + public class JumpGame + { + public bool CanJump(int[] nums) + { + int curMax = nums[0]; + for (int i = 1; i < nums.Length; i++) + { + if (curMax < i) return false; + curMax = Math.Max(curMax, i + nums[i]); + } + return true; + } + } +} diff --git a/Week 03/id_546/LeetCode_860_546.cs b/Week 03/id_546/LeetCode_860_546.cs new file mode 100644 index 000000000..1feab6eaa --- /dev/null +++ b/Week 03/id_546/LeetCode_860_546.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Easy +{ + /// + /// 860. 柠檬水找零 + /// + public class LemonadeChange + { + public bool LemonadeChange1(int[] bills) + { + int five = 0, ten = 0; + foreach (int i in bills) + { + if (i == 5) five++; + else if (i == 10) { five--; ten++; } + else if (ten > 0) { ten--; five--; } + else five -= 3; + if (five < 0) return false; + } + return true; + } + } +} diff --git a/Week 03/id_546/LeetCode_874_546.cs b/Week 03/id_546/LeetCode_874_546.cs new file mode 100644 index 000000000..7b6022632 --- /dev/null +++ b/Week 03/id_546/LeetCode_874_546.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Easy +{ + /// + /// 874. 模拟行走机器人 + /// + public class WalkingRobotSimulation + { + public int RobotSim(int[] commands, int[][] obstacles) + { + List list = new List(); + foreach (int[] obs in obstacles) + { + list.Add(obs[0] + " " + obs[1]); + } + int[][] dirs = new int[][] { + new []{ 0, 1 }, + new []{ 1, 0 }, + new []{ 0, -1 }, + new []{ -1, 0 } + }; + + int d = 0, x = 0, y = 0, result = 0; + + for(int w=0;w 0 && !list.Contains((x + dirs[d][0]) + " " + (y + dirs[d][1]))) + { + x += dirs[d][0]; + y += dirs[d][1]; + } + } + result = Math.Max(result, x * x + y * y); + } + return result; + } + } +} diff --git a/Week 03/id_551/LeetCode_122_551.swift b/Week 03/id_551/LeetCode_122_551.swift new file mode 100644 index 000000000..a113a207a --- /dev/null +++ b/Week 03/id_551/LeetCode_122_551.swift @@ -0,0 +1,20 @@ +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + // 贪心算法 + // 贪心前提:每天只要涨就买卖,跌就不买卖,榨干每一次上涨,最终得到最优解 + // 子过程: if prices[i] > prices[i -1] { profit += xx } + + if prices.count < 2 { + // 少于 2 个价格,无意义 + return 0 + } + + var profit = 0 + for i in 1.. prices[i - 1] { + profit += prices[i] - prices[i - 1] + } + } + return profit + } +} diff --git a/Week 03/id_551/LeetCode_33_551.swift b/Week 03/id_551/LeetCode_33_551.swift new file mode 100644 index 000000000..064ad0953 --- /dev/null +++ b/Week 03/id_551/LeetCode_33_551.swift @@ -0,0 +1,36 @@ +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + // 旋转排序数组:有限制的有序数组, + // 要求:O(logn), 不能 for 一遍 + // 二分查找的前提:1、单调性;2、有界限(bounded);3、能够通过索引访问; + // 关键点:除了某个节点突然下降外是升序数组,1. 找单边有序(nums[mid] < nums[hi], 则右边有序) 2.规约 + var lo = 0 + var hi = nums.count - 1 + while (lo <= hi) { + var mid = lo + (hi - lo) / 2 + if target == nums[mid] { + return mid + } + if nums[mid] < nums[hi] { + // 右边有序 + if target <= nums[hi] && target > nums[mid] { + // target 在右边,开始向右规约 + lo = mid + 1 + } else { + // target 在左边,开始规约 + hi = mid - 1 + } + } else { + // 左边有序 + if target >= nums[lo] && target < nums[mid] { + // target 在左边,开始向左规约 + hi = mid - 1 + } else { + // target 在右边,开始向右规约 + lo = mid + 1 + } + } + } + return -1 + } +} diff --git a/Week 03/id_551/LeetCode_74_551.swift b/Week 03/id_551/LeetCode_74_551.swift new file mode 100644 index 000000000..65d652d5a --- /dev/null +++ b/Week 03/id_551/LeetCode_74_551.swift @@ -0,0 +1,30 @@ +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + // 当成虚拟有序数组处理,二分查找 + // low = 0, high = m * n - 1, mid = low + (high - low) / 2, row_mid = mid / n, clomun_mid = mid % n + + var m = matrix.count + if m == 0 { return false } + var n = matrix[0].count + + var lo = 0 + var hi = m * n - 1 + + while lo <= hi { + var mid = (lo + hi) / 2 + var val = matrix[mid / n][mid % n] + + if target == val { + return true + } + + if target > val && target <= matrix[hi / n][hi % n] { + lo = mid + 1 + } else { + hi = mid - 1 + } + } + + return false + } +} diff --git a/Week 03/id_551/LeetCode_860_551.swift b/Week 03/id_551/LeetCode_860_551.swift new file mode 100644 index 000000000..cafce9e88 --- /dev/null +++ b/Week 03/id_551/LeetCode_860_551.swift @@ -0,0 +1,39 @@ +class Solution { + func lemonadeChange(_ bills: [Int]) -> Bool { + // 贪心算法 + + // 贪心法前提:20 % 5,10 % 5 均为 0,所以子问题实现局部最优解,可以获得最终结果最优 + + /* 局部最优解: + 1、5 元不需要找零; + 2、10 元, 如果有 5 元则找零 5 元; + 3、20 元,如果有 10 元和 5元,则找零 10 元和 5 元,或者 3 个 5元; + */ + var ten: Int = 0 + var five: Int = 0 + + for bill in bills { + if bill == 5 { + five += 1 + } else if bill == 10 { + if five > 0 { + ten += 1 + five -= 1 + } else { + return false + } + } else if bill == 20 { + if ten > 0 && five > 0 { + ten -= 1 + five -= 1 + } else if five > 2 { + five -= 3 + } else { + return false + } + } + } + + return true + } +} diff --git a/Week 03/id_556/LeetCode_33_556.java b/Week 03/id_556/LeetCode_33_556.java new file mode 100644 index 000000000..53a03086f --- /dev/null +++ b/Week 03/id_556/LeetCode_33_556.java @@ -0,0 +1,66 @@ +class Solution { + public int search(int[] nums, int target) { + // check boundary here!!! + if (nums.length == 0) { + return -1; + } + if (nums.length == 1) { + return nums[0] == target ? 0 : -1; + } + // find rotateindex first, and then binary search in ordered part + int index = findRotateIndex(nums); + int l, r; + if (index == 0) { + l = 0; + r = nums.length - 1; + } else { + if (target >= nums[0]) { + // in the left(unrotated) part + l = 0; + r = index; + } else { + // in the right(rotated) part + l = index; + r = nums.length - 1; + } + } + return binarySearch(nums, l, r, target); + } + + public int binarySearch(int[] nums, int l, int r, int target) { + while (l <= r) { + int m = l + (r - l) / 2; + if (nums[m] == target) { + return m; + } else { + if (nums[m] < target) { + l = m + 1; + } else { + r = m - 1; + } + } + } + return -1; + } + + public int findRotateIndex(int[] a) { + if (a[0] < a[a.length - 1]) { + return 0; + } + int l = 0, r = a.length - 1; + int m = l + (r - l) / 2; + while (l <= r) { + m = l + (r - l) / 2; + if (a[m] > a[m + 1]) { + return m + 1; + } else { + if (a[m] < a[l]) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return m; + } +} \ No newline at end of file diff --git a/Week 03/id_556/LeetCode_874_556.java b/Week 03/id_556/LeetCode_874_556.java new file mode 100644 index 000000000..7601702d5 --- /dev/null +++ b/Week 03/id_556/LeetCode_874_556.java @@ -0,0 +1,39 @@ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + // clockwise: up, right, down, left + int[][] offset = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + int x = 0, y = 0; + int max = 0; + // index of the offset towards dir + int dir = 0; + Set obs = new HashSet<>(); + for (int i = 0; i < obstacles.length; ++i) { + obs.add(obstacles[i][0] + "," + obstacles[i][1]); + } + // let's move + for (int i = 0; i < commands.length; ++i) { + if (commands[i] == -1) { + // turn right + dir = (dir + 1) % 4; + } else if (commands[i] == -2) { + // turn left + dir = (dir + 3) % 4; + } else if (commands[i] > 0) { + for (int j = 0; j < commands[i]; ++j) { + int nextX = x + offset[dir][0]; + int nextY = y + offset[dir][1]; + if (obs.contains(nextX + "," + nextY)) { + // stop and stay + break; + } else { + x = nextX; + y = nextY; + max = Math.max(max, x * x + y * y); + } + } + } + } + return max; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_556/NOTE.md b/Week 03/id_556/NOTE.md index a6321d6e2..918fd1ac4 100644 --- a/Week 03/id_556/NOTE.md +++ b/Week 03/id_556/NOTE.md @@ -1,4 +1,167 @@ -# NOTE +# 二分查找寻找半有序数组无序点 - +约定旋转点为被旋转部分第一个元素的下标,如[4, 5, 6, 7, 8, 0, 1, 2]中0的下标 +若数组无旋转应当为单调递增,找旋转点即为寻找第一次减小(也是唯一一次)的地方,直观的想法为依次比较a[i]与a[i+1],复杂度为O(n)。而使用二分法,一步步缩小旋转点存在的区间范围来找到旋转点,复杂度为O(logn)。 + +- 初始化:l=0, r=a.length-1, m=l+(r-l)/2 +- 思路1: 比较a[m]与前一个数,如果a[m]a[r],则说明旋转点在m到r之间,令l=m+1;否则,说明旋转点在l到m之间,令r=m-1; + +代码: +```java +public static int findIndex(int[] a) { + if (a[0] < a[a.length - 1]) { + return 0; + } + int l = 0, r = a.length - 1; + int m = l + (r - l) / 2; + while (l <= r) { + m = l + (r - l) / 2; + if (a[m] < a[m - 1]) { + return m; + } else { + if (a[m] > a[r]) { + l = m + 1; + } else { + r = m - 1; + } + } + } + return m; +} +``` +以上代码其实是存在bug的,比如数组长度为2且降序时(如[3,1]),m=0,m-1=-1会造成数组下标越界。 + +- 思路2: 比较a[m]与后一个数,如果a[m]>a[m+1],则找到,返回m+1;否则,比较a[m]与左端,如果a[m] a[m + 1]) { + return m+1; + } else { + if (a[m] < a[l]) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return m; + } +``` + +# Week3-9-深度广度优先遍历 +搜索很多时候就需要遍历,算法可以根据数据结构特征进行提升;DFS和BFS复杂度都是O(n),区别在于顺序不同。 + +## DFS +### 递归写法: +```python +def dfs(node): + if node in visited: + return + visited.add(node) + # process current node + ... + dfs(node.left) + dfs(node.right) +``` +```python +def dfs(node, visited): + visited.add(node) + # process current node + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) +``` +```python +def dfs(node, visited): + if node in visited: # terminator + return + visited.add(node) + # process current node + ... + for next_node in node.children(): + if not next_node in visited: # check again + dfs(next_node, visited) +``` +非递归写法:(其实是用栈手动模拟递归过程) +```python +def dfs(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + while stack: + node = stack.pop() + visited.add(node) + process(node) + nodes = get_related_nodes(node) + stack.push(nodes) +``` +## BFS +```python +def bfs(node): + queue = [] + queue.append([start]) + visited.add(start) + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = get_related_nodes(node) + queue.push(nodes) +``` + +## PFS(启发式搜索) + +# Week3-10-贪心算法 + + 贪心算法:在每一步选择中都选取当前状态下最优的选,希望结果得到全局最优,因此主要解决最优化问题(如最小生成树,霍夫曼编码等) + +> Greedy与DP的不同:DP可以保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能 +(带最优判断的回溯) + +> 贪心法一般不能得到实际问题的最优解,但高效且结果接近最优解,因此可以用作辅助算法。 + +> 一旦一个问题可以用贪心法解决,那么贪心法一般是解决这个问题的最好和自然方法。但这种情况很少。 + + +适合贪心法的情况: + +- 问题能分解成子问题,而子问题的最优解能递推到最终问题的最优解(最优子结构) + +> 贪心法难的在于证明和转换角度(有时需要从前往后/从后往前/局部切入进行贪心) + +# Week3-11-二分查找 + +适合二分查找的条件: +1. 目标函数单调性(有序) +2. 存在上下界 +3. 能够通过索引访问 + +代码模板 +```python +left, right=0, len(array)-1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target + return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +四步切题 +1. 与面试官确认题目细节,边界条件,输入输出,以及corner case; +2. 思考自己能想到的所有解法,分析时间空间复杂度; +3. 与面试官探讨自己想到的最优解法,得到确认或提示; +4. 开始写代码,给出test case(正常,边界,错误,变态)。 diff --git a/Week 03/id_566/leetcode_33_566.php b/Week 03/id_566/leetcode_33_566.php new file mode 100644 index 000000000..dbace9e69 --- /dev/null +++ b/Week 03/id_566/leetcode_33_566.php @@ -0,0 +1,38 @@ += $nums[$start] && $target < $nums[$mid]){ + $end = $mid - 1; + }else{ + $start = $mid + 1; + } + }else{ + if($target > $nums[$mid] && $target <= $nums[$end]){ + $start = $mid + 1; + }else{ + $end = $mid - 1; + } + } + } + return -1; + } +} +?> \ No newline at end of file diff --git a/Week 03/id_566/leetcode_455_566.php b/Week 03/id_566/leetcode_455_566.php new file mode 100644 index 000000000..5566fd89f --- /dev/null +++ b/Week 03/id_566/leetcode_455_566.php @@ -0,0 +1,35 @@ += gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + +class Solution { + + /** + * @param Integer[] $g + * @param Integer[] $s + * @return Integer + */ + function findContentChildren($childrens, $cookies) { + $sum = 0; + //实际可以不用php的sort,自己写一个sort的函数 + sort($childrens); + sort($cookies); + foreach($cookies as $cookies_num => $cookie) + { + foreach($childrens as $children_num => $children) + { + if($cookie >= $children) + { + $sum++; + unset($childrens[$children_num]); + break; + } + } + } + return $sum; + } +} +?> \ No newline at end of file diff --git a/Week 03/id_571/NOTE.md b/Week 03/id_571/NOTE.md index a6321d6e2..dafe21454 100644 --- a/Week 03/id_571/NOTE.md +++ b/Week 03/id_571/NOTE.md @@ -1,4 +1,77 @@ # NOTE - +## 搜索 +- 所有节点都访问一次 +- 所有节点仅访问一次 + +### DFS + +```js +// recursion +function dfs(node, visited) { + if (node in visited) { + return; + } + visited.push(node); + for (let next_node of node.children()) { + if (!(node in visited)) { + dfs(next_node, visited); + } + } +} +// iteration +function dfs(node) { + let stack = []; + if (!node) return stack; + stack.push(node); + let visited = []; + while (stack.length !== 0) { + let n = stack.pop(); + visited.push(n); + for (let next_node of node.children()) { + if (!(next_node in visited)) { + stack.push(next_node); + } + } + } +} +``` + +### BFS + +```js +function bfs(node) { + let queue = []; + queue.push(node); + let visited = []; + while (queue.length !== 0) { + let n = queue.shift(); + visited.push(n); + for (let next_node of node.children()) { + queue.push(next_node); + } + } +} +``` + +## 二分搜索 + +1. 目标函数单调 +2. 存在上下界 +3. 可以通过索引访问 + +```js +let left = 0, + right = array.length - 1; +while (left <= right) { + let mid = (left + right) >>> 1; + if (array[mid] === target) { + return mid; + } else if (array[mid] <= target) { + left = mid + 1; + } else { + right = mid - 1; + } +} +``` diff --git a/Week 03/id_571/leetcode_122.571.js b/Week 03/id_571/leetcode_122.571.js new file mode 100644 index 000000000..b546e94b3 --- /dev/null +++ b/Week 03/id_571/leetcode_122.571.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + let res = 0; + for (let i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + res += prices[i] - prices[i - 1]; + } + } + return res; +}; diff --git a/Week 03/id_571/leetcode_33_571.js b/Week 03/id_571/leetcode_33_571.js new file mode 100644 index 000000000..33231872f --- /dev/null +++ b/Week 03/id_571/leetcode_33_571.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function(nums, target) { + let left = 0, + right = nums.length - 1; + while (left < right) { + let mid = (right + left) >>> 1; + // [0, mid] go up + if (nums[mid] >= nums[0] && (target > nums[mid] || target < nums[0])) { + left = mid + 1; + } else if (target > nums[mid] && target < nums[0]) { + left = mid + 1; + } else { + right = mid; + } + } + return left === right && nums[left] === target ? left : -1; +}; + +search([4, 5, 6, 7, 0, 1, 2], 7); \ No newline at end of file diff --git a/Week 03/id_571/leetcode_367_571.js b/Week 03/id_571/leetcode_367_571.js new file mode 100644 index 000000000..e8d912dc4 --- /dev/null +++ b/Week 03/id_571/leetcode_367_571.js @@ -0,0 +1,20 @@ +/** + * @param {number} num + * @return {boolean} + */ +var isPerfectSquare = function(num) { + if (num === 0 || num === 1) return true; + let left = 1, + right = num; + while (left <= right) { + let mid = left + ((right - left) >>> 1); + if (mid * mid === num) { + return true; + } else if (mid * mid > num) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return false; +}; diff --git a/Week 03/id_571/leetcode_455_571.js b/Week 03/id_571/leetcode_455_571.js new file mode 100644 index 000000000..beb1e444c --- /dev/null +++ b/Week 03/id_571/leetcode_455_571.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function(g, s) { + g = g.sort((a, b) => a - b); + s = s.sort((a, b) => a - b); + let i = 0; + for (let j = 0; i < g.length && j < s.length; j++) { + if (s[j] >= g[i]) { + i++; + } + } + return i; +}; + +findContentChildren([10, 9, 8, 7], [5, 6, 7, 8]); diff --git a/Week 03/id_571/leetcode_55_571.js b/Week 03/id_571/leetcode_55_571.js new file mode 100644 index 000000000..d86815875 --- /dev/null +++ b/Week 03/id_571/leetcode_55_571.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function(nums) { + if (!nums) return false; + let endReachable = nums.length - 1; + for (let i = nums.length - 1; i >= 0; i--) { + if (nums[i] + i >= endReachable) { + endReachable = i; + } + } + return endReachable === 0; +}; diff --git a/Week 03/id_571/leetcode_69_571.js b/Week 03/id_571/leetcode_69_571.js new file mode 100644 index 000000000..f35772afe --- /dev/null +++ b/Week 03/id_571/leetcode_69_571.js @@ -0,0 +1,18 @@ +/** + * @param {number} x + * @return {number} + */ +var mySqrt = function(x) { + if (x === 0 || x === 1) return x; + let left = 1, + right = x; + while (left <= right) { + let mid = left + ((right - left) >>> 1); + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return right; +}; diff --git a/Week 03/id_586/102-binary-tree-level-order-traversal.c b/Week 03/id_586/102-binary-tree-level-order-traversal.c new file mode 100755 index 000000000..539f5394b --- /dev/null +++ b/Week 03/id_586/102-binary-tree-level-order-traversal.c @@ -0,0 +1,86 @@ +/* +# 102 二叉树的层次遍历 + +给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + +例如: 给定二叉树: [3,9,20,null,null,15,7], + 3 + / \ + 9 20 + / \ + 15 7 + +返回其层次遍历结果: + + [ + [3], + [9,20], + [15,7] + ] + +*/ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution1 { +public: + vector> levelOrder(TreeNode* root) { + vector> ret; + + if (!root) return ret; + + queue q; + TreeNode *curr; + + q.push(root); + + while(q.empty() == 0) { + vector level; + int len = q.size(); + for (int i = 0; i < len; i++) { + curr = q.front(); + level.push_back(curr->val); + q.pop(); + if (curr->left) q.push(curr->left); + if (curr->right) q.push(curr->right); + } + ret.push_back(level); + } + + return ret; + } +}; + +/* + * 方法2: 使用递归的方法 + * */ +class Solution2 { +public: + vector> ret; + + void buildVector(TreeNode *root, int depth) + { + if(root == NULL) return; + /* start the current level */ + if(ret.size() == depth) + ret.push_back(vector()); + + /* fulfil the current level */ + ret[depth].push_back(root->val); + + /* process child nodes for the next level */ + buildVector(root->left, depth + 1); + buildVector(root->right, depth + 1); + } + + vector > levelOrder(TreeNode *root) { + buildVector(root, 0); + return ret; + } +}; diff --git a/Week 03/id_586/122-best-time-to-buy-and-sell-stock-ii.cc b/Week 03/id_586/122-best-time-to-buy-and-sell-stock-ii.cc new file mode 100755 index 000000000..fbccc4a3f --- /dev/null +++ b/Week 03/id_586/122-best-time-to-buy-and-sell-stock-ii.cc @@ -0,0 +1,11 @@ +class Solution { +public: + int maxProfit(vector& prices) { + int maxprofit = 0; + for (int i = 1; i < prices.size(); i++) { + if (prices[i] > prices[i - 1]) + maxprofit += prices[i] - prices[i - 1]; + } + return maxprofit; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/126-word-ladder-ii.cc b/Week 03/id_586/126-word-ladder-ii.cc new file mode 100755 index 000000000..df097cb43 --- /dev/null +++ b/Week 03/id_586/126-word-ladder-ii.cc @@ -0,0 +1,66 @@ +class Solution { +public: + vector> findLadders(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail; + if (dict.find(endWord) == dict.end()) { + return {}; + } + head.insert(beginWord); + tail.insert(endWord); + unordered_map> children; + vector> ladders; + vector ladder; + ladder.push_back(beginWord); + if (searchLadders(head, tail, dict, children, false)) { + genLadders(beginWord, endWord, children, ladder, ladders); + } + return ladders; + } +private: + bool searchLadders(unordered_set& head, unordered_set& tail, unordered_set& dict, unordered_map>& children, bool flip) { + if (head.empty()) { + return false; + } + if (head.size() > tail.size()) { + return searchLadders(tail, head, dict, children, !flip); + } + for (string word : head) { + dict.erase(word); + } + for (string word : tail) { + dict.erase(word); + } + unordered_set intermediate; + bool done = false; + for (string word : head) { + string temp = word; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (tail.find(word) != tail.end()) { + done = true; + flip ? children[word].push_back(temp) : children[temp].push_back(word); + } else if (!done && dict.find(word) != dict.end()) { + intermediate.insert(word); + flip ? children[word].push_back(temp) : children[temp].push_back(word); + } + } + word[i] = t; + } + } + return done || searchLadders(tail, intermediate, dict, children, !flip); + } + + void genLadders(string beginWord, string endWord, unordered_map>& children, vector& ladder, vector>& ladders) { + if (beginWord == endWord) { + ladders.push_back(ladder); + } else { + for (string child : children[beginWord]) { + ladder.push_back(child); + genLadders(child, endWord, children, ladder, ladders); + ladder.pop_back(); + } + } + } +}; \ No newline at end of file diff --git a/Week 03/id_586/127-word-ladder.cc b/Week 03/id_586/127-word-ladder.cc new file mode 100755 index 000000000..2c0b79d1b --- /dev/null +++ b/Week 03/id_586/127-word-ladder.cc @@ -0,0 +1,42 @@ +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail; + if (dict.find(endWord) == dict.end()) { + return 0; + } + head.insert(beginWord); + tail.insert(endWord); + int ladder = 2; + while (!head.empty() && !tail.empty()) { + if (head.size() < tail.size()) { + phead = &head; + ptail = &tail; + } else { + phead = &tail; + ptail = &head; + } + unordered_set temp; + for (auto it = phead -> begin(); it != phead -> end(); it++) { + string word = *it; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (ptail -> find(word) != ptail -> end()) { + return ladder; + } + if (dict.find(word) != dict.end()) { + temp.insert(word); + dict.erase(word); + } + } + word[i] = t; + } + } + ladder++; + phead -> swap(temp); + } + return 0; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/200-number-of-islands.cc b/Week 03/id_586/200-number-of-islands.cc new file mode 100755 index 000000000..00d3396fa --- /dev/null +++ b/Week 03/id_586/200-number-of-islands.cc @@ -0,0 +1,39 @@ +class Solution { +public: + int numIslands(vector>& grid) { + int nr = grid.size(); + if (!nr) return 0; + int nc = grid[0].size(); + + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + grid[r][c] = '0'; // mark as visited + queue> neiors; + neiors.push({r, c}); + while (!neiors.empty()) { + auto rc = neiors.front(); + neiors.pop(); + int row = rc.first, col = rc.second; + if (row - 1 >= 0 && grid[row-1][col] == '1') { + neiors.push({row-1, col}); grid[row-1][col] = '0'; + } + if (row + 1 < nr && grid[row+1][col] == '1') { + neiors.push({row+1, col}); grid[row+1][col] = '0'; + } + if (col - 1 >= 0 && grid[row][col-1] == '1') { + neiors.push({row, col-1}); grid[row][col-1] = '0'; + } + if (col + 1 < nc && grid[row][col+1] == '1') { + neiors.push({row, col+1}); grid[row][col+1] = '0'; + } + } + } + } + } + + return num_islands; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/22-generate-parentheses.cc b/Week 03/id_586/22-generate-parentheses.cc new file mode 100755 index 000000000..2d93ec98b --- /dev/null +++ b/Week 03/id_586/22-generate-parentheses.cc @@ -0,0 +1,41 @@ +class Solution { +public: + + #if 1 + vector generateParenthesis(int n) { + vector ret; + generate(ret, "", 0, 0, n); + return ret; + } + + void generate(vector &ans, string cur, int open, int close, int n) { + if (cur.length() == n * 2) { + ans.push_back(cur); + return; + } + + if (open < n) + generate(ans, cur + "(", open + 1, close, n); + if (close < open) + generate(ans, cur + ")", open, close + 1, n); + } + #else + vector generateParenthesis(int n) { + vector ret; + generate(ret, "", n, n); + return ret; + } + + void generate(vector &ans, string cur, int left, int right) { + if (left == 0 && right == 0) { + ans.push_back(cur); + return; + } + + if (left > 0) + generate(ans, cur + "(", left - 1, right); + if (right > left) + generate(ans, cur + ")", left, right - 1); + } + #endif +}; \ No newline at end of file diff --git a/Week 03/id_586/322-coin-change.cc b/Week 03/id_586/322-coin-change.cc new file mode 100755 index 000000000..8bcc1896c --- /dev/null +++ b/Week 03/id_586/322-coin-change.cc @@ -0,0 +1,23 @@ +class Solution { +public: + int coinChange(vector& coins, int amount) { + // int Max = amount + 1; + // vector dp(amount + 1, Max); + // dp[0] = 0; + // for (int i = 1; i <= amount; i++) { + // for (int j = 0; j < coins.size(); j++) { + // if (coins[j] <= i) { + // dp[i] = min(dp[i], dp[i - coins[j]] + 1); + // } + // } + // } + // return dp[amount] > amount ? -1 : dp[amount]; + + vector need(amount+1, amount+1); + need[0] = 0; + for (int c : coins) + for (int a=c; a<=amount; a++) + need[a] = min(need[a], need[a-c] + 1); + return need.back() > amount ? -1 : need.back(); + } +}; \ No newline at end of file diff --git a/Week 03/id_586/33-search-in-rotated-sorted-array.cc b/Week 03/id_586/33-search-in-rotated-sorted-array.cc new file mode 100755 index 000000000..87b538ce3 --- /dev/null +++ b/Week 03/id_586/33-search-in-rotated-sorted-array.cc @@ -0,0 +1,43 @@ +class Solution { +public: + int search(vector& nums, int target) { +// int lo = 0, hi = nums.size(); +// while (lo < hi) { +// int mid = (lo + hi) / 2; + +// double num = (nums[mid] < nums[0]) == (target < nums[0]) +// ? nums[mid] +// : target < nums[0] ? -INFINITY : INFINITY; + +// if (num < target) +// lo = mid + 1; +// else if (num > target) +// hi = mid; +// else +// return mid; +// } +// return -1; + + int lo=0,hi=nums.size()-1; + // find the index of the smallest value using binary search. + // Loop will terminate since mid < hi, and lo or hi will shrink by at least 1. + // Proof by contradiction that mid < hi: if mid==hi, then lo==hi and loop would have been terminated. + while(lonums[hi]) lo=mid+1; + else hi=mid; + } + // lo==hi is the index of the smallest value and also the number of places rotated. + int rot=lo; + lo=0;hi=nums.size()-1; + // The usual binary search and accounting for rotation. + while(lo<=hi){ + int mid=(lo+hi)/2; + int realmid=(mid+rot)%nums.size(); + if(nums[realmid]==target)return realmid; + if(nums[realmid]& bank) { + //1: 判读极端情况 + if(start.empty() || end.empty() || bank.empty()) return -1; + + if(find(bank.begin(), bank.end(), end) == bank.end()) + return -1; //目标基因不在基因库中 + + //2: bfs的初始化工作: 初始化步长,初始化queue,将start入队列,用vecotr来标记已经访问过的点。 + vector visit(bank.size(),0); + int step=0; + queue q; + q.push(start); + + //3: 进行bfs : 先将步长+1,然后确定每次bfs的长度size,寻找目标基因,然后出栈入栈等操作 + while (!q.empty()) { + step++; + int n = q.size();//确定每次bfs的宽度 + for (int i = 0; i < n; ++i) { + string &temp = q.front(); q.pop();//获得队头元素 + for (int j = 0; j < bank.size(); ++j) {//遍历整个基因库,访问未标记的基因;找到某个字符变异的基因添加标记,并进入队列即可 + if (visit[j] == 0) { + int diff = 0; + for (int k = 0; k < temp.size(); ++k) + if (temp[k] != bank[j][k]) diff++; + + if (diff == 1) { //找到某个字符编译的基因 + if (bank[j] == end) return step;//若该下标j代表的基因为目标基因,则直接返回步长 + visit[j] = 1;//标记下标为j的基因已访问 + q.push(bank[j]); + } + } + } + } + } + return -1; + } +}; + +/* + * - 由于单向bfs类似金字塔,越到底层,塔基越大(而众多塔基中只有一点end满足条件),而且其回溯路径也少。 + * 所以我们采用双向bfs,即既从begin->end遍历,又从end->begin遍历,当然每次我们都选用较短队列进行遍历,这样可减少用时。 + * - 循环结束的条件是两个bfs碰头。每个单词遍历的方向,1由前向后遍历,2由后向前遍历,3两个bfs碰头。 + * 公式:0|1=1、0|2=2、1|2=3和i&i=i、i&0=0 + * */ +class Solution2 { +public: + //解法2:双向bfs + int minMutation(string start, string end, vector& bank) { + //1:建立hashmap表,顺便去掉重复元素 + unordered_map mp; + for (const auto& b : bank) mp[b] = 0; + + //2:排除极端情况,end不在基因库中 + if (mp.count(end) == 0) return -1; + + //3:bfs的初始化工作 + queue q1({start}), q2({end});//前向队列,后向队列 + int step=0; + const char table[4]={'A','C','G','T'};//基因的字符 + //或1表示前向队列由前往后遍历,或2表示后向队列由后向前遍历,每次我们选用较小的队列进行遍历 + for (mp[start] |= 1,mp[end] |= 2; q1.size() && q2.size(); ++step) {//每遍历完一次,步长+1 + bool first = q1.size() < q2.size(); + queue &q = first ? q1 : q2;//选择较小的队列进行遍历节约时间 + int flag = first ? 1 : 2;//此次遍历的方式 + + for (int n = q.size(); n--; q.pop()) { + string& temp = q.front(); + if (mp[temp] == 3) return step; //两个队列碰头,返回步长 + for (int i = 0; i < temp.size(); ++i) { + for (int j = 0; j < 4; ++j) { + string s = temp; + if (s[i] == table[j]) continue; //重复字符,跳出循环,寻找下一个字符 + s[i] = table[j]; + //该单词不在map中或该单词已经被遍历过了,跳出循环,寻找下一个单词 + if (mp.count(s) == 0 || mp[s] & flag) continue; + mp[s] |= flag;//标记该单词已经被遍历过了 + q.push(s); + } + } + } + } + return -1; + } +}; diff --git a/Week 03/id_586/455-assign-cookies.cc b/Week 03/id_586/455-assign-cookies.cc new file mode 100755 index 000000000..10bb155b0 --- /dev/null +++ b/Week 03/id_586/455-assign-cookies.cc @@ -0,0 +1,25 @@ +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + int g_length = g.size(); + int s_length = s.size(); + + int i = 0; + int j = 0; + int res = 0; + + while (i < g_length && j < s_length) { + if (g[i] <= s[j]) { + //可以满足胃口,把小饼干喂给小朋友 + res += 1; + i += 1; + j += 1; + } else + //不满足胃口,查看下一块小饼干 + j += 1; + } + return res; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/515-find-largest-value-in-each-tree-row.cc b/Week 03/id_586/515-find-largest-value-in-each-tree-row.cc new file mode 100755 index 000000000..563e4342d --- /dev/null +++ b/Week 03/id_586/515-find-largest-value-in-each-tree-row.cc @@ -0,0 +1,33 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + /* DFS solution */ + vector solution; + void helper(TreeNode* node, int cl) { + if (node == NULL) return; + + if (solution.size() < cl + 1) + solution.push_back(node->val); + else { + if (solution[cl] < node->val) + solution[cl] = node->val; + } + helper(node->left, cl+1); + helper(node->right, cl+1); + } + + vector largestValues(TreeNode* root) { + if(root == NULL) return solution; + + helper(root, 0); + return solution; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/529-minesweeper.cc b/Week 03/id_586/529-minesweeper.cc new file mode 100755 index 000000000..6fe531a03 --- /dev/null +++ b/Week 03/id_586/529-minesweeper.cc @@ -0,0 +1,45 @@ +class Solution { +public: + vector> updateBoard(vector>& board, vector& click) { + if(board[click[0]][click[1]] == 'M'){ + board[click[0]][click[1]] = 'X'; + return board; + } + reveal(board,click[0],click[1]); + return board; + } + + bool inboard(const vector>& board, int x, int y){ + return ( x>=0 && x=0 && y>& board, int x, int y){ + if(!inboard(board,x,y)) return; + if(board[x][y] == 'E'){ + //search 8 adjacent squares + int count = 0; + if(inboard(board,x-1,y-1) && board[x-1][y-1] == 'M') count++; + if(inboard(board,x-1,y ) && board[x-1][y ] == 'M') count++; + if(inboard(board,x-1,y+1) && board[x-1][y+1] == 'M') count++; + if(inboard(board,x ,y-1) && board[x ][y-1] == 'M') count++; + if(inboard(board,x ,y+1) && board[x ][y+1] == 'M') count++; + if(inboard(board,x+1,y-1) && board[x+1][y-1] == 'M') count++; + if(inboard(board,x+1,y ) && board[x+1][y ] == 'M') count++; + if(inboard(board,x+1,y+1) && board[x+1][y+1] == 'M') count++; + + if(count>0) + board[x][y] = '0'+count; + else{ + board[x][y] = 'B'; + reveal(board,x-1,y-1); + reveal(board,x-1,y ); + reveal(board,x-1,y+1); + reveal(board,x ,y-1); + reveal(board,x ,y+1); + reveal(board,x+1,y-1); + reveal(board,x+1,y ); + reveal(board,x+1,y+1); + } + } + } +}; \ No newline at end of file diff --git a/Week 03/id_586/55-jump-game.cc b/Week 03/id_586/55-jump-game.cc new file mode 100755 index 000000000..de3ce03d6 --- /dev/null +++ b/Week 03/id_586/55-jump-game.cc @@ -0,0 +1,17 @@ +class Solution { +public: + bool canJump(vector& nums) { + // int i = 0; + // for (int reach = 0; i < nums.size() && i <= reach; ++i) + // reach = max(i + nums[i], reach); + // return i == nums.size(); + + if (nums.size() == 0) return false; + int len = nums.size() - 1; + for (int i = nums.size() - 1; i >= 0; i--) { + if (nums[i] + i >= len) + len = i; + } + return len == 0; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/69-sqrtx.cc b/Week 03/id_586/69-sqrtx.cc new file mode 100755 index 000000000..64892e7c2 --- /dev/null +++ b/Week 03/id_586/69-sqrtx.cc @@ -0,0 +1,26 @@ +class Solution { +public: + int mySqrt(int x) { + // 注意:针对特殊测试用例,例如 2147395599 + // 要把搜索的范围设置成长整型 + // 为了照顾到 0 把左边界设置为 0 + if (x == 0 || x == 1) return x; + + long left = 0; + // # 为了照顾到 1 把右边界设置为 x // 2 + 1 + long right = x / 2 + 1; + + while (left < right) { + // 注意:这里一定取右中位数,如果取左中位数,代码会进入死循环 + // long mid = left + (right - left + 1) / 2; + long mid = (left + right + 1) >> 1; + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid; + } + } + // 因为一定存在,因此无需后处理 + return (int) left; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/860-lemonade-change.cc b/Week 03/id_586/860-lemonade-change.cc new file mode 100755 index 000000000..2b70b8209 --- /dev/null +++ b/Week 03/id_586/860-lemonade-change.cc @@ -0,0 +1,14 @@ +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) five--, ten++; + else if (ten > 0) ten--, five--; + else five -= 3; + if (five < 0) return false; + } + return true; + } +}; \ No newline at end of file diff --git a/Week 03/id_586/NOTE.md b/Week 03/id_586/NOTE.md index a6321d6e2..29a579c60 100644 --- a/Week 03/id_586/NOTE.md +++ b/Week 03/id_586/NOTE.md @@ -1,4 +1,123 @@ # NOTE - +[DFS 代码模板(递归写法、非递归写法)](https://shimo.im/docs/ddgwCccJQKxkrcTq/read) +递归写法 + +```python +visited = set() + +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + # ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) +``` + +非递归写法 + +```python +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + # ... +``` + +[BFS 代码模板](https://shimo.im/docs/P8TqKHGKt3ytkYYd/read) + +```python +def BFS(graph, start, end): + + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + # ... +``` + +实战题目 + + https://leetcode-cn.com/problems/binary-tree-level-order-traversal/#/description + https://leetcode-cn.com/problems/minimum-genetic-mutation/#/description + https://leetcode-cn.com/problems/generate-parentheses/#/description + https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/#/description + +课后作业 + + https://leetcode-cn.com/problems/word-ladder/description/ + https://leetcode-cn.com/problems/word-ladder-ii/description/ + https://leetcode-cn.com/problems/number-of-islands/ + https://leetcode-cn.com/problems/minesweeper/description/ + +参考链接 + + [coin change 题目](https://leetcode-cn.com/problems/coin-change/) + [动态规划定义](https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92) + +课后作业 + + https://leetcode-cn.com/problems/lemonade-change/description/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + https://leetcode-cn.com/problems/assign-cookies/description/ + https://leetcode-cn.com/problems/walking-robot-simulation/description/ + https://leetcode-cn.com/problems/jump-game/ 、 https://leetcode-cn.com/problems/jump-game-ii/ + +参考链接 + +[二分查找代码模板](https://shimo.im/docs/hjQqRQkGgwd9g36J/read) +[Fast InvSqrt() 扩展阅读](https://www.beyond3d.com/content/articles/8/) + +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +实战题目 + + https://leetcode-cn.com/problems/sqrtx/ + https://leetcode.com-cn/problems/valid-perfect-square/ + +课后作业 + + https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + https://leetcode-cn.com/problems/search-a-2d-matrix/ + https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + 使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + 说明:同学们可以将自己的思路、代码写在第 3 周的学习总结中 \ No newline at end of file diff --git a/Week 03/id_586/linux_list/CircularLinkeList.png b/Week 03/id_586/linux_list/CircularLinkeList.png new file mode 100755 index 000000000..b6a00922a Binary files /dev/null and b/Week 03/id_586/linux_list/CircularLinkeList.png differ diff --git a/Week 03/id_586/linux_list/DoublyLinkedList.png b/Week 03/id_586/linux_list/DoublyLinkedList.png new file mode 100755 index 000000000..6c9847c92 Binary files /dev/null and b/Week 03/id_586/linux_list/DoublyLinkedList.png differ diff --git a/Week 03/id_586/linux_list/Makefile b/Week 03/id_586/linux_list/Makefile new file mode 100644 index 000000000..874fe41b7 --- /dev/null +++ b/Week 03/id_586/linux_list/Makefile @@ -0,0 +1,9 @@ +obj-m := list.o +KDIR := /lib/modules/`uname -r`/build + +all: + make -C $(KDIR) M=$$PWD + +clean: + make -C $(KDIR) M=$$PWD clean + diff --git a/Week 03/id_586/linux_list/SingleLinkedlist.png b/Week 03/id_586/linux_list/SingleLinkedlist.png new file mode 100755 index 000000000..f6744fcf2 Binary files /dev/null and b/Week 03/id_586/linux_list/SingleLinkedlist.png differ diff --git a/Week 03/id_586/linux_list/container_of.png b/Week 03/id_586/linux_list/container_of.png new file mode 100755 index 000000000..584ee9de1 Binary files /dev/null and b/Week 03/id_586/linux_list/container_of.png differ diff --git a/Week 03/id_586/linux_list/linux_list.md b/Week 03/id_586/linux_list/linux_list.md new file mode 100755 index 000000000..9ad27b855 --- /dev/null +++ b/Week 03/id_586/linux_list/linux_list.md @@ -0,0 +1,427 @@ +# Linux 内核链表及其应用 + +链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链, +是线性表的一种重要实现方式。有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间, +可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是**访问的顺序性和组织链的空间损失**。 + +使用链表的情况是: **遍历所有数据**或者**需要动态加入和删除数据** + +## 单链表, 双链表 和 循环链表 + +Linux 内核中使用了很多数据结构,关于链表内核就是提供了**单链表,双链表 和哈希表** + +- 单链表: + 单链表代码在 include/linux/llist.h 和 lib/llist.c 中。内核巧妙的使用 CPU 提供的 cmpxchg 指令实现了一个无锁的单链表 +- 双链表 + 双链表操作函数都在 include/linux/list.h +- 哈希表 + 哈希表使用双链表,具体代码在: include/linux/list.h + +这篇文章主要介绍了 Linux 双链表 + +### 1. 通常一个单链表的结构体如下所示 + +```c +struct list { + void *data; /* 指向链表数据 */ + struct list *next; /* 指向下一个结点 */ +}; +``` + +单链表的示意图如下: + +![单链表](SingleLinkedlist.png) + +### 2. 通常一个双链表的结构体如下所示 + +```c +struct list { + void *data; /* 指向链表数据 */ + struct list *next; /* 指向下一个结点 */ + struct list *prev; /* 指向上一个结点 */ +}; +``` + +双链表的示意图如下: + +![双链表](DoublyLinkedList.png) + +### 3. 循环链表 + +循环链表的示意图如下: + +![循环链表](CircularLinkeList.png) + +循环链表是一种特殊的单链表。它跟单链表唯一的区别就在尾结点。 +单链表的尾结点指针指向空地址, 而循环链表的尾结点指针是指向链表的头结点。 + +## Linux 内核的实现 + +在Linux内核中使用了大量的链表结构来组织数据,包括设备列表以及各种功能模块中的数据组织。这些链表大多采用在 +**include/linux/list.h** + +相对于通常的链表实现的方法,Linux内核的实现很有意思。通常的链表实现是通过在数据结构体内部添加一个指向数据的 +next/prev 结点指针,使得数据链接起来,形成链表的。 + +Linux内核的实现方式与众不同,并不是在数据结构中添加链表,而是把链表当成一个数据类型添加到数据结构中的。Linux内核 +链表是怎么实现的呢,下面我们一步一步进行解读: + +### 1. 内核链表的数据结构 + +Linux内核链表的代码放在 **include/linux/list.h**, 感兴趣的同学可以查看 + +链表的声明在 **include/linux/types.h** 中: + +```c +struct list_head { + struct list_head *next, *prev; +}; +``` + +有了这个定义我们该怎么使用呢?假如我们有一个 book 结构体,想把所有的制作一个列表清单则可简单定义如下: + +```c +struct book { + int id; /* 书的 ID */ + struct list_head list; /* 所有 book 结构体形成的链表 */ +} +``` + +好了我们有了一个可以使用的链表结构体,但是还是需要一些链表的操作方法才可以使用它,内核已经为我们提供好了 +一套完整操作链表的方法 list_add(), list_del(), list_swap(), list_empty() 等。这些链表操作函数有一个 +特点就是:参数都是 **struct list_head** 类型的指针 + +### 2. 访问数据 + +Linux链表中仅保存了数据项结构中 list_head 成员变量的地址,那么我们如何通过这个 list_head 成员访问到 +作为它的所有者的节点数据呢? + +Linux为此提供了一个 **list_entry(ptr, type, member)** 宏: + +- ptr 是指向该数据中list_head成员的指针,也就是存储在链表中的地址值 +- type 是数据项的类型 +- member 则是数据项类型定义中list_head成员的变量名 + +```c +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) + +/* container_of 定义在 include/linux/kernel.h中 */ +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) +``` + +list_entry 宏定义转到了 container_of, container_of在Linux内核中是一个常用的宏 +这个宏的用途就是:已知一个结构体的成员变量的首地址,进而获得整个结构体变量的首地址 + +先来分析下代码 **offsetof** 是将 0 地址强转换为 TYPE * 类型,然后取的成员 MEMBER 的地址。因为起始地址为0, +MEMBER 的地址就是该成员在 TYPE 结构体中的偏移地址。所以这个宏的意思就是: 获取 MEMBER 在 TYPE 中的偏移量 + +再看 container_of 的第一条语句把 ptr 强制转换为 void * 类型,是为了便于减去该地址在结构体的偏移量。 +第二语句就是把当前指向的地址减去所在结构体的偏移量就得到了,要求的结构体的地址,最后强制类型转换 + +可以结合下图进行学习 + +![container_of](container_of.png) + +**引用图:**[The Magical container_of() Macro ](https://radek.io/2012/11/10/magical-container_of-macro/) + +### 3. 链表操作 + +下面来看链表的操作: 这些函数的复杂度都是 O(1) 的 + +#### 1) 初始化节点 + +- LIST_HEAD 的作用是定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。 +- LIST_HEAD_INIT 的作用是初始化节点:设置name节点的前继节点和后继节点都是指向name本身。 +- INIT_LIST_HEAD 和 LIST_HEAD_INIT 一样,是初始化节点:将list节点的前继节点和后继节点都是指向list本身。 + +我们刚开始定义的一个 book 结构体可以这样使用: + static LIST_HEAD(book_list); + +```c +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} +``` + +#### 2) 添加节点 + +- __list_add(new, prev, next) 的作用是添加节点:将new插入到prev和next之间。在linux中,以"__"开头的函数是内核的内部使用 +- list_add(new, head) 的作用是添加new节点:将new添加到head之后,是new称为head的后继节点。 +- list_add_tail(new, head) 的作用是添加new节点:将new添加到head之前,即将new添加到双链表的末尾。 + +有一个book + list_add(&book->list, &book_list); + +```c +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} +``` + +#### 3) 删除节点 + +```c +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + + +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del_entry(entry); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +``` + +#### 4) 替换节点 + +```c +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +/** + * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position + * @entry1: the location to place entry2 + * @entry2: the location to place entry1 + */ +static inline void list_swap(struct list_head *entry1, + struct list_head *entry2) +{ + struct list_head *pos = entry2->prev; + + list_del(entry2); + list_replace(entry1, entry2); + if (pos == entry1) + pos = entry2; + list_add(entry1, pos); +} +``` + +#### 5)获取节点 + +```c +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +``` + +#### 6) 遍历节点 + +```c +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) +``` + +## Linux 内核链表的应用 + +### 内核实列 + +下面编写一个linux 内核模块,用以创建、增加、删除和遍历链表 + +```c +#include +#include +#include +#include + +#define N 8 /* 链表节点 */ + +struct book_list { + int id; /* 数据 */ + struct list_head list; /* 指向双联表前后节点的指针 */ +}; + +struct book_list book_head; /* 头节点 */ + +static int __init list_test_init(void) +{ + struct book_list *node; /* 每次申请链表节点时所用的指针 */ + struct list_head *pos; + struct book_list *p; + int i; + + printk("%s is starting...\n", __func__); + INIT_LIST_HEAD(&book_head.list); + + /* 建立N个节点,依次加入到链表当中 */ + for (i = 0; i < N; i++) { + /* kmalloc()在内核空间申请内存,类似于malloc,参见第四章 */ + node = (struct book_list *)kmalloc(sizeof(struct book_list), GFP_KERNEL); + node->id = i+1; + list_add_tail(&node->list, &book_head.list); + printk("Node %d has added to the list_test...\n", i+1); + } + + /* 遍历链表 */ + i = 1; + list_for_each(pos, &book_head.list) { + p = list_entry(pos, struct book_list, list); + printk("Node %d's data:%d\n", i, p->id); + i++; + } + + return 0; +} + +static void __exit list_test_exit(void) +{ + struct list_head *pos, *n; + struct book_list *p; + int i = 1; + + /* 依次删除N个节点, 为了安全删除节点而进行的遍历 */ + list_for_each_safe(pos, n, &book_head.list) { + list_del(pos); + p = list_entry(pos, struct book_list, list); + kfree(p); + printk("Node %d has removed from the list_test...\n", i++); + } + printk("%s is exiting...\n", __func__); +} + +module_init(list_test_init); +module_exit(list_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("TEST"); +``` + +```makefile +obj-m := list.o +KDIR := /lib/modules/`uname -r`/build + +all: + make -C $(KDIR) M=$$PWD + +clean: + make -C $(KDIR) M=$$PWD clean +``` + +### 安全性考虑 + +在并发执行的环境下,链表操作通常都应该考虑同步安全性问题,为了方便,Linux将这一操作留给应用自己处理。 +Linux链表自己考虑的安全性主要有两个方面: + +1. 链表为空的判断 + +内核提供了2个函数来判断链表是否为空 + + list_empty() 只是通过**头指针的next是否指向自己**来判断链表是否为空 + list_empty_careful() 同时判断头指针的next和prev,仅当两者都指向自己时才返回真 + +添加安全操作主要是为了解决调用该函数时操作链表导致 next和prev 不一致的情况 + +2. 遍历链表时删除节点 + +链表在遍历的时候,都是通过移动pos指针来遍历整个链表。但如果在遍历的操作的时候,有一个删除 pos 指向的节点的操作, +pos 指针的移动就会停止,因为 list_del(pos) 将把 pos 的 next、prev 置成 LIST_POSITION1 和 LIST_POSITION2 的特殊值。 + +所以内核又添加了两个遍历操作的"_safe"接口:list_for_each_safe(pos, n, head)、list_for_each_entry_safe(pos, n, head, member), +这两个接口要求调用者另外提供一个与 pos 同类型的指针 n,在for循环中暂存pos下一个节点的地址,避免因pos节点被释放而造成的中断 diff --git a/Week 03/id_586/linux_list/list.c b/Week 03/id_586/linux_list/list.c new file mode 100644 index 000000000..b2861a95a --- /dev/null +++ b/Week 03/id_586/linux_list/list.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#define N 8 /* 链表节点 */ + +struct book_list { + int id; /* 数据 */ + struct list_head list; /* 指向双联表前后节点的指针 */ +}; + +struct book_list book_head; /* 头节点 */ + +static int __init list_test_init(void) +{ + struct book_list *node; /* 每次申请链表节点时所用的指针 */ + struct list_head *pos; + struct book_list *p; + int i; + + printk("%s is starting...\n", __func__); + INIT_LIST_HEAD(&book_head.list); + + /* 建立N个节点,依次加入到链表当中 */ + for (i = 0; i < N; i++) { + /* kmalloc()在内核空间申请内存,类似于malloc,参见第四章 */ + node = (struct book_list *)kmalloc(sizeof(struct book_list), GFP_KERNEL); + node->id = i+1; + list_add_tail(&node->list, &book_head.list); + printk("Node %d has added to the list_test...\n", i+1); + } + + /* 遍历链表 */ + i = 1; + list_for_each(pos, &book_head.list) { + p = list_entry(pos, struct book_list, list); + printk("Node %d's data:%d\n", i, p->id); + i++; + } + + return 0; +} + +static void __exit list_test_exit(void) +{ + struct list_head *pos, *n; + struct book_list *p; + int i = 1; + + /* 依次删除N个节点, 为了安全删除节点而进行的遍历 */ + list_for_each_safe(pos, n, &book_head.list) { + list_del(pos); + p = list_entry(pos, struct book_list, list); + kfree(p); + printk("Node %d has removed from the list_test...\n", i++); + } + printk("%s is exiting...\n", __func__); +} + +module_init(list_test_init); +module_exit(list_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("TEST"); diff --git a/Week 03/id_586/summary.md b/Week 03/id_586/summary.md new file mode 100755 index 000000000..4b3e10fe7 --- /dev/null +++ b/Week 03/id_586/summary.md @@ -0,0 +1,1139 @@ +# DFS, BFS and Binary Search + +- 深度优先搜索(DFS) + +在这个策略中,我们采用深度作为优先级,以便从跟开始一直到达某个确定的叶子,然后再返回根到达另一个分支。 + +深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为先序遍历,中序遍历和后序遍历。 + +- 宽度优先搜索(BFS) + +我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到 + +```python +# DFS 代码模板 +# 递归写法 +visited = set() + +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +# 非递归写法 +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + +#BFS 代码模板 +def BFS(graph, start, end): + + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + +# 二分查找代码模板 +def bs(array, target): + left, right = 0, len(array) - 1 + while left <= right: + # mid = left + (right - left) / 2 + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +## 102 二叉树的层次遍历 + +给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + +例如: 给定二叉树: [3,9,20,null,null,15,7] + + 3 + / \ + 9 20 + / \ + 15 7 + +返回其层次遍历结果: + + [ + [3], + [9,20], + [15,7] + ] + +```CPP +/* + * 方法1 : 使用迭代法,使遍历的元素借用一个队列更方便 + * / +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> levelOrder(TreeNode* root) { + vector> ret; + + if (!root) return ret; + + queue q; + TreeNode *curr; + + q.push(root); + + while(q.empty() == 0) { + vector level; + int len = q.size(); + for (int i = 0; i < len; i++) { + curr = q.front(); + level.push_back(curr->val); + q.pop(); + if (curr->left) q.push(curr->left); + if (curr->right) q.push(curr->right); + } + ret.push_back(level); + } + + return ret; + } +}; + +/* + * 方法2: 使用递归的方法 + * */ +class Solution { +public: + vector> ret; + + void buildVector(TreeNode *root, int depth) + { + if(root == NULL) return; + /* start the current level */ + if(ret.size() == depth) + ret.push_back(vector()); + + /* fulfil the current level */ + ret[depth].push_back(root->val); + + /* process child nodes for the next level */ + buildVector(root->left, depth + 1); + buildVector(root->right, depth + 1); + } + + vector > levelOrder(TreeNode *root) { + buildVector(root, 0); + return ret; + } +}; +``` + +## 433. 最小基因变化 + +一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一个。 +假设我们要调查一个基因序列的变化。一次基因变化意味着这个基因序列中的一个字符发生了变化。 +例如,基因序列由"AACCGGTT" 变化至 "AACCGGTA" 即发生了一次基因变化。 +与此同时,每一次基因变化的结果,都需要是一个合法的基因串,即该结果属于一个基因库。 +现在给定3个参数 — start, end, bank,分别代表起始基因序列,目标基因序列及基因库,请找出能够使起始基因序列变化为目标基因序列所需的最少变化次数。如果无法实现目标变化,请返回 -1。 + +注意: + + 起始基因序列默认是合法的,但是它并不一定会出现在基因库中。 + 所有的目标基因序列必须是合法的。 + 假定起始基因序列与目标基因序列是不一样的。 + +示例 1: + + start: "AACCGGTT" + end: "AACCGGTA" + bank: ["AACCGGTA"] + 返回值: 1 + +示例 2: + + start: "AACCGGTT" + end: "AAACGGTA" + bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] + 返回值: 2 + +示例 3: + + start: "AAAAACCC" + end: "AACCCCCC" + bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] + 返回值: 3 + +```cpp +class Solution1 { +public: + //解法1:单向bfs + int minMutation(string start, string end, vector& bank) { + //1: 判读极端情况 + if(start.empty() || end.empty() || bank.empty()) return -1; + + if(find(bank.begin(), bank.end(), end) == bank.end()) + return -1; //目标基因不在基因库中 + + //2: bfs的初始化工作: 初始化步长,初始化queue,将start入队列,用vecotr来标记已经访问过的点。 + vector visit(bank.size(),0); + int step=0; + queue q; + q.push(start); + + //3: 进行bfs : 先将步长+1,然后确定每次bfs的长度size,寻找目标基因,然后出栈入栈等操作 + while (!q.empty()) { + step++; + int n = q.size();//确定每次bfs的宽度 + for (int i = 0; i < n; ++i) { + string &temp = q.front(); q.pop();//获得队头元素 + for (int j = 0; j < bank.size(); ++j) {//遍历整个基因库,访问未标记的基因;找到某个字符变异的基因添加标记,并进入队列即可 + if (visit[j] == 0) { + int diff = 0; + for (int k = 0; k < temp.size(); ++k) + if (temp[k] != bank[j][k]) diff++; + + if (diff == 1) { //找到某个字符编译的基因 + if (bank[j] == end) return step;//若该下标j代表的基因为目标基因,则直接返回步长 + visit[j] = 1;//标记下标为j的基因已访问 + q.push(bank[j]); + } + } + } + } + } + return -1; + } +}; + +/* + * - 由于单向bfs类似金字塔,越到底层,塔基越大(而众多塔基中只有一点end满足条件),而且其回溯路径也少。 + * 所以我们采用双向bfs,即既从begin->end遍历,又从end->begin遍历,当然每次我们都选用较短队列进行遍历,这样可减少用时。 + * - 循环结束的条件是两个bfs碰头。每个单词遍历的方向,1由前向后遍历,2由后向前遍历,3两个bfs碰头。 + * 公式:0|1=1、0|2=2、1|2=3和i&i=i、i&0=0 + * */ +class Solution2 { +public: + //解法2:双向bfs + int minMutation(string start, string end, vector& bank) { + //1:建立hashmap表,顺便去掉重复元素 + unordered_map mp; + for (const auto& b : bank) mp[b] = 0; + + //2:排除极端情况,end不在基因库中 + if (mp.count(end) == 0) return -1; + + //3:bfs的初始化工作 + queue q1({start}), q2({end});//前向队列,后向队列 + int step=0; + const char table[4]={'A','C','G','T'};//基因的字符 + //或1表示前向队列由前往后遍历,或2表示后向队列由后向前遍历,每次我们选用较小的队列进行遍历 + for (mp[start] |= 1,mp[end] |= 2; q1.size() && q2.size(); ++step) {//每遍历完一次,步长+1 + bool first = q1.size() < q2.size(); + queue &q = first ? q1 : q2;//选择较小的队列进行遍历节约时间 + int flag = first ? 1 : 2;//此次遍历的方式 + + for (int n = q.size(); n--; q.pop()) { + string& temp = q.front(); + if (mp[temp] == 3) return step; //两个队列碰头,返回步长 + for (int i = 0; i < temp.size(); ++i) { + for (int j = 0; j < 4; ++j) { + string s = temp; + if (s[i] == table[j]) continue; //重复字符,跳出循环,寻找下一个字符 + s[i] = table[j]; + //该单词不在map中或该单词已经被遍历过了,跳出循环,寻找下一个单词 + if (mp.count(s) == 0 || mp[s] & flag) continue; + mp[s] |= flag;//标记该单词已经被遍历过了 + q.push(s); + } + } + } + } + return -1; + } +}; +``` + +## 22 generate-parentheses + +给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 +例如,给出 n = 3,生成结果为: + + [ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" + ] + +```cpp +class Solution { +public: + + #if 1 + vector generateParenthesis(int n) { + vector ret; + generate(ret, "", 0, 0, n); + return ret; + } + + void generate(vector &ans, string cur, int open, int close, int n) { + if (cur.length() == n * 2) { + ans.push_back(cur); + return; + } + + if (open < n) + generate(ans, cur + "(", open + 1, close, n); + if (close < open) + generate(ans, cur + ")", open, close + 1, n); + } + #else + vector generateParenthesis(int n) { + vector ret; + generate(ret, "", n, n); + return ret; + } + + void generate(vector &ans, string cur, int left, int right) { + if (left == 0 && right == 0) { + ans.push_back(cur); + return; + } + + if (left > 0) + generate(ans, cur + "(", left - 1, right); + if (right > left) + generate(ans, cur + ")", left, right - 1); + } + #endif +}; +``` + +## 515. 在每个树行中找最大值 + +您需要在二叉树的每一行中找到最大的值。 + +输入: + + 1 + / \ + 3 2 + / \ \ + 5 3 9 +输出: [1, 3, 9] + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + /* DFS solution */ + vector solution; + void helper(TreeNode* node, int cl) { + if (node == NULL) return; + + if (solution.size() < cl + 1) + solution.push_back(node->val); + else { + if (solution[cl] < node->val) + solution[cl] = node->val; + } + helper(node->left, cl+1); + helper(node->right, cl+1); + } + + vector largestValues(TreeNode* root) { + if(root == NULL) return solution; + + helper(root, 0); + return solution; + } +}; +``` + +## 126. 单词接龙 II + +```cpp +class Solution { +public: + vector> findLadders(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail; + if (dict.find(endWord) == dict.end()) { + return {}; + } + head.insert(beginWord); + tail.insert(endWord); + unordered_map> children; + vector> ladders; + vector ladder; + ladder.push_back(beginWord); + if (searchLadders(head, tail, dict, children, false)) { + genLadders(beginWord, endWord, children, ladder, ladders); + } + return ladders; + } +private: + bool searchLadders(unordered_set& head, unordered_set& tail, unordered_set& dict, unordered_map>& children, bool flip) { + if (head.empty()) { + return false; + } + if (head.size() > tail.size()) { + return searchLadders(tail, head, dict, children, !flip); + } + for (string word : head) { + dict.erase(word); + } + for (string word : tail) { + dict.erase(word); + } + unordered_set intermediate; + bool done = false; + for (string word : head) { + string temp = word; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (tail.find(word) != tail.end()) { + done = true; + flip ? children[word].push_back(temp) : children[temp].push_back(word); + } else if (!done && dict.find(word) != dict.end()) { + intermediate.insert(word); + flip ? children[word].push_back(temp) : children[temp].push_back(word); + } + } + word[i] = t; + } + } + return done || searchLadders(tail, intermediate, dict, children, !flip); + } + + void genLadders(string beginWord, string endWord, unordered_map>& children, vector& ladder, vector>& ladders) { + if (beginWord == endWord) { + ladders.push_back(ladder); + } else { + for (string child : children[beginWord]) { + ladder.push_back(child); + genLadders(child, endWord, children, ladder, ladders); + ladder.pop_back(); + } + } + } +}; +``` +## 127. 单词接龙 + +给定两个单词(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" 不在字典中,所以无法进行转换。 + +算法中最重要的步骤是找出相邻的节点,也就是只差一个字母的两个单词 + +This problem has a nice BFS structure. Let's illustrate this using the example in the problem statement. + + beginWord = "hit", + endWord = "cog", + wordList = ["hot","dot","dog","lot","log","cog"] + +Since only one letter can be changed at a time, if we start from "hit", we can only change to those words which have exactly one letter different from it (in this case, "hot"). Putting in graph-theoretic terms, "hot" is a neighbor of "hit". The idea is simpy to start from the beginWord, then visit its neighbors, then the non-visited neighbors of its neighbors until we arrive at the endWord. This is a typical BFS structure. + +```cpp +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()); + queue todo; + todo.push(beginWord); + int ladder = 1; + while (!todo.empty()) { + int n = todo.size(); + for (int i = 0; i < n; i++) { + string word = todo.front(); + todo.pop(); + if (word == endWord) { + return ladder; + } + dict.erase(word); + for (int j = 0; j < word.size(); j++) { + char c = word[j]; + for (int k = 0; k < 26; k++) { + word[j] = 'a' + k; + if (dict.find(word) != dict.end()) { + todo.push(word); + } + } + word[j] = c; + } + } + ladder++; + } + return 0; + } +}; +``` + +The above code starts from a single end beginWord. We may also start from the endWord simultaneously. Once we meet the same word, we are done. This link provides such a two-end search solution. I rewrite the code below for better readability. This solution uses two pointers phead and ptail to switch to the smaller set at each step to save time. + +```cpp +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail; + if (dict.find(endWord) == dict.end()) { + return 0; + } + head.insert(beginWord); + tail.insert(endWord); + int ladder = 2; + while (!head.empty() && !tail.empty()) { + if (head.size() < tail.size()) { + phead = &head; + ptail = &tail; + } else { + phead = &tail; + ptail = &head; + } + unordered_set temp; + for (auto it = phead -> begin(); it != phead -> end(); it++) { + string word = *it; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (ptail -> find(word) != ptail -> end()) { + return ladder; + } + if (dict.find(word) != dict.end()) { + temp.insert(word); + dict.erase(word); + } + } + word[i] = t; + } + } + ladder++; + phead -> swap(temp); + } + return 0; + } +}; +``` + +## 529. 扫雷游戏 + +给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。 +现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板: + + 如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。 + 如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。 + 如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。 + 如果在此次点击中,若无更多方块可被揭露,则返回面板。 + +示例 1: + + 输入: + + [['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'M', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E'], + ['E', 'E', 'E', 'E', 'E']] + + Click : [3,0] + + 输出: + + [['B', '1', 'E', '1', 'B'], + ['B', '1', 'M', '1', 'B'], + ['B', '1', '1', '1', 'B'], + ['B', 'B', 'B', 'B', 'B']] + + +```CPP +class Solution { +public: + vector> updateBoard(vector>& board, vector& click) { + if(board[click[0]][click[1]] == 'M'){ + board[click[0]][click[1]] = 'X'; + return board; + } + reveal(board,click[0],click[1]); + return board; + } + + bool inboard(const vector>& board, int x, int y){ + return ( x>=0 && x=0 && y>& board, int x, int y){ + if(!inboard(board,x,y)) return; + if(board[x][y] == 'E'){ + //search 8 adjacent squares + int count = 0; + if(inboard(board,x-1,y-1) && board[x-1][y-1] == 'M') count++; + if(inboard(board,x-1,y ) && board[x-1][y ] == 'M') count++; + if(inboard(board,x-1,y+1) && board[x-1][y+1] == 'M') count++; + if(inboard(board,x ,y-1) && board[x ][y-1] == 'M') count++; + if(inboard(board,x ,y+1) && board[x ][y+1] == 'M') count++; + if(inboard(board,x+1,y-1) && board[x+1][y-1] == 'M') count++; + if(inboard(board,x+1,y ) && board[x+1][y ] == 'M') count++; + if(inboard(board,x+1,y+1) && board[x+1][y+1] == 'M') count++; + + if(count>0) + board[x][y] = '0'+count; + else{ + board[x][y] = 'B'; + reveal(board,x-1,y-1); + reveal(board,x-1,y ); + reveal(board,x-1,y+1); + reveal(board,x ,y-1); + reveal(board,x ,y+1); + reveal(board,x+1,y-1); + reveal(board,x+1,y ); + reveal(board,x+1,y+1); + } + } + } +}; +``` + +## 200. 岛屿数量 + +给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + +示例 1: + + 输入: + 11110 + 11010 + 11000 + 00000 + + 输出: 1 + +示例 2: + + 输入: + 11000 + 11000 + 00100 + 00011 + + 输出: 3 + +```cpp +/* 方法一:深度优先搜索 + * 线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动深度优先搜索。 + * 在深度优先搜索过程中,每个访问过的结点被标记为 0。计数启动深度优先搜索的根结点的数量, + * 即为岛屿的数量。 + */ +class Solution1 { +private: + void dfs(vector>& grid, int r, int c) { + int nr = grid.size(); + int nc = grid[0].size(); + + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r-1][c] == '1') dfs(grid, r - 1, c); + if (r + 1 < nr && grid[r+1][c] == '1') dfs(grid, r + 1, c); + if (c - 1 >= 0 && grid[r][c-1] == '1') dfs(grid, r, c - 1); + if (c + 1 < nc && grid[r][c+1] == '1') dfs(grid, r, c + 1); + } + +public: + int numIslands(vector>& grid) { + int nr = grid.size(); + if (!nr) return 0; + int nc = grid[0].size(); + + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } +}; + +/* + * 方法二: 广度优先搜索 + * 线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动广度优先搜索。 + * 将其放入队列中,并将值设为 0 以标记访问过该结点。迭代地搜索队列中的每个结点, + * 直到队列为空。 + * */ +class Solution2 { +public: + int numIslands(vector>& grid) { + int nr = grid.size(); + if (!nr) return 0; + int nc = grid[0].size(); + + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + grid[r][c] = '0'; // mark as visited + queue> nei***ors; + nei***ors.push({r, c}); + while (!nei***ors.empty()) { + auto rc = nei***ors.front(); + nei***ors.pop(); + int row = rc.first, col = rc.second; + if (row - 1 >= 0 && grid[row-1][col] == '1') { + nei***ors.push({row-1, col}); grid[row-1][col] = '0'; + } + if (row + 1 < nr && grid[row+1][col] == '1') { + nei***ors.push({row+1, col}); grid[row+1][col] = '0'; + } + if (col - 1 >= 0 && grid[row][col-1] == '1') { + nei***ors.push({row, col-1}); grid[row][col-1] = '0'; + } + if (col + 1 < nc && grid[row][col+1] == '1') { + nei***ors.push({row, col+1}); grid[row][col+1] = '0'; + } + } + } + } + } + + return num_islands; + } +}; +``` + +## 322. 零钱兑换 + +给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 + +示例 1: + + 输入: coins = [1, 2, 5], amount = 11 + 输出: 3 + 解释: 11 = 5 + 5 + 1 + +示例 2: + + 输入: coins = [2], amount = 3 + 输出: -1 + +说明: 你可以认为每种硬币的数量是无限的。 + +```cpp +class Solution { +public: + int coinChange(vector& coins, int amount) { + // int Max = amount + 1; + // vector dp(amount + 1, Max); + // dp[0] = 0; + // for (int i = 1; i <= amount; i++) { + // for (int j = 0; j < coins.size(); j++) { + // if (coins[j] <= i) { + // dp[i] = min(dp[i], dp[i - coins[j]] + 1); + // } + // } + // } + // return dp[amount] > amount ? -1 : dp[amount]; + + vector need(amount+1, amount+1); + need[0] = 0; + for (int c : coins) + for (int a = c; a <= amount; a++) + need[a] = min(need[a], need[a-c] + 1); + return need.back() > amount ? -1 : need.back(); + } +}; +``` + +## 455. 分发饼干 + +假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + +注意: + + 你可以假设胃口值为正。 + 一个小朋友最多只能拥有一块饼干。 + +示例 1: + + 输入: [1,2,3], [1,1] + + 输出: 1 + +解释: + 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + 所以你应该输出1。 + +示例 2: + + 输入: [1,2], [1,2,3] + + 输出: 2 + +解释: + 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + 所以你应该输出2. + +```CPP +/*贪心问题。优先满足胃口小的小朋友的需求。 + 1. 对 g 和 s 升序排序 + 2. 初始化两个指针 i 和 j 分别指向 g 和 s 初始位置 + 3. 对比 g[i] 和 s[j] + g[i] <= s[j]:饼干满足胃口,把能满足的孩子数量加 1,并移动指针 i = i + 1,j = j + 1 + g[i] > s[j]:无法满足胃口,j 右移,继续查看下一块饼干是否可以满足胃口 +*/ +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + int g_length = g.size(); + int s_length = s.size(); + + int i = 0; + int j = 0; + int res = 0; + + while (i < g_length && j < s_length) { + if (g[i] <= s[j]) { + //可以满足胃口,把小饼干喂给小朋友 + res += 1; + i += 1; + j += 1; + } else + //不满足胃口,查看下一块小饼干 + j += 1; + } + return res; + } +}; +``` + +## 122. 买卖股票的最佳时机 II + +给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 +设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + +示例 1: + + 输入: [7,1,5,3,6,4] + 输出: 7 + 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 + +```CPP +class Solution { +public: + int maxProfit(vector& prices) { + int maxprofit = 0; + for (int i = 1; i < prices.size(); i++) { + if (prices[i] > prices[i - 1]) + maxprofit += prices[i] - prices[i - 1]; + } + return maxprofit; + } +}; +``` + +## 55. 跳跃游戏 + +给定一个非负整数数组,你最初位于数组的第一个位置。 +数组中的每个元素代表你在该位置可以跳跃的最大长度。 +判断你是否能够到达最后一个位置。 + +示例 1: + + 输入: [2,3,1,1,4] + 输出: true + 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + +示例 2: + + 输入: [3,2,1,0,4] + 输出: false + 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 + +```cpp +class Solution { +public: + bool canJump(vector& nums) { + // int i = 0; + // for (int reach = 0; i < nums.size() && i <= reach; ++i) + // reach = max(i + nums[i], reach); + // return i == nums.size(); + + if (nums.size() == 0) return false; + int len = nums.size() - 1; + for (int i = nums.size() - 1; i >= 0; i--) + if (nums[i] + i >= len) len = i; + return len == 0; + } +}; +``` + +## 860. 柠檬水找零 + +在柠檬水摊上,每一杯柠檬水的售价为 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 + +```cpp +/* +Count the number of $5 and $10 in hand. +if (customer pays with $5) five++; +if (customer pays with $10) ten++, five--; +if (customer pays with $20) ten--, five-- or five -= 3; +*/ +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) five--, ten++; + else if (ten > 0) ten--, five--; + else five -= 3; + if (five < 0) return false; + } + return true; + } +}; +``` + +## 69. x 的平方根 + +实现 int sqrt(int x) 函数。 +计算并返回 x 的平方根,其中 x 是非负整数。 +由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 + +示例 1: + + 输入: 4 + 输出: 2 + +示例 2: + + 输入: 8 + 输出: 2 + 说明: 8 的平方根是 2.82842..., + 由于返回类型是整数,小数部分将被舍去。 + +```cpp +class Solution { +public: + int mySqrt(int x) { + // 注意:针对特殊测试用例,例如 2147395599 + // 要把搜索的范围设置成长整型 + // 为了照顾到 0 把左边界设置为 0 + if (x == 0 || x == 1) return x; + + long left = 0; + // # 为了照顾到 1 把右边界设置为 x // 2 + 1 + long right = x / 2 + 1; + + while (left < right) { + // 注意:这里一定取右中位数,如果取左中位数,代码会进入死循环 + long mid = left + (right - left + 1) / 2; + //long mid = (left + right + 1) >> 1; + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid; + } + } + // 因为一定存在,因此无需后处理 + return (int) left; + } +}; +``` + +## 33. 搜索旋转排序数组 + +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +你可以假设数组中不存在重复的元素。 +你的算法时间复杂度必须是 O(log n) 级别。 + +示例 1: + + 输入: nums = [4,5,6,7,0,1,2], target = 0 + 输出: 4 + +示例 2: + + 输入: nums = [4,5,6,7,0,1,2], target = 3 + 输出: -1 + +```cpp +class Solution { +public: + int search(vector& nums, int target) { +#ifdef OK + int lo = 0, hi = nums.size(); + while (lo < hi) { + int mid = (lo + hi) / 2; + + double num = (nums[mid] < nums[0]) == (target < nums[0]) + ? nums[mid] + : target < nums[0] ? -INFINITY : INFINITY; + + if (num < target) + lo = mid + 1; + else if (num > target) + hi = mid; + else + return mid; + } + return -1; +#else + int lo=0,hi=nums.size()-1; + // find the index of the smallest value using binary search. + // Loop will terminate since mid < hi, and lo or hi will shrink by at least 1. + // Proof by contradiction that mid < hi: if mid==hi, then lo==hi and loop would have been terminated. + while(lonums[hi]) lo=mid+1; + else hi=mid; + } + // lo==hi is the index of the smallest value and also the number of places rotated. + int rot=lo; + lo=0;hi=nums.size()-1; + // The usual binary search and accounting for rotation. + while(lo<=hi){ + int mid=(lo+hi)/2; + int realmid=(mid+rot)%nums.size(); + if(nums[realmid]==target)return realmid; + if(nums[realmid]>1; + if( target < nums[0] && target > nums[mid]){ + low = mid+1; + } + else if(nums[0] <= nums[mid] && (target > nums[mid] || target < nums[0])) { + low = mid+1; + } + else{ + high = mid; + } + } + return low == high && nums[low] == target ? low : -1; +}; diff --git a/Week 03/id_591/LeetCode_69_591.js b/Week 03/id_591/LeetCode_69_591.js new file mode 100644 index 000000000..b83820318 --- /dev/null +++ b/Week 03/id_591/LeetCode_69_591.js @@ -0,0 +1,21 @@ +/** + * @param {number} x + * @return {number} + */ +var mySqrt = function(x) { + if(x<=1){ + return x; + } + let left = 1, right = Math.ceil(x/2); + while(left <= right){ + let middle = parseInt((left + right)/2); + if(middle*middle < x){ + left = middle + 1; + }else if(middle*middle > x){ + right = middle - 1; + }else{ + return middle; + } + } + return right; +}; \ No newline at end of file diff --git a/Week 03/id_591/NOTE.md b/Week 03/id_591/NOTE.md index a6321d6e2..4ac18b1c1 100644 --- a/Week 03/id_591/NOTE.md +++ b/Week 03/id_591/NOTE.md @@ -1,4 +1,129 @@ -# NOTE +# 笔记 +## 1、树深度优先遍历和广度优先遍历 +### 1.1、区别 +#### 1.1.1、遍历顺序不一样 +深度优先遍历是先遍历子节点再遍历兄弟节点,广度优先遍历是先遍历兄弟节点再遍历子节点。 +#### 1.1.2、实现算法不一样 +因为访问都是从根节点开始,深度优先遍历采用递归或者栈实现,实现先进后出,而广度优先遍历采用先进先出的队列的方式实现。 +深度优先遍历模版 +```python +//递归实现 +visited = set() +def dfs(node, visited): +if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +//非递归实现,自己维护栈来实现 +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... +``` +例子:二叉树的深度遍历: +```javascript +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ + +var levelOrder = function(root) { + var result = {}; + + var levelOrderRecursion = function(root, level){ + if(!root){ + return; + } + + if(!result[level]){ + result[level] = []; + } + result[level].push(root.val); + + levelOrderRecursion(root.left, level+1); + levelOrderRecursion(root.right, level+1); + } + + levelOrderRecursion(root, 0); + return Object.values(result); +}; +``` + +广度优先遍历模版: +```python +def BFS(graph, start, end): + + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... +``` +## 2、贪心算法 +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有 +利)的选择,从而希望导致结果是全局最好或最优的算法。 + +### 2.1、与动态规划的区别 +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退;动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +### 2.2、适用贪心算法的场景 +简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。 +## 3、二分查找 +### 3.1、二分查找的前提 +1. 目标函数单调性(单调递增或者递减) +2. 存在上下界(bounded) +3. 能够通过索引访问(index accessible) + +### 3.2、代码模版 +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` diff --git a/Week 03/id_596/LeetCode_153_596.py b/Week 03/id_596/LeetCode_153_596.py new file mode 100644 index 000000000..613e1ea58 --- /dev/null +++ b/Week 03/id_596/LeetCode_153_596.py @@ -0,0 +1,14 @@ +class Solution: + def findMin(self, nums: List[int]) -> int: + left = 0 + right = len(nums) - 1 + + while left < right: + mid = (right - left) // 2 + left + + if (nums[mid] < nums[right]): + right = mid + else: + left = mid + 1 + + return nums[left] \ No newline at end of file diff --git a/Week 03/id_596/LeetCode_529_596.py b/Week 03/id_596/LeetCode_529_596.py new file mode 100644 index 000000000..04775577e --- /dev/null +++ b/Week 03/id_596/LeetCode_529_596.py @@ -0,0 +1,51 @@ +class Solution: + def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]: + # 非法输入 + if not board or not board[0]: + return board + + x, y = click[0], click[1] + # 一下就挖到地雷,提前返回 + if board[x][y] == 'M': + board[x][y] = 'X' + return board + # 得到地图的长宽 + m, n = len(board), len(board[0]) + # 用来记录访问历史的二维数组,0为未访问,1为访问过 + visited = [[0 for _ in range(n + 1)] for j in range(m + 1)] + # 用来组成向八个方向搜索的向量 + dx = [1, 1, -1, -1, 0, 0, -1, 1] + dy = [1, 0, -1, 0, 1, -1, 1, -1] + + def dfs(x, y): + # 如果是地雷或者访问过,停止搜索 + if board[x][y] == 'M' or visited[x][y] == 1: + return + + visited[x][y] = 1 + mineCount = 0 # 用来统计附近的地雷个数 + + # 向八个方向搜索 + for k in range(len(dx)): + x1 = x + dx[k] + y1 = y + dy[k] + + # 判断是否是地雷 + if 0 <= x1 < m and 0 <= y1 < n and board[x1][y1] == 'M': + mineCount += 1 + + if mineCount > 0: + board[x][y] = str(mineCount) # 在地图上标记地雷个数 + else: + board[x][y] = 'B' # 没有相邻地雷,需要对该位置的八个方向做相同的搜索 + + for k in range(len(dx)): + x1 = x + dx[k] + y1 = y + dy[k] + + # 过滤掉越界和访问过的位置 + + if 0 <= x1 < m and 0 <= y1 < n and visited[x1][y1] == 0: + dfs(x1, y1) + dfs(x, y) + return board \ No newline at end of file diff --git a/Week 03/id_596/NOTE.md b/Week 03/id_596/NOTE.md index a6321d6e2..f098cfe7b 100644 --- a/Week 03/id_596/NOTE.md +++ b/Week 03/id_596/NOTE.md @@ -1,4 +1,129 @@ # NOTE - +> 使用二分查找,寻找一个半有序数组[4, 5, 6, 7, 0, 1, 2]中间无序的地方 +思路与LeetCode作业153一样,需要出数组中的最小值,那么该位置之后直到数组结尾都为无序的地方。 +实现代码如下: + +```python +def findMin(self, nums: List[int]) -> int: + left = 0 + right = len(nums) - 1 + + while left < right: + mid = (right - left) // 2 + left + + if (nums[mid] < nums[right]): + right = mid + else: + left = mid + 1 + + return nums[left] +``` + +## 学习笔记 + +### 深度优先搜索和广度优先搜索 + +遍历需要满足的条件 +* 每个节点都要访问一次 +* 每个节点仅仅访问一次 +* 对于节点的访问顺序不限 + * 深度优先:depth first search + * 广度优先:breadth first search + +深度优先搜索可以使用递归来实现,或者使用迭代配合一个栈来模拟调用堆栈 +dfs 递归写法 +``` python +visited = set() +def dfs(node, visited): + if node in visited: + return + + visited.add(node) + # process current node + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) +``` + +dfs 非递归写法 +```python +def dfs(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_ndoes(node) + stack.push(nodes) + + # other processing work +``` + +相对的广度优先搜索可以使用队列来实现 +```python +def bfs(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other process work + ... +``` + +### 贪心算法 + +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 + +#### 贪心算法与动态规划的区别 +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择不能回退。 +动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +* 贪心:当前做局部最优判断 +* 回溯:能够回退 +* 动态规划:最优判断+回退 + +#### 贪心算法的作用 +贪心法可以解决一些最优化问题,如:求图中最小生成树,求哈夫曼编码等。然而对于工程和生活中的问题,贪心法一般不能得到我们所要求的答案 + +一旦一个问题可以通过贪心法来解决,小么贪心法一般是解决这个问题的最好办法。由于贪心法的高效性以及其所求得的答案比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +#### 贪心算法的适用场景 +简单的说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。 + +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +### 二分查找 + +#### 二分查找的前提 +1. 目标函数单调性(单调递增或者递减) +2. 存在上下界(bounded) +3. 能够通过索引访问(index accessible) + +#### 代码模版 +```python +left, right = 0, len(array)-1 +while left <= right: + mid = (left + right)/2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid + 1 +``` \ No newline at end of file diff --git a/Week 03/id_601/LeetCode_153_601.java b/Week 03/id_601/LeetCode_153_601.java new file mode 100644 index 000000000..b3a3582c3 --- /dev/null +++ b/Week 03/id_601/LeetCode_153_601.java @@ -0,0 +1,22 @@ +class Solution { + public int findMin(int[] nums) { + if (nums.length == 1) return nums[0]; + int lo = 0, hi = nums.length - 1; + while (lo <= hi) { + + if (hi - lo == 1 || hi - lo == 0) { + return nums[lo] < nums[hi] ? nums[lo] : nums[hi]; + } + + int mid = (lo + hi) / 2; + + if (nums[lo] > nums[hi] && nums[mid] > nums[hi]) { + lo = mid + 1; + }else{ + hi = mid; + } + } + + return 0; + } +} diff --git a/Week 03/id_601/LeetCode_74_601.java b/Week 03/id_601/LeetCode_74_601.java new file mode 100644 index 000000000..462584095 --- /dev/null +++ b/Week 03/id_601/LeetCode_74_601.java @@ -0,0 +1,26 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if((matrix==null||matrix.length==0)||(matrix.length==1&&matrix[0].length==0)) return false; + int left = 0; + int right = 0; + int l = 0; + for (int i=0; i= matrix[i][0]){ + right = matrix[i].length - 1; + l = i; + } + } + int mid = 0; + while (left <= right) { + mid = (left + right) / 2; + if (matrix[l][mid] == target) { + return true; + }else if (matrix[l][mid] < target) { + left = mid + 1; + }else{ + right = mid - 1; + } + } + return false; + } +} diff --git "a/Week 03/id_606/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" "b/Week 03/id_606/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" new file mode 100644 index 000000000..81820dd80 --- /dev/null +++ "b/Week 03/id_606/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=153 lang=java + * + * [153] 寻找旋转排序数组中的最小值 + * + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/description/ + * + * algorithms + * Medium (49.70%) + * Likes: 102 + * Dislikes: 0 + * Total Accepted: 21K + * Total Submissions: 42.2K + * Testcase Example: '[3,4,5,1,2]' + * + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * + * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + * + * 请找出其中最小的元素。 + * + * 你可以假设数组中不存在重复元素。 + * + * 示例 1: + * + * 输入: [3,4,5,1,2] + * 输出: 1 + * + * 示例 2: + * + * 输入: [4,5,6,7,0,1,2] + * 输出: 0 + * + */ + +// @lc code=start +class Solution { + public int findMin(int[] nums) { + int len = nums.length; + if (len == 0) { + throw new IllegalArgumentException("数组为空,无最小元素"); + } + int left = 0; + int right = len - 1; + while (left < right) { + // int mid = left + (right - left) / 2; + int mid = (left + right) >>> 1; + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + // 因为题目中说:你可以假设数组中不存在重复元素。 + // 此时一定有 nums[mid] < nums[right] + right = mid; + } + } + // 一定存在最小元素,因此无需再做判断 + return nums[left]; + + } +} +// @lc code=end diff --git "a/Week 03/id_606/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" "b/Week 03/id_606/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" new file mode 100644 index 000000000..c35952f85 --- /dev/null +++ "b/Week 03/id_606/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" @@ -0,0 +1,81 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + * + * https://leetcode-cn.com/problems/number-of-islands/description/ + * + * algorithms + * Medium (45.63%) + * Likes: 265 + * Dislikes: 0 + * Total Accepted: 36K + * Total Submissions: 78.8K + * Testcase Example: '[["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]' + * + * 给定一个由 '1'(陆地)和 + * '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + * + * 示例 1: + * + * 输入: + * 11110 + * 11010 + * 11000 + * 00000 + * + * 输出: 1 + * + * + * 示例 2: + * + * 输入: + * 11000 + * 11000 + * 00100 + * 00011 + * + * 输出: 3 + * + * + */ + +// @lc code=start +class Solution { + public int numIslands(char[][] grid) { + + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } + + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } +} +// @lc code=end diff --git a/Week 03/id_611/LeetCode_102_611.java b/Week 03/id_611/LeetCode_102_611.java new file mode 100644 index 000000000..71119817d --- /dev/null +++ b/Week 03/id_611/LeetCode_102_611.java @@ -0,0 +1,66 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import javax.swing.tree.TreeNode; + +/* + * @lc app=leetcode.cn id=102 lang=java + * + * [102] 二叉树的层次遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + public void helper(TreeNode node,int level,List> res){ + if(res.size() == level) res.add(new ArrayList<>()); + res.get(level).add(node.val); + if(node.left != null) helper(node.left, level + 1, res); + if(node.right != null) helper(node.right, level + 1, res); + + } + + public List> levelOrder(TreeNode root) { + //边界条件 + List> res = new ArrayList<>(); + if(root == null) return res; + helper(root, 0, res); + return res; + } + + // public List> levelOrder(TreeNode root) { + // //边界条件 + // List> res = new ArrayList<>(); + // if(root == null) return res; + // //迭代方式 + // //使用队列的方式进行层级访问 + // Queue queue = new LinkedList<>(); + // queue.offer(root); + + // while(!queue.isEmpty()){ + // int level = queue.size(); + // List subList = new ArrayList<>(); + // for(int i = 0; i < level; i++){ + // TreeNode node = queue.remove(); + // if(node.left != null) queue.add(node.left); + // if(node.right != null) queue.add(node.right); + // subList.add(node.val); + // } + // res.add(subList); + // } + // return res; + // } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_122_611.java b/Week 03/id_611/LeetCode_122_611.java new file mode 100644 index 000000000..182239f5b --- /dev/null +++ b/Week 03/id_611/LeetCode_122_611.java @@ -0,0 +1,20 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int max = 0; + for(int i = 1; i < prices.length; i++){ + if(prices[i] > prices[i-1]){ + max += prices[i] -prices[i-1]; + } + } + return max; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_127_611.java b/Week 03/id_611/LeetCode_127_611.java new file mode 100644 index 000000000..efe9a3078 --- /dev/null +++ b/Week 03/id_611/LeetCode_127_611.java @@ -0,0 +1,62 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import javafx.util.Pair; + +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ +// @lc code=start +class Solution { + //直接bfs + public int ladderLength(String beginWord, String endWord, List wordList) { + int L = beginWord.length(); + //预处理数据 + HashMap> dict = new HashMap<>(); + wordList.forEach(word->{ + for(int i = 0; i < L; i++){ + String newWord = word.substring(0,i) + "*" + word.substring(i+1,L); + ArrayList dicts = dict.getOrDefault(newWord, new ArrayList<>()); + dicts.add(word); + dict.put(newWord, dicts); + } + }); + + //BFS使用的queue + // Queue> Q = new LinkedList>(); + Queue> q = new LinkedList>(); + q.add(new Pair<>(beginWord, 1)); + //visited,访问过数据 + HashMap visited = new HashMap<>(); + visited.put(beginWord, true); + + //开始bfs遍历 + while(!q.isEmpty()){ + Pair p = q.poll(); + String word = p.getKey(); + Integer level = p.getValue(); + + for(int i = 0; i < L; i++){ + String newWord = word.substring(0,i) + "*" + word.substring(i+1, L); + //如果找到,跟上一级单词差距为1 + for(String item : dict.getOrDefault(newWord,new ArrayList<>())){ + if(item.equals(endWord)){ + return level + 1; + } + if(!visited.containsKey(item)){ + visited.put(item, true); + q.offer(new Pair<>(item,level +1)); + } + } + } + } + return 0; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_153_611.java b/Week 03/id_611/LeetCode_153_611.java new file mode 100644 index 000000000..6b640f3cd --- /dev/null +++ b/Week 03/id_611/LeetCode_153_611.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=153 lang=java + * + * [153] 寻找旋转排序数组中的最小值 + */ + +// @lc code=start +class Solution { + public int findMin(int[] nums) { + if(nums.length==0) return 0; + int left =0; + int right = nums.length -1; + while(left < right){ + int mid = (right + left) /2; + if(nums[mid] > nums[right]) left = mid +1; + else right = mid; + } + return nums[left]; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_200_611.java b/Week 03/id_611/LeetCode_200_611.java new file mode 100644 index 000000000..f3d0638fe --- /dev/null +++ b/Week 03/id_611/LeetCode_200_611.java @@ -0,0 +1,97 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +import javafx.util.Pair; +import sun.net.www.content.image.gif; + +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @lc code=start +class Solution { + + //bfs解法 + public int numIslands(char[][] grid) { + if(grid == null || grid.length ==0){ + return 0; + } + int nr = grid.length; + int nc = grid[0].length; + int num_length = 0; + for(int r = 0; r < nr; r++){ + for(int c = 0; c < nc; c++){ + if(grid[r][c] == '1'){ + num_length++; + grid[r][c] = '0'; + Queue> q = new LinkedList<>(); + q.add(new Pair<>(r,c)); + while(!q.isEmpty()){ + Pair pair = q.poll(); + int row = pair.getKey(); + int col = pair.getValue(); + + if(row - 1 > 0 && grid[row-1][col]=='1'){ + q.add(new Pair(row-1,col)); + grid[row-1][col] = '0'; + } + if(row + 1 > 0 && grid[row+1][col]=='1'){ + q.add(new Pair(row+1,col)); + grid[row+1][col] = '0'; + } + if(col - 1 > 0 && grid[row][col-1]=='1'){ + q.add(new Pair(row,col-1)); + grid[row][col-1] = '0'; + } + if(col + 1 > 0 && grid[row][col + 1] == '1'){ + q.add(new Pair(row,col +1)); + grid[row][col+1] = '0'; + } + } + } + } + return num_length; + } + } + + //dfs解法 + public int numIslands2(char[][] grid) { + if(grid == null || grid.length==0) return 0; + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + //纵向遍历 + for(int r = 0; r < nr; r++){ + //横向遍历 + for(int x = 0; x = nr || y >= nc || grid[r][y] =='0'){ + return; + } + grid[r][y] = '0'; + dfs(grid, r -1, y); + dfs(grid, r +1, y); + dfs(grid, r, y -1); + dfs(grid, r, y +1); + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_33_611.java b/Week 03/id_611/LeetCode_33_611.java new file mode 100644 index 000000000..ef1775703 --- /dev/null +++ b/Week 03/id_611/LeetCode_33_611.java @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=33 lang=java + * + * [33] 搜索旋转排序数组 + */ + +// @lc code=start +class Solution { + public int search(int[] nums, int target) { + int minIdx = findMinidx(nums); + if(target == nums[minIdx]) return minIdx; + int m = nums.length -1; + int start = (target <= nums[m]) ? minIdx : 0; + int end = (target > nums[m]) ? minIdx : m; + + while(start <= end){ + int mid = (start+(end - start)) >>>1; + if(nums[mid] == target) return mid; + else if(target > nums[mid]) start = mid +1; + else end = mid -1; + } + return -1; + } + + public int findMinidx(int[] nums){ + int start = 0 , end = nums.length -1; + while(start < end){ + int mid = (start + ( end - start)) >>>1; + if (nums[mid] > nums[end]) start = mid + 1; + else end = mid; + } + return start; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_433_611.java b/Week 03/id_611/LeetCode_433_611.java new file mode 100644 index 000000000..cfb5a7398 --- /dev/null +++ b/Week 03/id_611/LeetCode_433_611.java @@ -0,0 +1,62 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +/* + * @lc app=leetcode.cn id=433 lang=java + * + * [433] 最小基因变化 + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + String start = "AACCGGTT"; + String end = "AACCGGTA"; + String[] bank = new String[]{"AACCGGTA","AACCGGTC"}; + minMutation(start, end, bank); + + + } + + public static int minMutation(String start, String end, String[] bank) { + if(start.equals(end)) return 0; + Set bankSet = new HashSet<>(); + for(String b :bank) bankSet.add(b); + + char[] chars = new char[]{'A','C','G','T'}; + int level = 0; + Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + visited.add(start); + queue.offer(start); + + while(!queue.isEmpty()){ + int size = queue.size(); + while(size-- > 0){ + String cur = queue.poll(); + if(cur.equals(end)) return level; + + char[] charArr = cur.toCharArray(); + for(int i = 0; i < charArr.length; i++){ + char old = charArr[i]; + for(int c =0; c < chars.length; c++){ + charArr[i] = chars[c]; + String next = new String(charArr); + if(!visited.contains(next) && bankSet.contains(next)){ + visited.add(next); + queue.offer(next); + } + } + charArr[i] = old; + } + } + level++; + } + return -1; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_455_611.java b/Week 03/id_611/LeetCode_455_611.java new file mode 100644 index 000000000..131bcee09 --- /dev/null +++ b/Week 03/id_611/LeetCode_455_611.java @@ -0,0 +1,25 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=455 lang=java + * + * [455] 分发饼干 + */ + +// @lc code=start +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int scount = 0,gcount = 0; + while(scount < s.length && gcount < g.length){ + if(g[gcount] <= s[scount]){ + gcount++; + } + scount++; + } + return gcount; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_45_611.java b/Week 03/id_611/LeetCode_45_611.java new file mode 100644 index 000000000..7a471a9dd --- /dev/null +++ b/Week 03/id_611/LeetCode_45_611.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=45 lang=java + * + * [45] 跳跃游戏 II + */ + +// @lc code=start +class Solution { + public int jump(int[] nums) { + int end = 0; + int maxPostion = 0; + int step = 0; + for(int i = 0; i < nums.length-1; i++){ + maxPostion = Math.max(maxPostion, nums[i] + i); + if(i == end){ + end = maxPostion ; + step++; + } + } + return step; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_515_611.java b/Week 03/id_611/LeetCode_515_611.java new file mode 100644 index 000000000..b4c0d7cee --- /dev/null +++ b/Week 03/id_611/LeetCode_515_611.java @@ -0,0 +1,57 @@ +import java.util.ArrayList; +import java.util.LinkedList; + +/* + * @lc app=leetcode.cn id=515 lang=java + * + * [515] 在每个树行中找最大值 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +import javax.swing.tree.TreeNode; + +class Solution { + public List largestValues(TreeNode root) { + List data = new ArrayList<>(); + if(root == null) return data; + bfsFunc(data,root); + return data; + } + + public void bfsFunc(List data,TreeNode node){ + Queue queue = new LinkedList<>(); + + queue.offer(node); + while(!queue.isEmpty()){ + int max = Integer.MIN_VALUE; + int size = queue.size(); + while(size-- > 0){ + TreeNode tmpNode = queue.poll(); + if(tmpNode.left != null) queue.offer(tmpNode.left); + if(tmpNode.right != null) queue.offer(tmpNode.right); + + max = max < tmpNode.val ? tmpNode.val : max; + } + data.add(max); + } + + + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_529_611.java b/Week 03/id_611/LeetCode_529_611.java new file mode 100644 index 000000000..350de19e8 --- /dev/null +++ b/Week 03/id_611/LeetCode_529_611.java @@ -0,0 +1,95 @@ +import java.util.LinkedList; +import java.util.Queue; + +/* + * @lc app=leetcode.cn id=529 lang=java + * + * [529] 扫雷游戏 + */ + +// @lc code=start +class Solution { + + //bfs解法 + public char[][] updateBoard(char[][] board, int[] click) { + int m = board.length, n = board[0].length; + Queue queue = new LinkedList<>(); + queue.add(click); + + while(!queue.isEmpty()){ + int[] cell = queue.poll(); + int row = cell[0],col = cell[1]; + if(board[row][col]=='M'){ + board[row][col] = 'X'; + }else{ + int count = 0; + for(int i = -1; i < 2; i++){ + for(int j = -1; j <2; j++){ + if(i==0 && j==0)continue; + int r = row + i,c = col + j; + if(r < 0 || r >= m || c < 0 || c >= n)continue; + if(board[r][c]=='M' || board[r][c]=='X') count++; + } + } + + if(count>0){ + board[row][col]=(char)(count + '0'); + }else{ + //一定要给当前值赋值 + board[row][col] = 'B'; + for(int i = -1; i < 2; i++){ + for(int j = -1; j < 2; j++){ + if(i==0 && j==0)continue; + int r = row + i,c = col + j; + if(r < 0 || r>= m || c < 0 || c >=n )continue; + if(board[r][c]=='E'){ + queue.add(new int[]{r,c}); + board[r][c]='B'; + } + } + } + } + } + + } + return board; + } + + //dfs解法 + public char[][] updateBoard1(char[][] board, int[] click) { + int m = board.length, n = board[0].length; + int row = click[0],col = click[1]; + + if(board[row][col] =='M'){ + board[row][col] ='X'; + } else { + //计算附近地雷数量 + int count = 0; + for(int i = -1; i < 2; i++){ + for(int j = -1; j < 2; j++){ + if(j==0 && i==0)continue; + int r = row + i, c = col + j; + if(r < 0 || r >= m || c < 0 || c >= n) continue; + if(board[r][c] == 'M' || board[r][c] == 'X' ) count++; + } + } + //填充数量 + if(count>0){ + board[row][col] = (char)(count + '0'); + }else{ + board[row][col] = 'B'; + for(int i = -1; i < 2; i++){ + for(int j = -1; j < 2; j++){ + if(i==0 && j==0) continue; + int r = row + i,c = col + j; + if(r<0 || r >= m || c <0 || c >= n)continue; + if(board[r][c] == 'E') updateBoard(board, new int[]{r,c}); + } + } + } + } + return board; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_55_611.java b/Week 03/id_611/LeetCode_55_611.java new file mode 100644 index 000000000..1f99dec09 --- /dev/null +++ b/Week 03/id_611/LeetCode_55_611.java @@ -0,0 +1,19 @@ +/* + * @lc app=leetcode.cn id=55 lang=java + * + * [55] 跳跃游戏 + */ + +// @lc code=start +class Solution { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + for(int i = nums.length-1; i >= 0; i--){ + if(i + nums[i] >= lastPos) + lastPos = i; + } + return lastPos == 0; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_69_611.java b/Week 03/id_611/LeetCode_69_611.java new file mode 100644 index 000000000..b105870e5 --- /dev/null +++ b/Week 03/id_611/LeetCode_69_611.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=69 lang=java + * + * [69] x 的平方根 + */ + +// @lc code=start +class Solution { + + public int mySqrt(int x){ + long n = x; + while(n *n > x){ + n = (n + x/n)/2; + } + return (int)n; + } + + //???? + public int mySqrt1(int x) { + if (x == 0) { + return 0; + } + long left = 1; + long right = x/2 +1; + while(left < right){ + long mid = (left + right + 1) >>> 1; + long sq = mid * mid; + if(sq > x){ + right = mid -1; + }else{ + left = mid; + } + } + return (int)left; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_74_611.java b/Week 03/id_611/LeetCode_74_611.java new file mode 100644 index 000000000..416e25570 --- /dev/null +++ b/Week 03/id_611/LeetCode_74_611.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=74 lang=java + * + * [74] 搜索二维矩阵 + */ + +// @lc code=start +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if(m == 0) return false; + int n = matrix[0].length; + + int left = 0, right = n*m -1; + int pivotIdx , pivotElement; + while(left <= right){ + pivotIdx = (left + right)/2; + //privotIdx / n = 得到第几行 ,pivotIdx % n = 得到第几列 + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if(target == pivotElement) return true; + else{ + if(target < pivotElement) right = pivotIdx -1; + else left = pivotIdx + 1; + } + } + return false; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_860_611.java b/Week 03/id_611/LeetCode_860_611.java new file mode 100644 index 000000000..1a8b67023 --- /dev/null +++ b/Week 03/id_611/LeetCode_860_611.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + */ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0,ten = 0; + for(int i = 0; i < bills.length; i++){ + if(bills[i]== 5){ + five++; + }else if(bills[i] == 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; + } +} +// @lc code=end + diff --git a/Week 03/id_611/LeetCode_874_611.java b/Week 03/id_611/LeetCode_874_611.java new file mode 100644 index 000000000..bb6c82bb1 --- /dev/null +++ b/Week 03/id_611/LeetCode_874_611.java @@ -0,0 +1,35 @@ +import java.util.Set; + +/* + * @lc app=leetcode.cn id=874 lang=java + * + * [874] 模拟行走机器人 + */ + +// @lc code=start +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + Set set = new HashSet(); + for(int[] o : obstacles) + set.add(o[0] + " " + o[1]); + int max =0, x = 0,y = 0,dir = 0,dirs[][] = {{0,1},{1,0},{0,-1},{-1,0}}; + for(int c :commands){ + if(c == -2) + dir = dir == 0 ? 3 : dir - 1; + else if(c == -1) + dir = dir == 3 ? 0 : dir + 1; + else{ + int[] xy = dirs[dir]; + while(c-- > 0 && !set.contains((x + xy[0]) + " " + (y + xy[1]))){ + x += xy[0];y += xy[1]; + } + } + max = Math.max(max, x *x + y * y); + } + + return max; + } + +} +// @lc code=end + diff --git a/Week 03/id_616/LeetCode_122_616.cpp b/Week 03/id_616/LeetCode_122_616.cpp new file mode 100644 index 000000000..7f35a08e0 --- /dev/null +++ b/Week 03/id_616/LeetCode_122_616.cpp @@ -0,0 +1,12 @@ +class Solution { +public: + int maxProfit(vector& prices) { + if(prices.size() < 2) return 0; + int cnt = 0; + for(int i = 1; i < prices.size(); ++i){ + int diff = prices[i] - prices[i-1]; + if(diff > 0) cnt += diff; + } + return cnt; + } +}; \ No newline at end of file diff --git a/Week 03/id_616/LeetCode_200_616.cpp b/Week 03/id_616/LeetCode_200_616.cpp new file mode 100644 index 000000000..3aa9e40e3 --- /dev/null +++ b/Week 03/id_616/LeetCode_200_616.cpp @@ -0,0 +1,29 @@ +class Solution { +private: + void sink(vector>& grid, int i, int j, int high, int len) { + grid[i][j] = '0'; + if (i - 1 >= 0 && grid[i-1][j] == '1') sink(grid, i - 1, j,high,len); + if (i + 1 < high && grid[i+1][j] == '1') sink(grid, i + 1, j,high,len); + if (j - 1 >= 0 && grid[i][j-1] == '1') sink(grid, i, j - 1,high,len); + if (j + 1 < len && grid[i][j+1] == '1') sink(grid, i, j + 1,high,len); + } + +public: + int numIslands(vector>& grid) { + int high = grid.size(); + if (!high) return 0; + int len = grid[0].size(); + + int cnt = 0; + for (int i = 0; i < high; ++i) { + for (int j = 0; j < len; ++j) { + if (grid[i][j] == '1') { + sink(grid, i, j, high, len); + ++cnt; + } + } + } + + return cnt; + } +}; \ No newline at end of file diff --git a/Week 03/id_616/LeetCode_455_616.cpp b/Week 03/id_616/LeetCode_455_616.cpp new file mode 100644 index 000000000..3f945c791 --- /dev/null +++ b/Week 03/id_616/LeetCode_455_616.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + int cnt = 0; + int j = 0; + for(int i = 0; i < s.size(); ++i){ + if (g[j] <= s[i]){ + j++; + cnt++; + if(j >= g.size()) return cnt; + } + } + return cnt; + } +}; \ No newline at end of file diff --git a/Week 03/id_616/LeetCode_55_616.cpp b/Week 03/id_616/LeetCode_55_616.cpp new file mode 100644 index 000000000..cf704baa8 --- /dev/null +++ b/Week 03/id_616/LeetCode_55_616.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + bool canJump(vector& nums) { + if(nums.size() < 2) return true; + int base = nums.size() - 1; + for(int i = base - 1; i >= 0; --i){ + if(nums[i] >= base - i){ + base = i; + } + } + if(base == 0) return true; + return false; + } +}; \ No newline at end of file diff --git a/Week 03/id_616/LeetCode_860_616.cpp b/Week 03/id_616/LeetCode_860_616.cpp new file mode 100644 index 000000000..d1e6859af --- /dev/null +++ b/Week 03/id_616/LeetCode_860_616.cpp @@ -0,0 +1,50 @@ +class Solution { +private: + bool canChangeRight(int i, vector &change){ + if(i == 5) { + change[0]++; + return true; + } + if(i == 10) { + if(change[0] > 0){ + change[0]--; + change[1]++; + } else { + return false; + } + return true; + } + if(i == 20) { + if(change[1] > 0 && change[0] > 0){ + change[0]--; + change[1]--; + change[2]++; + return true; + } else { + if(change[0] >= 3){ + change[0] -= 3; + change[2]++; + return true; + } else { + return false; + } + } + return true; + } + return false; + } + +public: + bool lemonadeChange(vector& bills) { + vector change(3); + change[0] = 0; + change[1] = 0; + change[2] = 0; + + for(auto &i : bills){ + if(!canChangeRight(i, change)) return false; + } + + return true; + } +}; \ No newline at end of file diff --git a/Week 03/id_616/NOTE.md b/Week 03/id_616/NOTE.md index a6321d6e2..132444bf0 100644 --- a/Week 03/id_616/NOTE.md +++ b/Week 03/id_616/NOTE.md @@ -1,4 +1,108 @@ -# NOTE +# 学习总结 - +## 深度优先搜索和广度优先搜索 +### 遍历需要满足的条件 + +- 每个节点都要访问一次 +- 每个节点仅仅访问一次 +- 对于节点的访问顺序不限 + +深度优先搜索可以使用递归来实现,或者使用迭代配合一个栈来模拟调用堆栈 + +### dfs 递归写法 + +```visited = set() +def dfs(node, visited): + if node in visited: + return + + visited.add(node) + # process current node + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) +``` + +### dfs 非递归写法 + +```def dfs(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_ndoes(node) + stack.push(nodes) + + # other processing work +``` + +### 相对的广度优先搜索可以使用队列来实现 + +```def bfs(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other process work + ... +``` + +## 贪心算法 + +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 + +### 贪心算法与动态规划的区别 + +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择不能回退。 +动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +贪心:当前做局部最优判断 +回溯:能够回退 +动态规划:最优判断+回退 + +### 贪心算法的作用 + +贪心法可以解决一些最优化问题,如:求图中最小生成树,求哈夫曼编码等。然而对于工程和生活中的问题,贪心法一般不能得到我们所要求的答案 +一旦一个问题可以通过贪心法来解决,小么贪心法一般是解决这个问题的最好办法。由于贪心法的高效性以及其所求得的答案比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +### 贪心算法的适用场景 + +简单的说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。 + +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +## 二分查找 + +### 二分查找的前提 + +- 目标函数单调性(单调递增或者递减) +- 存在上下界(bounded) +- 能够通过索引访问(index accessible) + +代码模版 +```left, right = 0, len(array)-1 +while left <= right: + mid = (left + right)/2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid + 1 +``` \ No newline at end of file diff --git a/Week 03/id_631/LeetCode_127_631.go b/Week 03/id_631/LeetCode_127_631.go new file mode 100644 index 000000000..c9f501a9e --- /dev/null +++ b/Week 03/id_631/LeetCode_127_631.go @@ -0,0 +1,45 @@ +//once 20191103 14:43 +// BFS +// 50.59%, 100% +func ladderLength3(beginWord string, endWord string, wordList []string) int { + length := len(wordList) + + queue := append([]string{}, beginWord) + steps := 0 + + for len(queue) > 0 { + steps++ + + for i := len(queue); i > 0; i-- { + s := queue[0] // pop front + queue = queue[1:] + + if s == endWord { + return steps + } + + if steps >= length && len(wordList) == 0 { + return 0 + } + + for i := len(wordList) - 1; i >= 0; i-- { + if isMatch(wordList[i], s) { + queue = append(queue, wordList[i]) + wordList = append(wordList[0:i], wordList[i+1:]...) + } + } + } + } + + return 0 +} + +func isMatch(from, to string) bool { + counter := 0 + for i := 0; i < len(to); i++ { + if from[i] != to[i] { + counter++ + } + } + return counter == 1 +} \ No newline at end of file diff --git a/Week 03/id_631/LeetCode_153_631.go b/Week 03/id_631/LeetCode_153_631.go new file mode 100644 index 000000000..daa88ebb7 --- /dev/null +++ b/Week 03/id_631/LeetCode_153_631.go @@ -0,0 +1,21 @@ +//二分查找 +// 75.89% 68.18% +func findMin(nums []int) int { + if len(nums) == 0 { + return 0 + } + + l, r := 0, len(nums) - 1 + for l + 1 < r { + mid := l + (r - l) / 2 + if nums[mid] <= nums[r] { + r = mid + } else { + l = mid + } + } + if nums[l] > nums[r] { + return nums[r] + } + return nums[l] +} \ No newline at end of file diff --git a/Week 03/id_631/LeetCode_860_631.go b/Week 03/id_631/LeetCode_860_631.go new file mode 100644 index 000000000..04063d483 --- /dev/null +++ b/Week 03/id_631/LeetCode_860_631.go @@ -0,0 +1,31 @@ +//因为 20 可以用10 和 5 换, 10 可以 用5 换 +// 贪心策略需要尽可能地多留 5元在手上,防止10元的顾客无法找零。 +// 85.25%, 100% +func lemonadeChange(bills []int) bool { + five := 0 + ten := 0 + for _, bill := range bills { + if bill == 5 { + five++ + } else if bill == 10 { + if five >= 1 { + five-- + ten++ + } else { + return false + } + } else if bill == 20 { + if ten >= 1 && five >= 1 { + five-- + ten-- + } else if five >= 3 { + five = five - 3 + } else { + return false + } + } else { + return false + } + } + return true +} \ No newline at end of file diff --git a/Week 03/id_631/NOTE.md b/Week 03/id_631/NOTE.md index a6321d6e2..867af7984 100644 --- a/Week 03/id_631/NOTE.md +++ b/Week 03/id_631/NOTE.md @@ -1,4 +1,116 @@ # NOTE - +## BFS && DFS + * 遍历 = 暴力搜索 + * 树/图 每个节点只被访问一次 + * 深度优先、广度优先、优先级优先(启发式搜索算法, 推荐算法) + +```python +def dfs(node): + if node in visited: + return + visited.add(node) + + #process current node + + dfs(node.left) + dfs(node.right) + +visited = set(); +def dfs(node, visited): + # terminator + if node in visited: + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +def DFS(node): + visited, stack = [], [node] + + for len(stack) > 0 { + node = stack.pop() + visited.add(node) + + process_cur(node) + nodes = generate_related_nodes(node) + stack.push(nodes) + } + + #other process work +``` + +```python +def BFS(graph, start, end): + queue = [] + queue.append([start]) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... + +``` + +## 贪心算法 + +* 贪心算法: 当下做出局部最优判断,不能回退, 适合最优子结构性质的问题 +* 回溯算法: 能够回退 +* 动态规划: 最优判断+ 回退, 会保存之前的结果, 根据结果选择回退,常常适用于有重叠子问题和最优子结构性质的问题 + +场景: + + 1. 图的最小生成树 + 2. 哈夫曼编码 + +特点: + + 1. 高效 + 2. 适合接近最优解的情况 + 3. 可作为辅助算法 + +## 二分查找 + +条件: + + 1. 有序 + 2. 上下界 + 3. 索引访问 + +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +```c +//牛顿迭代法 +float InvSqrt (float x){ + float xhalf = 0.5f*x; + int i = *(int*)&x; + i = 0x5f3759df - (i>>1); + x = *(float*)&i; + x = x*(1.5f - xhalf*x*x); + return x; +} +``` diff --git a/Week 03/id_636/LeetCode_102_636.py b/Week 03/id_636/LeetCode_102_636.py new file mode 100644 index 000000000..69990bbb2 --- /dev/null +++ b/Week 03/id_636/LeetCode_102_636.py @@ -0,0 +1,46 @@ +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class List(list): + pass + + +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + # BFS + # DFS 使用 dfs,需要记录每层的 depth + # 先用 BFS 做 + res = [] + + # def + def bfs(root: TreeNode, depth: int): + # check if not root + if not root: + return + + # ? init depth's res ? + if len(res) == depth: + res.append([]) + + # process + res[depth].append(root.val) + + # left + bfs(root.left, depth + 1) + + # right + bfs(root.right, depth + 1) + + bfs(root, 0) + + return res + + def levelOrder_dfs(self, root: TreeNode) -> List[List[int]]: + # 使用 DFS + res = [] + + diff --git a/Week 03/id_636/LeetCode_322_636.py b/Week 03/id_636/LeetCode_322_636.py new file mode 100644 index 000000000..79d28eebd --- /dev/null +++ b/Week 03/id_636/LeetCode_322_636.py @@ -0,0 +1,37 @@ +''' +给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 + +示例 1: + +输入: coins = [1, 2, 5], amount = 11 +输出: 3 +解释: 11 = 5 + 5 + 1 +示例 2: + +输入: coins = [2], amount = 3 +输出: -1 +说明: +你可以认为每种硬币的数量是无限的。 + +链接:https://leetcode-cn.com/problems/coin-change。 +''' + + +class List(list): + pass + +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + # inport + import collections + dp = collections.defaultdict(lambda: 0) + + for index in range(1, amount + 1): + cost = float('inf') + for coin in coins: + if coin <= index: + cost = min(cost, dp[index - coin] + 1) + dp[index] = cost + + return -1 if dp[amount] == float('inf') else dp[amount] + diff --git a/Week 03/id_636/LeetCode_860_636.py b/Week 03/id_636/LeetCode_860_636.py new file mode 100644 index 000000000..9ef178bae --- /dev/null +++ b/Week 03/id_636/LeetCode_860_636.py @@ -0,0 +1,72 @@ +''' + +在柠檬水摊上,每一杯柠檬水的售价为 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  + +链接:https://leetcode-cn.com/problems/lemonade-change + +''' + + +class List(list): + pass + +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True diff --git a/Week 03/id_636/NOTE.md b/Week 03/id_636/NOTE.md index a6321d6e2..3c7a892b6 100644 --- a/Week 03/id_636/NOTE.md +++ b/Week 03/id_636/NOTE.md @@ -1,4 +1,73 @@ # NOTE +### 第三课、补充第二课中一些知识: +* [常见的数据结构](https://github.com/teslapatrick/algorithm004-01/blob/master/Week%2003/id_636/常用数据结构(待完善).pdf) +* [常见的算法](https://github.com/teslapatrick/algorithm004-01/blob/master/Week%2003/id_636/常用算法(待完善).pdf) + +### 贪心算法、动态规划对比 +* 贪心算法是一种在每一步中都取最优解,则由此判断为全局最优解;同时贪心算法会对每个子问题的解法方案给出选择,不能回退状态; +* 对比动态规划,其会保存以前的运算结果,并根据以前的结果对当前进行选择,"可以回退"; + +### BFS Module +```Python +def BFS(graph, start, end): + + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... +``` + +### DFS Module + +```Python +递归写法: +visited = set() + +def dfs(node, visited): +if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +非递归写法: + +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... + +``` + diff --git "a/Week 03/id_636/\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" "b/Week 03/id_636/\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" new file mode 100644 index 000000000..e4084f0a4 Binary files /dev/null and "b/Week 03/id_636/\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" differ diff --git "a/Week 03/id_636/\345\270\270\347\224\250\347\256\227\346\263\225\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" "b/Week 03/id_636/\345\270\270\347\224\250\347\256\227\346\263\225\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" new file mode 100644 index 000000000..53142180f Binary files /dev/null and "b/Week 03/id_636/\345\270\270\347\224\250\347\256\227\346\263\225\357\274\210\345\276\205\345\256\214\345\226\204\357\274\211.pdf" differ diff --git a/Week 03/id_641/lesson10/LeetCode_455_641.java b/Week 03/id_641/lesson10/LeetCode_455_641.java new file mode 100644 index 000000000..f494fa433 --- /dev/null +++ b/Week 03/id_641/lesson10/LeetCode_455_641.java @@ -0,0 +1,33 @@ +package vip.ruoyun.week3.lesson10; + +import java.util.Arrays; + +/** + * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 + * 对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j , + * 都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。 + * 你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + *

+ * 链接:https://leetcode-cn.com/problems/assign-cookies + */ +public class LeetCode_455_641 { + + public static int findContentChildren(int[] grid, int[] size) { + if (grid == null || size == null) return 0; + Arrays.sort(grid);//先排序 + Arrays.sort(size); + int gi = 0, si = 0; + while (gi < grid.length && si < size.length) { + if (grid[gi] <= size[si]) { + gi++; + } + si++; + } + return gi; + } + + public static void main(String[] args) { + System.out.println(findContentChildren(new int[]{1, 2, 3}, new int[]{1, 1})); + } + +} diff --git a/Week 03/id_641/lesson10/LeetCode_874_641.java b/Week 03/id_641/lesson10/LeetCode_874_641.java new file mode 100644 index 000000000..a87651690 --- /dev/null +++ b/Week 03/id_641/lesson10/LeetCode_874_641.java @@ -0,0 +1,59 @@ +package vip.ruoyun.week3.lesson10; + +import java.util.HashSet; +import java.util.Set; + +/** + * 机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令: + *

+ * -2:向左转 90 度 + * -1:向右转 90 度 + * 1 <= x <= 9:向前移动 x 个单位长度 + * 在网格上有一些格子被视为障碍物。 + *

+ * 第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1]) + *

+ * 如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。 + *

+ * 返回从原点到机器人的最大欧式距离的平方。 + *

+ * 链接:https://leetcode-cn.com/problems/walking-robot-simulation + */ +public class LeetCode_874_641 { + + public static int robotSim(int[] commands, int[][] obstacles) { + int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + int x = 0, y = 0; + int dir_index = 0; + int ans = 0; + Set blockSet = new HashSet<>(); + for (int i = 0; i < obstacles.length; i++) { + blockSet.add(obstacles[i][0] + "," + obstacles[i][1]); + } + + for (int i = 0; i < commands.length; i++) { + if (commands[i] == -1) { + dir_index = (dir_index + 1) % 4; + } else if (commands[i] == -2) { + dir_index = (dir_index + 3) % 4; + } else if (commands[i] > 0) { + for (int j = 1; j <= commands[i]; j++) { + int next_x = x + dir[dir_index][0]; + int next_y = y + dir[dir_index][1]; + if (blockSet.contains(next_x + "," + next_y)) { + break; + } else { + x = next_x; + y = next_y; + ans = Math.max(ans, x * x + y * y); + } + } + } + } + return ans; + } + + public static void main(String[] args) { + System.out.println(robotSim(new int[]{4, -1, 3}, new int[][]{})); + } +} diff --git a/Week 03/id_641/lesson11/LeetCode_33_641.java b/Week 03/id_641/lesson11/LeetCode_33_641.java new file mode 100644 index 000000000..aee05c556 --- /dev/null +++ b/Week 03/id_641/lesson11/LeetCode_33_641.java @@ -0,0 +1,48 @@ +package vip.ruoyun.week3.lesson11; + +/** + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + * 你可以假设数组中不存在重复的元素。 + * 你的算法时间复杂度必须是 O(log n) 级别 + *

+ * 链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array + */ +public class LeetCode_33_641 { + + public static int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + while (start <= end) { + int mid = (start + end) / 2; + if (target == nums[mid]) { + return mid; + } + //左半段是有序的 + if (nums[start] <= nums[mid]) { + //target 在这段里 + if (target >= nums[start] && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + //右半段是有序的 + } else { + if (target > nums[mid] && target <= nums[end]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + + } + return -1; + } + + public static void main(String[] args) { + System.out.println(search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0)); + System.out.println(search(new int[]{4, 5, 6, 7, 0, 1, 2}, 3)); + } + +} diff --git a/Week 03/id_641/lesson11/LeetCode_74_641.java b/Week 03/id_641/lesson11/LeetCode_74_641.java new file mode 100644 index 000000000..cbc91247d --- /dev/null +++ b/Week 03/id_641/lesson11/LeetCode_74_641.java @@ -0,0 +1,38 @@ +package vip.ruoyun.week3.lesson11; + +/** + * 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: + * 每行中的整数从左到右按升序排列。 + * 每行的第一个整数大于前一行的最后一个整数。 + *

+ * 链接:https://leetcode-cn.com/problems/search-a-2d-matrix + */ +public class LeetCode_74_641 { + + public static boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + + // 二分查找 + int left = 0, right = m * n - 1; + int pivotIdx, pivotElement; + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if (target == pivotElement) return true; + else { + if (target < pivotElement) right = pivotIdx - 1; + else left = pivotIdx + 1; + } + } + return false; + } + + + public static void main(String[] args) { + int[][] matrix = new int[][]{{1, 3, 5, 7}, {10, 11, 16, 20}, {23, 30, 34, 50}}; + System.out.println(searchMatrix(matrix, 20)); + } + +} diff --git a/Week 03/id_641/lesson9/LeetCode_127_641.java b/Week 03/id_641/lesson9/LeetCode_127_641.java new file mode 100644 index 000000000..074c9c1ef --- /dev/null +++ b/Week 03/id_641/lesson9/LeetCode_127_641.java @@ -0,0 +1,116 @@ +package vip.ruoyun.week3.lesson9; + + +import java.util.*; + +/** + * 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + *

+ * 每次转换只能改变一个字母。 + * 转换过程中的中间单词必须是字典中的单词。 + */ +public class LeetCode_127_641 { + + + //双端广度优先 + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; // 不存在结束字符 + if (beginWord.equals(endWord)) return 2;//等于 结束字符 + + // 预处理 双端广度优先 避免重复访问 递归 总是从少找向多 + // 预处理 + Map> patternMap = _getPatternMap(wordList); + + // 双端广度优先 + Set beginSet = new HashSet<>(), endSet = new HashSet<>(); + beginSet.add(beginWord); + endSet.add(endWord); + + Set visited = new HashSet<>(); + + // 递归 + return this._search(1, beginSet, endSet, visited, patternMap); + } + + private int _search(int level, Set beginSet, Set endSet, + Set visited, Map> patternMap) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; // 双端都找不到了 + + // process + visited.addAll(beginSet); + level++; + Set nextLevelSet = new HashSet<>(); + + // 遍历beginSet + for (String beginWord : beginSet) { + Set neighbors = _getNeighbors(beginWord, patternMap); + // 遍历所有相邻词 + for (String neighbor : neighbors) { + if (visited.contains(neighbor)) continue; // 避免重复访问 + if (endSet.contains(neighbor)) return level; // 已找到 + // 未找到,把相邻词记入下一层 + nextLevelSet.add(neighbor); + } + // 不能再此处 nextLevelSet.addAll(neighbors); 因为不能将 visited.contains(neighbor) 的节点放入 nextLevelSet + } + + // drill down + // 总是从少找向多 + if (nextLevelSet.size() <= endSet.size()) { + beginSet = nextLevelSet; + } else { + beginSet = endSet; + endSet = nextLevelSet; + } + + return this._search(level, beginSet, endSet, visited, patternMap); + + // reverse state + } + + // 返回给定单词表的所有匹映射,key为带*的匹配键,value为改匹配键可对应的单词集合 + private Map> _getPatternMap(List wordList) { + Map> map = new HashMap<>(); + for (String word : wordList) { + Set keys = _getPatterns(word); + for (String key : keys) { + if (!map.containsKey(key)) map.put(key, new HashSet<>()); + map.get(key).add(word); + } + } + return map; + } + + // 返回给定单词的所有可能的带*匹配键 + private Set _getPatterns(String word) { + Set res = new HashSet<>(); + char[] arr = word.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char temp = arr[i]; + arr[i] = '*'; + res.add(String.valueOf(arr)); + arr[i] = temp; + } + return res; + } + + // 返回给定单词、在给定匹配映射中的所有可能的相邻单词 + private Set _getNeighbors(String word, Map> patternMap) { + Set res = new HashSet<>(); + Set patterns = _getPatterns(word); + for (String pattern : patterns) { + if (!patternMap.containsKey(pattern)) continue; + res.addAll(patternMap.get(pattern)); + } + return res; + } + + public static void main(String[] args) { + String beginWord = "hit", endWord = "cog"; + String[] wordList = {"hot", "dot", "dog", "lot", "log", "cog"}; + LeetCode_127_641 sol = new LeetCode_127_641(); + System.out.println("" + sol.ladderLength(beginWord, endWord, Arrays.asList(wordList))); + } + +} diff --git a/Week 03/id_641/lesson9/LeetCode_200_641.java b/Week 03/id_641/lesson9/LeetCode_200_641.java new file mode 100644 index 000000000..7b36bfc0b --- /dev/null +++ b/Week 03/id_641/lesson9/LeetCode_200_641.java @@ -0,0 +1,84 @@ +package vip.ruoyun.week3.lesson9; + + +/** + * 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。 + * 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。 + * 你可以假设网格的四个边均被水包围。 + */ +public class LeetCode_200_641 { + // 上 左 下 右 + private static final int[][] directions = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + //标记数组,标记是否被访问过 + private boolean[][] marked; + //行 + private int rows; + //列 + private int cols; + // + private char[][] grid; + + public int numIslands(char[][] grid) { + rows = grid.length; + if (rows == 0) { + return 0; + } + this.grid = grid; + cols = grid[0].length; + // + marked = new boolean[rows][cols]; + + int count = 0; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (!marked[i][j] && grid[i][j] == '1') { + count++; + dfs(i, j); + } + } + + } + return count; + } + + //深度遍历 + private void dfs(int i, int j) { + marked[i][j] = true; + + for (int k = 0; k < 4; k++) { + int newX = i + directions[k][0]; + int newY = j + directions[k][1]; + // 如果不越界、没有被访问过、并且还要是陆地 + if (inArea(newX, newY) && grid[newX][newY] == '1' && !marked[newX][newY]) { + dfs(newX, newY); + } + } + } + + // 是否越界 + private boolean inArea(int x, int y) { + // 等于号不要忘了 + return x >= 0 && x < rows && y >= 0 && y < cols; + } + + public static void main(String[] args) { + LeetCode_200_641 solution = new LeetCode_200_641(); + char[][] grid1 = { + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'}}; + int numIslands1 = solution.numIslands(grid1); + System.out.println(numIslands1); + + char[][] grid2 = { + {'1', '1', '0', '0', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '1', '0', '0'}, + {'0', '0', '0', '1', '1'}}; + int numIslands2 = solution.numIslands(grid2); + System.out.println(numIslands2); + } + + +} diff --git "a/Week 03/id_646/\345\215\225\350\257\215\346\216\245\351\276\231.md" "b/Week 03/id_646/\345\215\225\350\257\215\346\216\245\351\276\231.md" new file mode 100644 index 000000000..c0d96f6d9 --- /dev/null +++ "b/Week 03/id_646/\345\215\225\350\257\215\346\216\245\351\276\231.md" @@ -0,0 +1,41 @@ +> 这一题,不会,找了一个别人的题解,看了几遍,默写下来了 +```js +var ladderLength = function(beginWord, endWord, wordList) { + var index=wordList.indexOf(beginWord); + if(index!==-1) + wordList.splice(index,1); + if(wordList.length===0) + return 0; + var queue=[beginWord], + res=2; + while(queue.length!==0){ + var len=queue.length; + for(var ii=0;ii1) + return false; + } + return true; + } +}; +``` \ No newline at end of file diff --git "a/Week 03/id_646/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.md" "b/Week 03/id_646/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.md" new file mode 100644 index 000000000..6f88f0ab2 --- /dev/null +++ "b/Week 03/id_646/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.md" @@ -0,0 +1,43 @@ +> 方法一:数组方法: + +> 复杂度分析:时间复杂度为O(n),空间复杂度为O(1) +```js +var searchMatrix = function (matrix, target) { + return matrix.some(item =>{ + return item.includes(target) + } ); +}; +``` + + + +> 方法二:二分查找 + +> 复杂度分析:时间复杂度O(m+logn),空间复杂度O(1) +```js +var searchMatrix = function (matrix, target) { + if (matrix.length === 0) return false; + let n = matrix[0].length; + let m = matrix.length; + + let left = 0; + let right = n - 1; + while (matrix[m - 1][0] > target && m > 1) { + m -= 1; + } + while (left <= right) { + let mid = Math.floor(left + (right - left) / 2); + let tmp = matrix[(m - 1)][mid]; + if (tmp === target) { + return true; + } else { + if (tmp < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + } + return false; +}; +``` \ No newline at end of file diff --git a/Week 03/id_651/LeetCode_33_651.cpp b/Week 03/id_651/LeetCode_33_651.cpp new file mode 100644 index 000000000..dbc66eb80 --- /dev/null +++ b/Week 03/id_651/LeetCode_33_651.cpp @@ -0,0 +1,46 @@ +/* +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +你可以假设数组中不存在重复的元素。 +你的算法时间复杂度必须是 O(log n) 级别。 +示例 1: +输入: nums = [4,5,6,7,0,1,2], target = 0 +输出: 4 +示例 2: +输入: nums = [4,5,6,7,0,1,2], target = 3 +输出: -1 + +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + //判断左右边界的值和当前中间值的大小 + //在进行中间值和目标值的大小比较 + int search(vector& nums, int target) { + int left = 0; + int right = nums.size() - 1; + while (left <= right){ + int mid = (right - left) / 2 + left; + if (nums[mid] == target) return mid; + if (nums[mid] < nums[right]){ + if (target > nums[mid] && target <= nums[right]) left = mid + 1; + else right = mid - 1; + } + else{ + if (target < nums[mid] && target >= nums[left]) right = mid - 1; + else left = mid + 1; + } + } + return -1; + } +} + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 03/id_651/LeetCode_55_651.cpp b/Week 03/id_651/LeetCode_55_651.cpp new file mode 100644 index 000000000..86bb9d193 --- /dev/null +++ b/Week 03/id_651/LeetCode_55_651.cpp @@ -0,0 +1,40 @@ +/* +给定一个非负整数数组,你最初位于数组的第一个位置。 + +数组中的每个元素代表你在该位置可以跳跃的最大长度。 + +判断你是否能够到达最后一个位置。 + +示例 1: + +输入: [2,3,1,1,4] +输出: true +解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + + +思路: + 用一个变量记录位置,然后直接遍历列表,计算该索引能够跳到的位置与变量的大小。 + 如果遍历完还没有,则是false +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + bool canJump(vector& nums) { + int k=0; + for(int i=0;ik)return false; + k = max(k,i+nums[i]); + } + return true; + } +} + + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 03/id_651/LeetCode_74_651.cpp b/Week 03/id_651/LeetCode_74_651.cpp new file mode 100644 index 000000000..8e1be20a0 --- /dev/null +++ b/Week 03/id_651/LeetCode_74_651.cpp @@ -0,0 +1,85 @@ +/* +编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: +每行中的整数从左到右按升序排列。 +每行的第一个整数大于前一行的最后一个整数。 +示例 1: +输入: +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] +] +target = 3 +输出: true +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] +] +target = 13 +输出: false + +思路: + 1. 暴力法1: 双重遍历。 查找元素 + 2. 暴力法2:拼接成一个数组,然后用二分法查找 + 3. 将二维数组具象成一个一维数组,二分法查找 +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + // 暴力法1 + bool searchMatrix1(vector>& matrix, int target) { + + for (int i=0;i< matrix.size();i++){ + for(int j=0; j< matrix[i].size();j++){ + if (matrix[i][j] == target) + return true; + } + } + return false; + } + // 暴力法2 + bool searchMatrix2(vector>& matrix, int target) { + vector result; + for(int i=0;i target) right = mid - 1; + else left = mid + 1; + } + return false; + } + // 具象成一个数组,进行二分查找 + bool searchMatrix2(vector>& matrix, int target) { + int n = matrix.size(); + // 需要判断下空数组的情况 + if (n == 0) return false; + int m = matrix[0].size(); + // 需要判断下空数组的情况 + if (m == 0) return false; + int l = 0, r = m * n - 1; + while (l != r){ + int mid = (l + r - 1) >> 1; + if (matrix[mid / m][mid % m] < target) + l = mid + 1; + else + r = mid; + } + return matrix[r / m][r % m] == target; + } +} + + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 03/id_651/LeetCode_860_651.cpp b/Week 03/id_651/LeetCode_860_651.cpp new file mode 100644 index 000000000..bb3359b74 --- /dev/null +++ b/Week 03/id_651/LeetCode_860_651.cpp @@ -0,0 +1,56 @@ +/* +在柠檬水摊上,每一杯柠檬水的售价为 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。 + +思路: 贪心算法: + 第一位是5元,不用找零 + 第二位是10元,找零5元 + 第三位是20元,则返回false + 假设前3位都是5元,第三位是10元,第四位是20元, + 则最优的是找零一张五元,一张十元,而不是三张五元 +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + bool lemonadeChange(vector& bills){ + int five=0; + int ten=0; + int twenty=0; + int len = bills.size(); + for(int i=0;i0 && ten >0){ + five--;ten--;twenty++; + } + //找3张的要后判断才是最优解 + else if(five>=3) five-=3; + else return false; + } + } + return true; + } +} + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 03/id_651/NOTE.md b/Week 03/id_651/NOTE.md index a6321d6e2..dbfad7525 100644 --- a/Week 03/id_651/NOTE.md +++ b/Week 03/id_651/NOTE.md @@ -1,4 +1,36 @@ # NOTE +Week 03 总结 +1. + 深度优先搜索(DFS): + -> 从根节点开始, 沿着树的分支一直往下找子节点 + -> 直到没有子节点, 再往回上一级, 重复第一步 + -> 直到所有的子节点都遍历了一遍 + + 广度优先搜索(BFS): 每个节点仅访问一次 + -> 从根节点开始, 沿着树的分支往下找,每层的节点。 + -> 每个节点仅访问一次 + -> 直到最后一层没有节点的时候结束 + +2. 贪心算法:找出当前情况的最优解,从而导致结果是全局最优解的算法 + + 与动态规划的区别: + 动态规划会保留以前的运算结果,根据当前结果会进行判断是否回退 +3. 二分查找 : 左右指针,向中间夹逼 + 前提: 目标函数单调性, 存在上下边界, 能通过索引访问 + 模板: + def fs(): + left = 0; right = length - 1; + while left < right: + mid = (left + right)/2 + 1; + if list[mid] == target: + return result + elif list[mid] > target: + right = mid - 1 + else: + left = mid + 1 + +总结: +做题量还没跟上,思维还没开始完全的转化, 暂时还做不到不看题解就能有思路。 还需要慢慢的积累,培养感觉 \ No newline at end of file diff --git a/Week 03/id_661/LeetCode_126_661.py b/Week 03/id_661/LeetCode_126_661.py new file mode 100644 index 000000000..5c2ccd4dc --- /dev/null +++ b/Week 03/id_661/LeetCode_126_661.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3.7 +class Solution: + def findLadders(self, beginWord: str, endWord: str, wordList: list) -> list: + wordList = set(wordList) + if endWord not in wordList: + return [] + res, visited, forward, backward, _len = ( + [], + set(), + {beginWord: [[beginWord]]}, + {endWord: [[endWord]]}, + 2, + ) + while forward: + if len(forward) > len(backward): + forward, backward = backward, forward + tmp = {} + while forward: + word, paths = forward.popitem() + visited.add(word) + for i in range(len(word)): + for a in "abcdefghijklmnopqrstuvwxyz": + new = word[:i] + a + word[i + 1 :] + if new in backward: + if paths[0][0] == beginWord: + res.extend( + fPath + bPath[::-1] + for fPath in paths + for bPath in backward[new] + ) + else: + res.extend( + bPath + fPath[::-1] + for fPath in paths + for bPath in backward[new] + ) + if new in wordList and new not in visited: + tmp[new] = tmp.get(new, []) + [ + path + [new] for path in paths + ] + _len += 1 + if res and _len > len(res[0]): + break + forward = tmp + return res diff --git a/Week 03/id_661/LeetCode_127_661.py b/Week 03/id_661/LeetCode_127_661.py new file mode 100644 index 000000000..7834355c0 --- /dev/null +++ b/Week 03/id_661/LeetCode_127_661.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3.7 + +from collections import deque + + +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + def construct_dict(word_list): + d = {} + for word in word_list: + for i in range(len(word)): + s = word[:i] + "_" + word[i + 1 :] + d[s] = d.get(s, []) + [word] + return d + + def bfs_words(begin, end, dict_words): + queue, visited = deque([(begin, 1)]), set() + while queue: + word, steps = queue.popleft() + if word not in visited: + visited.add(word) + if word == end: + return steps + for i in range(len(word)): + s = word[:i] + "_" + word[i + 1 :] + neigh_words = dict_words.get(s, []) + for neigh in neigh_words: + if neigh not in visited: + queue.append((neigh, steps + 1)) + return 0 + + d = construct_dict(wordList or set([beginWord, endWord])) + return bfs_words(beginWord, endWord, d) diff --git a/Week 03/id_661/LeetCode_200_661.py b/Week 03/id_661/LeetCode_200_661.py new file mode 100644 index 000000000..d0c88c165 --- /dev/null +++ b/Week 03/id_661/LeetCode_200_661.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def numIslands(self, grid: [[str]]) -> int: + def dfs(grid, i, j): + if not 0 <= i < len(grid) or not 0 <= j < len(grid[0]) or grid[i][j] == "0": + return + grid[i][j] = "0" + dfs(grid, i + 1, j) + dfs(grid, i, j + 1) + dfs(grid, i - 1, j) + dfs(grid, i, j - 1) + + count = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + if grid[i][j] == "1": + dfs(grid, i, j) + count += 1 + return count diff --git a/Week 03/id_661/LeetCode_33_661.py b/Week 03/id_661/LeetCode_33_661.py new file mode 100644 index 000000000..10d5672d3 --- /dev/null +++ b/Week 03/id_661/LeetCode_33_661.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: + return -1 + + low, high = 0, len(nums) - 1 + + while low <= high: + mid = int((low + high) / 2) + if target == nums[mid]: + return mid + + if nums[low] <= nums[mid]: + if nums[low] <= target <= nums[mid]: + high = mid - 1 + else: + low = mid + 1 + else: + if nums[mid] <= target <= nums[high]: + low = mid + 1 + else: + high = mid - 1 + + return -1 diff --git a/Week 03/id_661/LeetCode_455_661.py b/Week 03/id_661/LeetCode_455_661.py new file mode 100644 index 000000000..e7a07ef02 --- /dev/null +++ b/Week 03/id_661/LeetCode_455_661.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + g.sort() + s.sort() + + child = 0 + cookie = 0 + + while cookie < len(s) and child < len(g): + if s[cookie] >= g[child]: + child += 1 + cookie += 1 + + return child diff --git a/Week 03/id_661/LeetCode_529_661.py b/Week 03/id_661/LeetCode_529_661.py new file mode 100644 index 000000000..3061b396a --- /dev/null +++ b/Week 03/id_661/LeetCode_529_661.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def updateBoard(self, board, click): + (row, col), directions = ( + click, + ((-1, 0), (1, 0), (0, 1), (0, -1), (-1, 1), (-1, -1), (1, 1), (1, -1)), + ) + if 0 <= row < len(board) and 0 <= col < len(board[0]): + if board[row][col] == "M": + board[row][col] = "X" + elif board[row][col] == "E": + n = sum( + [ + board[row + r][col + c] == "M" + for r, c in directions + if 0 <= row + r < len(board) and 0 <= col + c < len(board[0]) + ] + ) + board[row][col] = str(n or "B") + for r, c in directions * (not n): + self.updateBoard(board, [row + r, col + c]) + return board diff --git a/Week 03/id_661/LeetCode_74_661.py b/Week 03/id_661/LeetCode_74_661.py new file mode 100644 index 000000000..d98f00a1c --- /dev/null +++ b/Week 03/id_661/LeetCode_74_661.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix or target is None: + return False + + rows, cols = len(matrix), len(matrix[0]) + low, high = 0, rows * cols - 1 + + while low <= high: + mid = int((low + high) / 2) + num = matrix[mid // cols][mid % cols] + + if num == target: + return True + elif num < target: + low = mid + 1 + else: + high = mid - 1 + + return False diff --git a/Week 03/id_661/LeetCode_860_661.py b/Week 03/id_661/LeetCode_860_661.py new file mode 100644 index 000000000..d7d3d1fff --- /dev/null +++ b/Week 03/id_661/LeetCode_860_661.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def lemonadeChange(self, bills): + five = ten = 0 + for i in bills: + if i == 5: + five += 1 + elif i == 10: + five, ten = five - 1, ten + 1 + elif ten > 0: + five, ten = five - 1, ten - 1 + else: + five -= 3 + if five < 0: + return False + return True diff --git a/Week 03/id_661/LeetCode_874_661.py b/Week 03/id_661/LeetCode_874_661.py new file mode 100644 index 000000000..7da3a8f12 --- /dev/null +++ b/Week 03/id_661/LeetCode_874_661.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + i = j = mx = d = 0 + move, obstacles = [(0, 1), (-1, 0), (0, -1), (1, 0)], set(map(tuple, obstacles)) + for command in commands: + if command == -2: + d = (d + 1) % 4 + elif command == -1: + d = (d - 1) % 4 + else: + x, y = move[d] + while command and (i + x, j + y) not in obstacles: + i += x + j += y + command -= 1 + mx = max(mx, i ** 2 + j ** 2) + return mx diff --git a/Week 03/id_666/LeetCode_33_666.java b/Week 03/id_666/LeetCode_33_666.java new file mode 100644 index 000000000..7dc5396ca --- /dev/null +++ b/Week 03/id_666/LeetCode_33_666.java @@ -0,0 +1,23 @@ +class Solution { + public int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + while (start <= end) { + int mid = start + (end - start) / 2; + int num = nums[mid]; + if ((nums[mid] < nums[0]) == (target < nums[0])) { + num = nums[mid]; + } else { + num = target < nums[0] ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + if (num < target) { + start = mid + 1; + } else if (num > target) { + end = mid - 1; + } else { + return mid; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 03/id_666/LeetCode_860_666.java b/Week 03/id_666/LeetCode_860_666.java new file mode 100644 index 000000000..2c1a729e5 --- /dev/null +++ b/Week 03/id_666/LeetCode_860_666.java @@ -0,0 +1,34 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + //定义收取 5 元 和 10 元的个数 + int five = 0; + int ten = 0; + for (int bill : bills) { + if (bill == 5) { + five ++; + } else if (bill == 10) { + //判断是否有找零 + if (five == 0) { + return fales; + } else { + ten ++; + five --; + } + } else { + //判断是否有足够的 5 元和 10 元 + if (five > 0 && ten > 0) { + five --; + ten --; + } else if (five >= 3) { + // 当有足够的 5 元情况 + five -= 3; + } else { + return false; + } + } + } + + return true; + } + +} \ No newline at end of file diff --git "a/Week 03/id_676/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/Week 03/id_676/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 000000000..539509595 --- /dev/null +++ "b/Week 03/id_676/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,111 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import javax.swing.tree.TreeNode; + +/* + * @lc app=leetcode.cn id=144 lang=java + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + + /* + *思路:1.使用递归的方法实现,时间复杂度为O(n) + * 2.使用栈的方法实现,时间复杂度为O(n) + */ + + //使用递归来实现 +class Solution { + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + public void helper(TreeNode root,List res) { + if (root != null) { + res.add(root.val); + if (root.left != null ) { + helper(root.left, res); + } + if (root.right != null) { + helper(root.right, res); + } + } + } +} +// @lc code=end + +//使用栈来实现 +class SolutionOne { + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + while (!stack.isEmpty() || cur != null) { + while (cur != null) { + res.add(cur.val); + stack.push(cur); + cur = cur.left; + } + cur = stack.pop(); + cur = cur.right; + } + return res; + } +} + +//递归实现中序遍历 +class SolutionTwo { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>() ; + helper(root, res); + return res; + } + + public void helper(TreeNode root,List res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + res.add(root.val); + if (root.right != null) { + helper(root.right, res); + } + } + } +} + +//递归实现后序遍历 +class SolutionThree{ + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + public void helper(TreeNode root, List res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + + if (root.right != null) { + helper(root.right, res); + } + res.add(root.val); + } + } +} diff --git "a/Week 03/id_676/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/Week 03/id_676/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 000000000..f5ec41de1 --- /dev/null +++ "b/Week 03/id_676/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,190 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import javax.swing.tree.TreeNode; + +/* + * @lc app=leetcode.cn id=145 lang=java + * + * [145] 二叉树的后序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + + /* + *思路:1.使用递归的方法实现,时间复杂度为O(n) + * 2.使用栈的方法实现,时间复杂度为O(n) + */ + + //使用递归来实现 +class Solution { + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + public void helper(TreeNode root, List res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + + if (root.right != null) { + helper(root.right, res); + } + res.add(root.val); + } + } +} +// @lc code=end + +//使用栈: +class SolutionTwo { + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) return res; + Stack stack = new Stack<>(); + stack.push(root); + while(!stack.isEmpty()) { + TreeNode cur = stack.pop(); + res.add(0,cur.val); + if (cur.left != null) { + stack.push(cur.left); + } + if (cur.right != null) { + stack.push(cur.right); + } + } + return res; + } +} + +/* +*使用栈来实现前序,中序和后序遍历 +*/ +//inorder +public List inorderTraversal(TreeNode root) { + List res=new ArrayList<>(); + if (root==null) return res; + + Stack stack=new Stack<>(); + TreeNode curr=root; + + while(curr!=null || !stack.isEmpty()){ + while (curr!=null){ + stack.push(curr); + curr=curr.left; + } + curr=stack.pop(); + res.add(curr.val); + curr=curr.right; + } + return res; +} + +//preorder +public List preorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + if(root == null) return list; + Stack stack = new Stack<>(); + stack.push(root); + while(!stack.isEmpty()) { + TreeNode current = stack.pop(); + list.add(current.val); + if(current.right!=null) { + stack.push(current.right); + } + if(current.left!=null) { + stack.push(current.left); + } + } + return list; +} + +//postorder + public List postorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + if(root == null) return list; + Stack stack = new Stack<>(); + stack.push(root); + while(!stack.isEmpty()) { + TreeNode curr = stack.pop(); + list.add(0,curr.val); + if(curr.left!=null) { + stack.push(curr.left); + } + if(curr.right!=null) { + stack.push(curr.right); + } + } + return list; +} + +/* +*使用队列来实现前序、中序和后序遍历 +*/ + +//proorder +public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Deque stack = new ArrayDeque<>(); + TreeNode p = root; + while(!stack.isEmpty() || p != null) { + if(p != null) { + stack.push(p); + result.add(p.val); // Add before going to children + p = p.left; + } else { + TreeNode node = stack.pop(); + p = node.right; + } + } + return result; +} + +//inorder +public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Deque stack = new ArrayDeque<>(); + TreeNode p = root; + while(!stack.isEmpty() || p != null) { + if(p != null) { + stack.push(p); + p = p.left; + } else { + TreeNode node = stack.pop(); + result.add(node.val); // Add after all left children + p = node.right; + } + } + return result; +} + +//postorder +public List postorderTraversal(TreeNode root) { + LinkedList result = new LinkedList<>(); + Deque stack = new ArrayDeque<>(); + TreeNode p = root; + while(!stack.isEmpty() || p != null) { + if(p != null) { + stack.push(p); + result.addFirst(p.val); // Reverse the process of preorder + p = p.right; // Reverse the process of preorder + } else { + TreeNode node = stack.pop(); + p = node.left; // Reverse the process of preorder + } + } + return result; +} \ No newline at end of file diff --git "a/Week 03/id_676/49.\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" "b/Week 03/id_676/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 000000000..3bb18ce0f --- /dev/null +++ "b/Week 03/id_676/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,82 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * @lc app=leetcode.cn id=49 lang=java + * + * [49] 字母异位词分组 + */ + + /* + *思路:1.先将字符串进行排序,排序后的字符串相等为字母异位词 + * 2.使用计数法来统计每个字符串字符出现的次数,如果相等那么就是字母异位词 + */ + +// @lc code=start +class Solution { + public List> groupAnagrams(String[] strs) { + if (strs.length == 0) return new ArrayList>(); + Map> map = new HashMap>(); + for (String s : strs) { + char[] a = s.toCharArray(); + Arrays.sort(a); //排序 + String key = String.valueOf(a); //排序后的字母异位词作为key + if (! map.containsKey(key)) { //向hashmap中添加key + map.put(key, new ArrayList()); + } + map.get(key).add(s); //向hashmap中相应的key添加对应的元素 + } + return new ArrayList>(map.values()); + } +} +// @lc code=end +class SolutionOne { + public List> groupAnagrams(String[] strs) { + if (strs.length == 0) return new ArrayList>(); + Map > map = new HashMap>(); + int[] count = new int[26]; + for (String s : strs) { //遍历传进来的字符数组中的字符串 + Arrays.fill(count, 0); //每次循环开始清0计数数组 + for (int i = 0 ; i < s.length() ; i++) { + count[s.charAt(i) - 'a'] ++; + } + StringBuilder stringbuilder = new StringBuilder(); + + for (int j = 0; j < 26;j++) { + stringbuilder.append('#'); //用#1#2.....的方式组成key值 + stringbuilder.append(count[j]); + } + String key = stringbuilder.toString(); + if (! map.containsKey(key)) { + map.put(key, new ArrayList()); + } + map.get(key).add(s); + } + return new ArrayList>(map.values()); + } +} + +class SolutionTwo { + public List> groupAnagrams(String[] strs) { + if (strs.length == 0) return new ArrayList(); + Map ans = new HashMap(); + int[] count = new int[26]; + for (String s : strs) { + Arrays.fill(count, 0); + for (char c : s.toCharArray()) count[c - 'a']++; + + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < 26; i++) { + sb.append('#'); + sb.append(count[i]); + } + String key = sb.toString(); + if (!ans.containsKey(key)) ans.put(key, new ArrayList()); + ans.get(key).add(s); + } + return new ArrayList(ans.values()); + } +} diff --git a/Week 03/id_681/LeetCode_122_681.java b/Week 03/id_681/LeetCode_122_681.java new file mode 100644 index 000000000..296c90415 --- /dev/null +++ b/Week 03/id_681/LeetCode_122_681.java @@ -0,0 +1,24 @@ +class Solution { + public int maxProfit(int[] prices) { + return calculate(prices, 0); + } + + public int calculate(int prices[], int s) { + if (s >= prices.length) + return 0; + int max = 0; + for (int start = s; start < prices.length; start++) { + int maxprofit = 0; + for (int i = start + 1; i < prices.length; i++) { + if (prices[start] < prices[i]) { + int profit = calculate(prices, i + 1) + prices[i] - prices[start]; + if (profit > maxprofit) + maxprofit = profit; + } + } + if (maxprofit > max) + max = maxprofit; + } + return max; + } +} diff --git a/Week 03/id_681/LeetCode_860_681.java b/Week 03/id_681/LeetCode_860_681.java new file mode 100644 index 000000000..74587b71d --- /dev/null +++ b/Week 03/id_681/LeetCode_860_681.java @@ -0,0 +1,26 @@ +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; + } +} + diff --git a/Week 03/id_686/LeetCode_322_686.java b/Week 03/id_686/LeetCode_322_686.java new file mode 100644 index 000000000..7bba3723b --- /dev/null +++ b/Week 03/id_686/LeetCode_322_686.java @@ -0,0 +1,39 @@ +//给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 +// +// 示例 1: +// +// 输入: coins = [1, 2, 5], amount = 11 +//输出: 3 +//解释: 11 = 5 + 5 + 1 +// +// 示例 2: +// +// 输入: coins = [2], amount = 3 +//输出: -1 +// +// 说明: +//你可以认为每种硬币的数量是无限的。 +// Related Topics 动态规划 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int coinChange(int[] coins, int amount) { + int [] f = new int[amount + 1]; + f[0] = 0; + for (int i = 1; i <= amount; i++){ + + int cost = Integer.MAX_VALUE; + for (int j = 0; j < coins.length; j++){ + if (i - coins[j] >= 0){ + if(f[i - coins[j]] != Integer.MAX_VALUE) + cost = Math.min(cost, f[i - coins[j]] + 1); + } + } + f[i] = cost; + } + return f[amount] == Integer.MAX_VALUE?-1:f[amount]; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_686/LeetCode_455_686.java b/Week 03/id_686/LeetCode_455_686.java new file mode 100644 index 000000000..f3c38ea71 --- /dev/null +++ b/Week 03/id_686/LeetCode_455_686.java @@ -0,0 +1,54 @@ +//假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 +// +// 注意: +// +// 你可以假设胃口值为正。 +//一个小朋友最多只能拥有一块饼干。 +// +// 示例 1: +// +// +//输入: [1,2,3], [1,1] +// +//输出: 1 +// +//解释: +//你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 +//虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 +//所以你应该输出1。 +// +// +// 示例 2: +// +// +//输入: [1,2], [1,2,3] +// +//输出: 2 +// +//解释: +//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 +//你拥有的饼干数量和尺寸都足以让所有孩子满足。 +//所以你应该输出2. +// +// Related Topics 贪心算法 + + +import java.util.Arrays; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int findContentChildren(int[] g, int[] s) { + if (g == null || s == null) return 0; + Arrays.sort(g); + Arrays.sort(s); + int gi = 0, si = 0; + while(gi < g.length && si < s.length){ + if (g[gi] <= s[si]){ + gi++; + } + si ++; + } + return gi; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_686/LeetCode_55_686.java b/Week 03/id_686/LeetCode_55_686.java new file mode 100644 index 000000000..11e45b9eb --- /dev/null +++ b/Week 03/id_686/LeetCode_55_686.java @@ -0,0 +1,37 @@ +//给定一个非负整数数组,你最初位于数组的第一个位置。 +// +// 数组中的每个元素代表你在该位置可以跳跃的最大长度。 +// +// 判断你是否能够到达最后一个位置。 +// +// 示例 1: +// +// 输入: [2,3,1,1,4] +//输出: true +//解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 +// +// +// 示例 2: +// +// 输入: [3,2,1,0,4] +//输出: false +//解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 +// +// Related Topics 贪心算法 数组 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean canJump(int[] nums) { + if (nums == null) return false; + int n = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--){ + if (nums[i] + i >= n) { + n = i; + } + } + return n == 0; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_686/LeetCode_69_686.java b/Week 03/id_686/LeetCode_69_686.java new file mode 100644 index 000000000..de8af6554 --- /dev/null +++ b/Week 03/id_686/LeetCode_69_686.java @@ -0,0 +1,39 @@ +//实现 int sqrt(int x) 函数。 +// +// 计算并返回 x 的平方根,其中 x 是非负整数。 +// +// 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 +// +// 示例 1: +// +// 输入: 4 +//输出: 2 +// +// +// 示例 2: +// +// 输入: 8 +//输出: 2 +//说明: 8 的平方根是 2.82842..., +//  由于返回类型是整数,小数部分将被舍去。 +// +// Related Topics 数学 二分查找 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int mySqrt(int x) { + if(x <= 1) return x; + double i = 0.0, j= (double)x, mid, temp; + while(true){ + mid = (i+j)/2; + temp = mid*mid; + if(temp-x >= 0 && temp-x <= .01) break; + if(temp < x) i = mid; + else if(temp > x) j = mid; + } + return (int)mid; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_691/691-Week 03/LeeCode_122_691.java b/Week 03/id_691/691-Week 03/LeeCode_122_691.java new file mode 100644 index 000000000..8b4b12525 --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeeCode_122_691.java @@ -0,0 +1,31 @@ +class Solution { + public int maxProfit(int[] prices) { + int i = 0; + int valley = prices[0]; + int peak = prices[0]; + int maxprofit = 0 ; + while(i < prices.length - 1){ + while(i < pricrs.length - 1 && prices[i] >= prices[ i + 1]) + i++; + valley = prices[i]; + while (i < prices.length - 1 && prices <= prices[i + 1]) + i++; + peak = prices[i]; + maxprofit += peak - valley; + } + return maxprofit; + } + + //贪心算法 + public int maxProfit(int[] prices){ + int res = 0; + for(int i = 0; i < prices.length; i++){ + int diff = prices[i + 1] - price[i]; + if(diff > 0){ + res += diff; + } + } + return res; + + } +} \ No newline at end of file diff --git a/Week 03/id_691/691-Week 03/LeeCode_127_691.java b/Week 03/id_691/691-Week 03/LeeCode_127_691.java new file mode 100644 index 000000000..da78dd971 --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeeCode_127_691.java @@ -0,0 +1,108 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + //all words are of same length + int L = beginWord.length(); + + //Dictionary to hold combination of words that can be formed + HashMap> allComboDict = new HashMap>(); + + wordList.forEach( + word -> { + for (int i = 0; i < L; i++){ + //key is generic word + //value is a list of words + String newWord = word.substring(0,i) + "*" + word.substring(i + 1,L); + ArrayList transformations = allComboDict.getOrDefault(newWord, newArrayList()); + //为什么这里要用List呀 + //一个newWord可能有多个word + transformations.add(word); + allComboDict.put(newWord,transformations); + } + } + ); + + //Queue for BFS + Queue> Q = new LinkedList>(); + Q.add(new Pair(beginWord,1)); + + //Visted to make sure we don't repeat processing same word + HashMap visited = new HashMap(); + visited.put(beginWord, true); + + while( !Q.isEmpty()) { + Pair node = Q.remove(); + String word = node.getKey(); + int level = node.getValue(); + + for(int i = 0; i < L; i++) { + + //Intermediate words for current word + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + + //next states are all the words which share the same intermediate state + for (String adjacentWord: allComboDict.getOrDefault(newWord, new ArrayList())) { + //if at any point if we find what we are looking for + //i.e the end word - we can return with the answer + if (adjacentWord.equals(endWord)){ + return level + 1; + } + + //otherwise,add it to the BFS Queue,Also male it visited + if (!visited.containsKey(adjacentWord)) { + visited.put(adjacentWord, true); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + } + + return 0 ; + } + + //双端BFS + public int ladderLength(String beginWord, String endWord, Set wordList) { + Set beginSet = new HashSet(); + Set endSet = new HashSet(); + + int len = 1; + int strLen = beginWord.length(); + HashSet visited = new HashSet(); + + beginSet.add(beginWord); + endSet.add(endWord); + + while( !beginSet.isEmpty() && !endSet.isEmpty()) { + if (beginSet.size() > endSet.size()) { + Set set = beginSet; + beginSet = endSet; + endSet = set; + } + + Set temp = new HashSet(); + for (String word: beginSet) { + char[] chs = word.toCharArray(); + for (int i = 0; i < chs.length; i++){ + for (char c = 'a'; c <= 'z'; c++) { + char old = chs[i]; + chs[i] = c; + String target = String.valueOf(chs); + + if(endSet.contains(target)){ + return len + 1; + } + + if( !visited.contains(target) && wordlist.contains(target)) { + temp.add(target); + visited.add(target); + } + + chs[i] = old; + } + } + } + + beginSet = temp; + len++'' + } + return 0; + } diff --git a/Week 03/id_691/691-Week 03/LeeCode_200_691.java b/Week 03/id_691/691-Week 03/LeeCode_200_691.java new file mode 100644 index 000000000..931d4252a --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeeCode_200_691.java @@ -0,0 +1,86 @@ +class Solution { + public int numIslands(char[][] grid) { + //深度优先 + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for(int r = 0; r < nr; ++r){ + for(int c = 0; c < nc; ++c) { + if (grid[r][c] == '1'){ + ++num_islands; + dfs(grid, r, c); + } + } + } + return num_islands; + } + + void dfs(char[][] grid, int r, int c){ + int nr = grid.length; + int nc = grid[0].length; + + if( r < 0 || c < 0 || r >= nr || grid[r][c] == + '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r ,c - 1); + dfs(grid, r, c + 1); + } + + + //广度首先 + public int numIsland(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_island = 0; + + for(int r = 0; r < nr; ++r){ + for(int c = 0; c < nc;++c){ + if(grid[r][c] == '1'){ + ++nums_islands; + grid[r][c] = '0' //mark as visited + Queue neignbors = new LinkedList<>(); + neignbors.add(r * nc + c); + while(!neignbors.isEmpty()){ + int id = neignbors.remove(); + int row = id/nc; + int col = id % nc; + + if( row - 1 >= 0 && grid[row -1][col] == '1'){ + neignbors.add((row - 1) * nc + col); + grid[row - 1][col] = '0'; + } + + if (row + 1 < nr && grid[row + 1][col] == '1'){ + neignbors.add((row + 1)* nc + col); + grid[row + 1][col] = '0'; + } + + if( col - 1 >= 0 && grid[row][col -1] == '1'){ + neignbors.add(row * nc + col - 1); + grid[row][col - 1] = '0'; + } + + if( col + 1 < nc && grid[row][col + 1] == '1') { + neignbos.add(row * nc + col + 1); + grid[row][col + 1] = '0' + } + } + } + } + } + } + +} diff --git a/Week 03/id_691/691-Week 03/LeeCode_74_691.java b/Week 03/id_691/691-Week 03/LeeCode_74_691.java new file mode 100644 index 000000000..e9b74131f --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeeCode_74_691.java @@ -0,0 +1,24 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int row_num = matrix.length; + int col_num = matrix[0].length; + + int begin = 0; + int end = row_num * col_num - 1; + + while(begin <= end){ + int mid = (begin + end) / 2; + int mid_value = matrix[mid/col_num][mid%col_num]; + + if(mid_value == target){ + retunr true; + }else if(mid_value < target){ + begin = mid + 1; + }else{ + end = mid - 1; + } + + } + return false; + } +} \ No newline at end of file diff --git a/Week 03/id_691/691-Week 03/LeetCode_33_691.java b/Week 03/id_691/691-Week 03/LeetCode_33_691.java new file mode 100644 index 000000000..7893403a3 --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeetCode_33_691.java @@ -0,0 +1,30 @@ +class Solution { + public int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + while(start <= end){ + int mid = (start + end) / 2; + if (nums[mid] == target){ + return mid; + } + + if(nums[start] <= nums[mid]){ + if(target < nums[mid] && target >= nums[start]){ + end = mid - 1; + }else { + start = mid + 1; + } + } + + if(nums[mid] <= nums[end]){ + if (target > nums[mid] && target <= nums[end]){ + start = mid + 1; + }else{ + end = mid - 1; + } + } + + return -1; + } + } +} diff --git a/Week 03/id_691/691-Week 03/LeetCode_860_691.java b/Week 03/id_691/691-Week 03/LeetCode_860_691.java new file mode 100644 index 000000000..b5fcb9753 --- /dev/null +++ b/Week 03/id_691/691-Week 03/LeetCode_860_691.java @@ -0,0 +1,48 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + if (bills == null || bills.length < 1){ + return true; + } + + if(bills[0] != 5){ + return false; + } + + int money[0] = new int[3]; //5 10 15 + money[0]++; + + for(int i = 1; i < bills.length; i++){ + switch (bills[i]){ + case 5: + money[0]++; + break; + + case 10: + money[1]++; + money[0]--; + + if(money[0] < 0){ + return false; + } + break; + + case 20: + money[2]++; + if(money[1] > 0){ + money[1]--; + }else{ + money[0] -= 2; + } + + money[0]--; + + if(money[0] < 0){ + return false; + } + + break; + } + return true; + } + } +} \ No newline at end of file diff --git a/Week 03/id_696/LeetCode_122_696.java b/Week 03/id_696/LeetCode_122_696.java new file mode 100644 index 000000000..80806c9c4 --- /dev/null +++ b/Week 03/id_696/LeetCode_122_696.java @@ -0,0 +1,15 @@ +package week03; + +public class LeetCode_122_696 { + + // 只求增加的利润总和 + public int maxProfit(int[] prices) { + int maxProfit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + maxProfit += prices[i] - prices[i - 1]; + } + } + return maxProfit; + } +} diff --git a/Week 03/id_696/LeetCode_455_696.java b/Week 03/id_696/LeetCode_455_696.java new file mode 100644 index 000000000..1a31a46cf --- /dev/null +++ b/Week 03/id_696/LeetCode_455_696.java @@ -0,0 +1,22 @@ +package week03; + +import java.util.Arrays; + +public class LeetCode_455_696 { + + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int result = 0; + for (int i = 0, j = 0; i < g.length && j < s.length;) { + if (g[i] <= s[j]) { + i++; + j++; + result++; + } else { + j++; + } + } + return result; + } +} diff --git a/Week 03/id_696/LeetCode_74_696.java b/Week 03/id_696/LeetCode_74_696.java new file mode 100644 index 000000000..b5b2621ac --- /dev/null +++ b/Week 03/id_696/LeetCode_74_696.java @@ -0,0 +1,29 @@ +package week03; + +public class LeetCode_74_696 { + + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0) { + throw new IllegalArgumentException(); + } + int len = matrix[0].length; + + int left = 0, right = matrix.length * len - 1; + int pivotIdx; + int pivotElement; + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / len][pivotIdx % len]; + if (target == pivotElement) { + return true; + } else { + if (target < pivotElement) { + right = pivotIdx - 1; + } else { + left = pivotIdx + 1; + } + } + } + return false; + } +} diff --git a/Week 03/id_696/LeetCode_860_696.java b/Week 03/id_696/LeetCode_860_696.java new file mode 100644 index 000000000..8ec911efd --- /dev/null +++ b/Week 03/id_696/LeetCode_860_696.java @@ -0,0 +1,30 @@ +package week03; + +public class LeetCode_860_696 { + + public boolean lemonadeChange(int[] bills) { + int five = 0; + int 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; + } +} diff --git a/Week 03/id_701/LeetCode_033_701.cs b/Week 03/id_701/LeetCode_033_701.cs new file mode 100644 index 000000000..6121eaf8e --- /dev/null +++ b/Week 03/id_701/LeetCode_033_701.cs @@ -0,0 +1,41 @@ +public class Solution +{ + public int Search(int[] nums, int target) + { + int index = -1; + int left = 0; + int right = nums.Length - 1; + while (left <= right) + { + int mid = left + ((right - left) / 2); + if (nums[mid] == target) + { + index = mid; + break; + } + if (nums[left] <= nums[mid]) + { + if (target >= nums[left] && target <= nums[mid]) + { + right = mid - 1; + } + else + { + left = mid + 1; + } + } + else + { + if (target > nums[mid] && target <= nums[right]) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + } + return index; + } +} \ No newline at end of file diff --git a/Week 03/id_701/LeetCode_033_701.py b/Week 03/id_701/LeetCode_033_701.py new file mode 100644 index 000000000..d26310fed --- /dev/null +++ b/Week 03/id_701/LeetCode_033_701.py @@ -0,0 +1,21 @@ +class Solution: + def search(self, nums: List[int], target: int) -> int: + index = -1 + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + (right - left) // 2 + if nums[mid] == target: + index = mid + break + elif nums[left] > target: + if nums[left] < nums[right]: + right = mid - 1 + else: + left = mid+1 + else: + if nums[left] < nums[right]: + left = mid+1 + else: + right = mid-1 + + return index diff --git a/Week 03/id_701/LeetCode_102_701.cs b/Week 03/id_701/LeetCode_102_701.cs new file mode 100644 index 000000000..518dd2ffd --- /dev/null +++ b/Week 03/id_701/LeetCode_102_701.cs @@ -0,0 +1,34 @@ +/** + * Definition for a binary tree node. */ + public class TreeNode { + public int val; + public TreeNode left; + public TreeNode right; + public TreeNode(int x) { val = x; } + } + +public class Solution { + public IList> LevelOrder(TreeNode root) { + var levels = new List>(); + if(root == null){ + return levels; + } + + void Helper(TreeNode node, int level){ + if(levels.Count == level){ + levels.Add(new List()); + } + levels[level].Add(node.val); + + if(node.left != null){ + Helper(node.left, level + 1); + } + if(node.right != null){ + Helper(node.right, level + 1); + } + } + + Helper(root, 0); + return levels; + } +} \ No newline at end of file diff --git a/Week 03/id_701/LeetCode_102_701.py b/Week 03/id_701/LeetCode_102_701.py new file mode 100644 index 000000000..8cfadda7e --- /dev/null +++ b/Week 03/id_701/LeetCode_102_701.py @@ -0,0 +1,27 @@ +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def levelOrder(self, root: TreeNode) -> list: + levels = [] + if not root: + return levels + + def helper(node: TreeNode, level: int): + if level(levels) == level: + levels.append([]) + + levels[level].append(node.val) + + if root.left: + helper(root.left, level + 1) + if root.right: + helper(root.right, level+1) + + helper(root, 0) + return levels diff --git a/Week 03/id_701/LeetCode_153_701.py b/Week 03/id_701/LeetCode_153_701.py new file mode 100644 index 000000000..839f778e5 --- /dev/null +++ b/Week 03/id_701/LeetCode_153_701.py @@ -0,0 +1,13 @@ +class Solution: + def findMin(self, nums: List[int]) -> int: + low, high = 0, len(nums) - 1 + while low <= high: + mid = low + (high - low) // 2 + if high - low <= 1: + return min(nums[high], nums[low]) + if nums[mid] < nums[mid - 1] and nums[mid] < nums[mid+1]: + return nums[mid] + if nums[mid] > nums[high]: + low = mid+1 + else: + high = mid-1 diff --git a/Week 03/id_701/LeetCode_200_701.cs b/Week 03/id_701/LeetCode_200_701.cs new file mode 100644 index 000000000..cda4a8f35 --- /dev/null +++ b/Week 03/id_701/LeetCode_200_701.cs @@ -0,0 +1,36 @@ +public class Solution +{ + public int NumIslands(char[][] grid) + { + int count = 0; + if (grid != null) + { + for (int i = 0; i < grid.Length; i++) + { + for (int j = 0; j < grid[i].Length; j++) + { + if (grid[i][j] == '1') + { + DFS(grid, i, j); + count += 1; + } + } + } + } + return count; + } + + private void DFS(char[][] grid, int x, int y) + { + if (x < 0 || x > grid.Length - 1 || y < 0 || y > grid[0].Length - 1 || grid[x][y] != '1') + { + return; + } + grid[x][y] = '#'; + + DFS(grid, x + 1, y); + DFS(grid, x - 1, y); + DFS(grid, x, y + 1); + DFS(grid, x, y - 1); + } +} \ No newline at end of file diff --git a/Week 03/id_701/LeetCode_200_701.py b/Week 03/id_701/LeetCode_200_701.py new file mode 100644 index 000000000..f1f1ce4b3 --- /dev/null +++ b/Week 03/id_701/LeetCode_200_701.py @@ -0,0 +1,20 @@ +class Solution: + def numIslands(self, grid: list) -> int: + def dfs(grid: list, i: int, j: int): + if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] != '1': + return + grid[i][j] = '#' + + dfs(grid, i-1, j) + dfs(grid, i+1, j) + dfs(grid, i, j-1) + dfs(grid, i, j+1) + + count = 0 + if grid: + for i in range(len(grid)): + for j in range(len(grid[i])): + if grid[i][j] == '1': + dfs(grid, i, j) + count += 1 + return count diff --git a/Week 03/id_701/NOTE.md b/Week 03/id_701/NOTE.md index a6321d6e2..000b99740 100644 --- a/Week 03/id_701/NOTE.md +++ b/Week 03/id_701/NOTE.md @@ -1,4 +1,104 @@ -# NOTE +# 【701-week3】第三周学习总结 - +## 深度优先搜索和广度优先搜索 +这两种搜索方式的时间复杂都都是 O(n),每个节点都要且仅仅访问一次,区别在于节点的访问顺序不一样。 + +树的遍历示例代码模板 + +```python +def dfs(node): + if node in visited: + return + + visited.add(node) + + if node.left: + dfs(node.left) + if node.right: + dfs(node.right) +``` + +DFS 代码示例模板: + +```python +# 递归方式 +visited = set() +def dfs(node, visited): + if node in visited: + return + + visited.add(node) + + for next_node in node.children(): + if not next_node in visited: + dfs(next_node, visited) + +# 非递归方式 +def dfs(self,tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + stack.push(nodes) +``` + +BFS 代码示例模板: + +```python +def bfs(graph, start, end): + queue = [] + queue.appned([start]) + visited.add(statrt) + + while queue: + node = queue.pop() + visited.add(node) + + # process(node) + + nodes = generate_related_nodes(node) + queue.push(nodes) +``` + +### 贪心算法 + +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 + +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +贪心法可以解决一些最优化问题,如:求图中的最小生成树、求哈夫曼编码等。然而对于工程和生活中的问题,贪心法一般不能得到我们所要求的答案。 + +一旦一个问题可以通过贪心法来解决,那么贪心法一般是解决这个问题的最好办法。由于贪心法的高效性以及其所求得的答案比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +适用场景:简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终 问题的最优解。这种子问题最优解称为最优子结构。 + + +### 二分查找 + +使用条件: + +- 目标函数单调性(单调递增或递减) +- 存在上下界 +- 能够通过索引访问 + +代码模板: + +```python +def binnary_search(array, target): + left, right = 0, len(array) - 1 + while left <= right: + mid = left + (right-left) // 2 + if array[mid] == target: + return array[mid] + elif array[mid] > target: + right = mid - 1 + else: + left = mid + 1 +``` diff --git a/Week 03/id_711/Leetcode_122_711.java b/Week 03/id_711/Leetcode_122_711.java new file mode 100644 index 000000000..07f69827f --- /dev/null +++ b/Week 03/id_711/Leetcode_122_711.java @@ -0,0 +1,39 @@ +package Week3; + +public class Leetcode_122_711 { + public static void main(String[] args) { + int[] prices = {7,1,5,3,6,4}; + System.out.println(maxProfit(prices)); + } + + /** + * 思路: + * 当第二日的价格大于第一天价格买入,第二天小于第一天价格时卖出 + * 执行用时 :1 ms, 在所有 java 提交中击败了99.99%的用户 + * 内存消耗 :37.6 MB, 在所有 java 提交中击败了53.47%的用户 + * @param prices + * @return + */ + private static int maxProfit(int[] prices) { + int maxProfit = 0; + int buy = 0; + boolean flag = false; + for (int i = 0; i < prices.length - 1; i++) { + if (prices[i] < prices[i + 1]) { + if (!flag) { + buy = prices[i]; + flag = true; + } + } + else if (flag) { + maxProfit += prices[i] - buy; + flag = false; + } + } + if (flag) { + maxProfit += prices[prices.length - 1] - buy; + } + return maxProfit; + + } +} diff --git a/Week 03/id_711/Leetcode_127_711.java b/Week 03/id_711/Leetcode_127_711.java new file mode 100644 index 000000000..a865cea8c --- /dev/null +++ b/Week 03/id_711/Leetcode_127_711.java @@ -0,0 +1,176 @@ +package Week3; + +import javafx.util.Pair; + +import java.util.*; + +public class Leetcode_127_711 { + + Map map = new HashMap<>(); + + public static void main(String[] args) { + Leetcode_127_711 ss = new Leetcode_127_711(); + + String beginWord = "hit"; + String endWord = "cog"; + String[] wordLists = {"hot","dot","dog","lot","log","cog"}; + List wordList = new ArrayList<>(); + for (String str:wordLists) { + wordList.add(str); + } + System.out.println(ss.ladderLength1(beginWord,endWord,wordList)); + + } + + /** + * 沙雕最慢算法 + * 执行用时 :1066 ms, 在所有 java 提交中击败了5.74%的用户 + * 内存消耗 :41.8 MB, 在所有 java 提交中击败了60.94%的用户 + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + private int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) + return 0; + map.put(beginWord,1); + Queue queue = new ArrayDeque<>(); + queue.add(beginWord); + while (!queue.isEmpty()) { + Queue help = new ArrayDeque<>(); + while (!queue.isEmpty()) { + String str = queue.remove(); + + // 这一步很费时间 + for (String s : wordList) { + if (map.containsKey(s)) + continue; + if (check(str, s)) { + help.add(s); + map.put(s,map.get(str) + 1); + } + } + } + queue = help; + } + if (map.containsKey(endWord)) + return map.get(endWord); + return 0; + } + + private boolean check(String str, String s) { + char[] ch = str.toCharArray(); + char[] ch2 = s.toCharArray(); + int count = 0; + for (int i = 0; i < str.length(); i++) { + if (ch[i] != ch2[i]) { + count++; + if (count > 1) + return false; + } + } + return true; + } + + /** + * 题解双向BFS做法 + * 写的啥啊。。。。。。。 + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + + private int L; + private HashMap> allComboDict; + + Leetcode_127_711() { + this.L = 0; + this.allComboDict = new HashMap<>(); + } + + private int ladderLength1(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + this.L = beginWord.length(); + wordList.forEach( + word -> { + for (int i = 0; i < L; i++) { + // Key is the generic word + // Value is a list of words which have the same intermediate generic word. + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + ArrayList transformations = + this.allComboDict.getOrDefault(newWord, new ArrayList()); + transformations.add(word); + this.allComboDict.put(newWord, transformations); + } + }); + + // Queues for birdirectional BFS + // BFS starting from beginWord + Queue> Q_begin = new LinkedList>(); + // BFS starting from endWord + Queue> Q_end = new LinkedList>(); + Q_begin.add(new Pair(beginWord, 1)); + Q_end.add(new Pair(endWord, 1)); + + // Visited to make sure we don't repeat processing same word. + HashMap visitedBegin = new HashMap(); + HashMap visitedEnd = new HashMap(); + visitedBegin.put(beginWord, 1); + visitedEnd.put(endWord, 1); + + while (!Q_begin.isEmpty() && !Q_end.isEmpty()) { + + // One hop from begin word + int ans = visitWordNode(Q_begin, visitedBegin, visitedEnd); + if (ans > -1) { + return ans; + } + + // One hop from end word + ans = visitWordNode(Q_end, visitedEnd, visitedBegin); + if (ans > -1) { + return ans; + } + } + + return 0; + } + + private int visitWordNode( + Queue> Q, + HashMap visited, + HashMap othersVisited) { + + Pair node = Q.remove(); + String word = node.getKey(); + int level = node.getValue(); + + for (int i = 0; i < this.L; i++) { + + // Intermediate words for current word + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + + // Next states are all the words which share the same intermediate state. + for (String adjacentWord : this.allComboDict.getOrDefault(newWord, new ArrayList())) { + // If at any point if we find what we are looking for + // i.e. the end word - we can return with the answer. + if (othersVisited.containsKey(adjacentWord)) { + return level + othersVisited.get(adjacentWord); + } + + if (!visited.containsKey(adjacentWord)) { + + // Save the level as the value of the dictionary, to save number of hops. + visited.put(adjacentWord, level + 1); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + return -1; + } + +} diff --git a/Week 03/id_711/Leetcode_200_711.java b/Week 03/id_711/Leetcode_200_711.java new file mode 100644 index 000000000..3fdbd02fe --- /dev/null +++ b/Week 03/id_711/Leetcode_200_711.java @@ -0,0 +1,51 @@ +package Week3; + +public class Leetcode_200_711 { + + char[][] g; + int[] a = {0,0,1,-1}; + int[] b = {1,-1,0,0}; + + public static void main(String[] args) { + + char[][] grid = { + {'1','1','1','1','0'}, + {'1','1','0','1','0'}, + {'1','1','0','0','0'}, + {'0','0','0','0','0'} + }; + Leetcode_200_711 ss = new Leetcode_200_711(); + System.out.println(ss.numIslands(grid)); + } + + /** + * 归零算法 + * 执行用时 :4 ms, 在所有 java 提交中击败了55.79%的用户 + * 内存消耗 :41.2 MB, 在所有 java 提交中击败了83.54%的用户 + * @param grid + * @return + */ + private int numIslands(char[][] grid) { + g = grid; + int count = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (g[i][j] == '1') { + count++; + zero(i,j); + } + } + } + return count; + } + + private void zero(int i, int j) { + g[i][j] = 0; + for (int k = 0; k < 4; k++) { + int x = i + a[k]; + int y = j + b[k]; + if (x >= 0 && x < g.length && y >= 0 && y < g[0].length && g[x][y] == '1') + zero(x, y); + } + } +} diff --git a/Week 03/id_711/Leetcode_455_711.java b/Week 03/id_711/Leetcode_455_711.java new file mode 100644 index 000000000..44b456010 --- /dev/null +++ b/Week 03/id_711/Leetcode_455_711.java @@ -0,0 +1,37 @@ +package Week3; + +import java.util.Arrays; + +public class Leetcode_455_711 { + public static void main(String[] args) { + int[] g = {1,1,3}; + int[] s = {1,1}; + System.out.println(findContentChildren(g,s)); + } + + /** + * + * 执行用时 :10 ms, 在所有 java 提交中击败了99.34%的用户 + * 内存消耗 :39.2 MB, 在所有 java 提交中击败了96.14%的用户 + * @param g + * @param s + * @return + */ + private static int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int x = 0, y = 0; + int ans = 0; + while (x < g.length && y < s.length) { + if (s[y] >= g[x]) { + ans++; + x++; + y++; + } + else { + y++; + } + } + return ans; + } +} diff --git a/Week 03/id_711/Leetcode_860_711.java b/Week 03/id_711/Leetcode_860_711.java new file mode 100644 index 000000000..2f3ad0523 --- /dev/null +++ b/Week 03/id_711/Leetcode_860_711.java @@ -0,0 +1,58 @@ +package Week3; + +public class Leetcode_860_711 { + public static void main(String[] args) { + int[] bills = {5,5,10,10,20}; + System.out.println(lemonadeChange1(bills)); + } + + /** + * 国际站简洁写法 + * @param bills + * @return + */ + private static boolean lemonadeChange1(int[] bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) {five--; ten++;} + else if (ten > 0) {ten--; five--;} + else five -= 3; + if (five < 0) return false; + } + return true; + } + + /** + * 简单贪心 + * 执行用时 :2 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :39.3 MB, 在所有 java 提交中击败了93.65%的用户 + * @param bills + * @return + */ + private static boolean lemonadeChange(int[] bills) { + int fiveNumber = 0, tenNumber = 0; + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + fiveNumber++; + } + else if (bills[i] == 10) { + if (fiveNumber < 1) + return false; + tenNumber++; + fiveNumber--; + } + else { + if (tenNumber > 0 && fiveNumber > 0) { + tenNumber--; + fiveNumber--; + } + else if (fiveNumber > 2) { + fiveNumber -= 3; + } + else return false; + } + } + return true; + } +} diff --git "a/Week 03/id_711/Week3\346\200\273\347\273\223.docx" "b/Week 03/id_711/Week3\346\200\273\347\273\223.docx" new file mode 100644 index 000000000..75e67be94 Binary files /dev/null and "b/Week 03/id_711/Week3\346\200\273\347\273\223.docx" differ diff --git a/Week 03/id_716/LeetCode_102_716.java b/Week 03/id_716/LeetCode_102_716.java new file mode 100644 index 000000000..2483b0684 --- /dev/null +++ b/Week 03/id_716/LeetCode_102_716.java @@ -0,0 +1,72 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +// https://leetcode-cn.com/problems/binary-tree-level-order-traversal +// 二叉树的层次遍历 + +public class LeetCode_102_716 { + // 1. 使用loop + 队列, BFS 算法实现 + public List> levelOrder1(TreeNode root) { + // 存储结果 + List> res = new ArrayList<>(); + if (root == null) return res; + + // 用队列来暂存依次要访问的每层节点 + Queue queue = new LinkedList<>(); + queue.offer(root); + // 跟踪正在遍历的是第几层的节点 + int level = 0; + while (!queue.isEmpty()) { + // 初始化当前层的容器 + res.add(new ArrayList<>()); + + // 获取队列的大小,表示要遍历的当前层的节点个数 + int nodeCntInCurrLevel = queue.size(); + for (int i = 0; i < nodeCntInCurrLevel; ++i) { + TreeNode curr = queue.poll(); + res.get(level).add(curr.val); + + if (curr.left != null) queue.offer(curr.left); + if (curr.right != null) queue.offer(curr.right); + } + + // 当前层遍历完了之后,层数+1 + level++; + } + + return res; + } + + // 2. 使用递归,DFS 算法实现 + public List> levelOrder2(TreeNode root) { + List> res = new ArrayList<>(); + levelOrderHelper(root, 0, res); + return res; + } + + // 可以使用递归解决,需要跟踪level + // 重复性是:每次都是遍历当前节点,记录值(只需要跟踪层次即可),然后是左子树,然后是右子树 + private void levelOrderHelper(TreeNode node, int level, List> res) { + // terminator + if (node == null) return; + + // process current logic + if (res.size() < level + 1) { + res.add(new ArrayList<>()); + } + res.get(level).add(node.val); + + // drill down + levelOrderHelper(node.left, level + 1, res); + levelOrderHelper(node.right, level + 1, res); + } +} + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int val) { this.val = val; } +} diff --git a/Week 03/id_716/LeetCode_107_716.java b/Week 03/id_716/LeetCode_107_716.java new file mode 100644 index 000000000..5ced7909d --- /dev/null +++ b/Week 03/id_716/LeetCode_107_716.java @@ -0,0 +1,63 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +// https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii +// 二叉树的层次遍历 II +// https://leetcode.com/problems/binary-tree-level-order-traversal/discuss/114449/A-general-approach-to-level-order-traversal-questions-in-Java + +public class LeetCode_107_716 { + // 1. 递归解法 + // 此题和 102 类似 + public List> levelOrderBottom1(TreeNode root) { + List> res = new LinkedList<>(); + levelOrderBottomHelper(root, 0, res); + return res; + } + + private void levelOrderBottomHelper(TreeNode node, int level, List> res) { + // terminator + if (node == null) return; + + // process current logic + if (res.size() < level + 1) { + res.add(0, new ArrayList<>()); + } + res.get(res.size() - level - 1).add(node.val); + + // drill down + levelOrderBottomHelper(node.left, level + 1, res); + levelOrderBottomHelper(node.right, level + 1, res); + } + + // 2. 迭代 + 队列 + public List> levelOrderBottom2(TreeNode root) { + List> res = new LinkedList<>(); + if (root == null) return res; + + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + res.add(0, new ArrayList<>()); + + int levelNodeSize = queue.size(); + for (int i = 0; i < levelNodeSize; i++) { + TreeNode curr = queue.poll(); + res.get(0).add(curr.val); + + if (curr.left != null) queue.offer(curr.left); + if (curr.right != null) queue.offer(curr.right); + } + } + + return res; + } +} + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int val) { this.val = val; } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_122_716.java b/Week 03/id_716/LeetCode_122_716.java new file mode 100644 index 000000000..a96b2aa28 --- /dev/null +++ b/Week 03/id_716/LeetCode_122_716.java @@ -0,0 +1,19 @@ + +// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii +// 买卖股票的最佳时机 II + +public class LeetCode_122_716 { + // 1. 暴力法,太复杂了,先直接放弃 + + // 2. 贪心法求解 + // 核心思想是:贪心的地方在于每次去寻找能够增加利润的值,前后两个价格做比较,只要产生收益就累加到 + // 最后的收益中,不能增加收益的就忽略掉 + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.length; i++) { + int diff = prices[i] - prices[i - 1]; + if (diff > 0) profit += diff; + } + return profit; + } +} diff --git a/Week 03/id_716/LeetCode_126_716.java b/Week 03/id_716/LeetCode_126_716.java new file mode 100644 index 000000000..c8ef82ecd --- /dev/null +++ b/Week 03/id_716/LeetCode_126_716.java @@ -0,0 +1,78 @@ +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +// https://leetcode-cn.com/problems/word-ladder-ii +// 单词接龙II + +public class LeetCode_126_716 { + // 1. bfs + public List> findLadders1(String beginWord, String endWord, List wordList) { + List> res = new ArrayList<>(); + if (!wordList.contains(endWord)) return res; + + bfs(beginWord, endWord, wordList, res); + return res; + } + + private void bfs(String beginWord, String endWord, List wordList, List> res) { + Queue> queue = new LinkedList<>(); + queue.offer(new ArrayList(){{ + add(beginWord); + }}); + + Set visited = new HashSet<>(); + Set wordSet = new HashSet<>(wordList); + boolean isFound = false; + + while (!queue.isEmpty()) { + int size = queue.size(); + Set subVisited = new HashSet<>(); + for (int i = 0; i < size; i++) { + List curr = queue.poll(); + String last = curr.get(curr.size() - 1); + // find neighbors + List neighbors = getNeighbors(last, wordSet); + + // iter neighbors + for (String neighbor : neighbors) { + if (!visited.contains(neighbor)) { + if (neighbor.equals(endWord)) { + isFound = true; + curr.add(neighbor); + res.add(new ArrayList<>(curr)); + curr.remove(curr.size() - 1); + } + curr.add(neighbor); + queue.offer(new ArrayList<>(curr)); + curr.remove(curr.size() - 1); + subVisited.add(neighbor); + } + } + + } + visited.addAll(subVisited); + if (isFound) break; + } + } + + private List getNeighbors(String word, Set wordSet) { + List neighbor = new ArrayList<>(); + char[] wordChars = word.toCharArray(); + for (char ch = 'a'; ch <= 'z'; ch++) { + for (int i = 0; i < wordChars.length; i++) { + if (wordChars[i] == ch) continue; + char old = wordChars[i]; + wordChars[i] = ch; + if (wordSet.contains(String.valueOf(wordChars) { + neighbor.add(String.valueOf(wordChars)); + } + wordChars[i] = old; + } + } + return neighbor; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_127_716.java b/Week 03/id_716/LeetCode_127_716.java new file mode 100644 index 000000000..bffe43aac --- /dev/null +++ b/Week 03/id_716/LeetCode_127_716.java @@ -0,0 +1,187 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +// https://leetcode-cn.com/problems/word-ladder +// 单词接龙 + +public class LeetCode_127_716 { + + // 1. bfs + // 核心点: + // a. 首先将wordList转成图的邻接表存储,将单词和单词的通用状态构成一个无向图; 通用态:hot 的通用态有 h*t, ho*, *ot, 以此类推 + // b. 在图中根据 bfs 查找 endWord,命中 endWord 所在的层次就是转换的长度;否则就无法到达 + // b1. 如果单词列表转换过来的图都是连通的,说明必然存在一个节点是endWord + // b2. 如果单词列表转换过来的图存在不连通的,比如有多个子图,说明有可能两个节点之间是不可达的,因为分别在两个子图中 + public int ladderLength1(String beginWord, String endWord, List wordList) { + // 将单词接龙问题转换成对图的bfs问题,这个是关键 + // 使用图的邻接表表示法存储 + Map> graph = new HashMap<>(); + + // 将单词列表转换成图表示 & endWord 不在单词列表中的话,直接over + if (!toGraph(wordList, endWord, graph)) return 0; + + // bfs 找最小转换长度 + return bfs(graph, beginWord, endWord); + } + + // bfs 的实现 + private int bfs(Map> graph, String beginWord, String endWord) { + // 记录已经访问过的 vertex + Set visited = new HashSet<>(); + visited.add(beginWord); + + // 待访问的 vertex 队列 + Queue queue = new LinkedList<>(); + queue.offer(new Pair(beginWord, 1)); + + while (!queue.isEmpty()) { + Pair curr = queue.poll(); + + // 遍历所有可能的状态 + for (int i = 0; i < beginWord.length(); i++) { + String keyToFind = toKey(curr.word, i); + + // 遍历邻接节点 + for (String adjWord : graph.getOrDefault(keyToFind, new ArrayList<>())) { + // 找到就直接返回 + if (adjWord.equals(endWord)) return curr.level + 1; + + // 不是要找的,就加入已访问集合 & 加入到待访问队列 + if (!visited.contains(adjWord)) { + visited.add(adjWord); + queue.offer(new Pair(adjWord, curr.level + 1)); + } + } + } + } + + return 0; + } + + // 单词列表转换成图 + private boolean toGraph(List wordList, String endWord, Map> graph) { + boolean containsEndWord = false; + int wordLength = endWord.length(); + + // 时间复杂度 O(m*n), n是字典长度,m是单词的长度 + for (String word : wordList) { + if (word.equals(endWord)) containsEndWord = true; + + for (int i = 0; i < wordLength; i++) { + String key = toKey(word, i); + List vertexList = graph.getOrDefault(key, new LinkedList<>()); + vertexList.add(word); + graph.put(key, vertexList); + } + } + + return containsEndWord; + } + + private String toKey(String word, int pos) { + char[] chars = word.toCharArray(); + chars[pos] = '*'; + return new String(chars); + } + + class Pair { + String word; + int level; + public Pair(String word, int level) { + this.word = word; + this.level = level; + } + } + + // ---------------------------- 分割线 ---------------------------- + + // 2. 双向 bfs + // 为啥能想到双向 bfs,就先记住吧 + + // 关于双向 bfs: + // a. 适用于目标节点已知的情况; 初始结点向目标结点和目标结点向初始结点同时扩展,直至在两个扩展方向上出现同一个结点,搜索结束。 + // b. 为了避免无谓的“组合爆炸”产生,就可以采取双向广度搜索算法,也就是从开始状态和结束状态同时开始搜索,一个向前搜,一个向后找。 + // c. 好处:我们不妨假设每次搜索的分支因子是 r,如果最短的路径长为 L 的话(也就是搜了 L 层),那么,用一般的 BFS 算法(不考虑去掉重复状态), + // 总的搜索状态数是 r^L(^表示乘方运算); 而如果采取双向 BFS 算法,那么,从前往后搜,我们只需要搜索 L/2 层, + // 从后往前搜,我们也只要搜 L/2 层,因此,搜索状态数是 2*(r^(L/2)),比普通 BFS 就快了很多了 + // 和方法 1 的分析没有区别,只有在 bfs 算法那里使用了 双向bfs + public int ladderLength2(String beginWord, String endWord, List wordList) { + // 将单词接龙问题转换成对图的bfs问题,这个是关键 + // 使用图的邻接表表示法存储 + Map> graph = new HashMap<>(); + + // 将单词列表转换成图表示 & endWord 不在单词列表中的话,直接over + if (!toGraph(wordList, endWord, graph)) return 0; + + // 双向 bfs + return bbfs(graph, beginWord, endWord); + } + + // bidirectional bread first search + private int bbfs(Map> graph, String beginWord, String endWord) { + Map beginVisited = new HashMap<>(); + beginVisited.put(beginWord, 1); + + Map endVisited = new HashMap<>(); + endVisited.put(endWord, 1); + + Queue beginQueue = new LinkedList<>(); + beginQueue.offer(new Pair(beginWord, 1)); + + Queue endQueue = new LinkedList<>(); + endQueue.offer(new Pair(endWord, 1)); + + // 控制流,控制双向搜索 + while (!beginQueue.isEmpty() && !endQueue.isEmpty()) { + // from begin + int l = visitWord(graph, beginQueue, beginVisited, endVisited); + if (l > -1) { + return l; + } + + // then from end + l = visitWord(graph, endQueue, endVisited, beginVisited); + if (l > -1) { + return l; + } + } + + return 0; + } + + private int visitWord(Map> graph, Queue queue, Map visited, + Map oppVisited) { + Pair curr = queue.poll(); + + for (int i = 0; i < curr.word.length(); i++) { + String keyToFind = toKey(curr.word, i); + + // 遍历邻接节点 + for (String adjWord : graph.getOrDefault(keyToFind, new ArrayList<>())) { + // 找到就直接返回 + if (oppVisited.containsKey(adjWord)) return curr.level + oppVisited.get(adjWord); + + // 不是要找的,就加入已访问集合 & 加入到待访问队列 + if (!visited.containsKey(adjWord)) { + visited.put(adjWord, curr.level + 1); + queue.offer(new Pair(adjWord, curr.level + 1)); + } + } + } + + return -1; + } + + // ---------- 上面的实现代码量较大 + // 3. 更加简化的实现,双向bfs + public int ladderLength3(String beginWord, String endWord, List wordList) { + + return 0; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_22_716.java b/Week 03/id_716/LeetCode_22_716.java new file mode 100644 index 000000000..c41edbe0a --- /dev/null +++ b/Week 03/id_716/LeetCode_22_716.java @@ -0,0 +1,64 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +// https://leetcode-cn.com/problems/generate-parentheses +// 括号生成 + +public class LeetCode_22_716 { + // 1. dfs 的思想 + public List generateParenthesis1(int n) { + List res = new ArrayList<>(); + dfs("", 0, 0, n, res); + return res; + } + + private void dfs(String s, int left, int right, int n, List res) { + // terminator + if (left == n && right == n) { + res.add(s); + return; + } + + // process current logic: add left or add right + // dirll down + if (left < n) dfs(s + "(", left + 1, right, n, res); + if (left > right) dfs(s + ")", left, right + 1, n, res); + } + + // 2. bfs 的思想 + public List generateParenthesis2(int n) { + List res = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(new Node("", 0, 0)); + + int level = 2 * n; + while (level > 0) { + int size = queue.size(); + while (size-- > 0) { + Node curr = queue.poll(); + if (curr.l < n) queue.offer(new Node(curr.s + "(", curr.l + 1, curr.r)); + if (curr.l > curr.r) queue.offer(new Node(curr.s + ")", curr.l, curr.r + 1)); + } + level--; + } + + while (!queue.isEmpty()) { + res.add(queue.poll().s); + } + + return res; + } + + class Node { + String s; + int l; // left + int r; // right + Node(String s, int left, int right) { + this.s = s; + l = left; + r = right; + } + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_33_716.java b/Week 03/id_716/LeetCode_33_716.java new file mode 100644 index 000000000..0eafe6194 --- /dev/null +++ b/Week 03/id_716/LeetCode_33_716.java @@ -0,0 +1,34 @@ + +// https://leetcode-cn.com/problems/search-in-rotated-sorted-array +// 搜索旋转排序数组 + +public class LeetCode_33_716 { + // 二分查找 + public int search(int[] nums, int target) { + int low = 0, high = nums.length - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (nums[mid] == target) return mid; + + // 这里是关键 + // nums[low] <= target && target < nums[mid] 表示 low mid 是有序的,且target在它们中间,需要将high向前移动 + // nums[low] > nums[mid] && target > nums[high] 表示: low ~ mid 是无序的,而且 target 比 high 位置的元素还要大, + // 因为 mid ~ high 是有序的,所以必然在 low ~ mid 中间,移动high + // nums[low] > nums[mid] && target < nums[mid] 表示 low ~ mid 是无序的, 而且 target 比mid位置处的值还要小, + // 因为 mid ~ high 是有序的,所以必然在 low ~ mid 中间,移动high + // 否则,就是移动low + if ((nums[low] <= target && target < nums[mid]) + || (nums[low] > nums[mid] && target > nums[high]) + || (nums[low] > nums[mid] && target < nums[mid])) { + high = mid - 1; + } else { + low = mid + 1; + } + } + + return low == high && nums[low] == target ? low : -1; + } + + // 还有另外一种思路:先找到无序的位置,然后再使用正常的二分查找找到索引位置,这种方式暂时不实现 +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_367_716.java b/Week 03/id_716/LeetCode_367_716.java new file mode 100644 index 000000000..04f2e77bd --- /dev/null +++ b/Week 03/id_716/LeetCode_367_716.java @@ -0,0 +1,55 @@ + +// https://leetcode-cn.com/problems/valid-perfect-square +// 有效的完全平方数 + +public class LeetCode_367_716 { + // 1. 暴力求解 + public boolean isPerfectSquare1(int num) { + for (int i = 1; i <= (num + 1)/2; i++) { + if (i == num/i && i * i == num) { + return true; + } + } + return false; + } + + // 2. 二分搜索 + public boolean isPerfectSquare2(int num) { + int l = 1, r = (num >> 1) + 1; + while (l <= r) { + int m = l + (r - l) / 2; + + // 可以最大程度的防止溢出 + if (m == num/m && m * m == num) return true; + + if (m > num/m) { + r = m - 1; + } else { + l = m + 1; + } + } + + return false; + } + // 同样,这个题目可以利用 69 题,在最后判断 r*r == num ? + + // 3. 等差数列 + public boolean isPerfectSquare3(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } + + // 4. 牛顿法 + public boolean isPerfectSquare4(int num) { + long r = num; + while (r > num/r) { + r = (r + num/r) / 2; + } + int rs = (int) r; + return rs * rs == num; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_402_716.java b/Week 03/id_716/LeetCode_402_716.java new file mode 100644 index 000000000..16bfaeda2 --- /dev/null +++ b/Week 03/id_716/LeetCode_402_716.java @@ -0,0 +1,27 @@ +// https://leetcode-cn.com/problems/remove-k-digits +// 移掉K位数字 + +public class LeetCode_402_716 { + public String removeKdigits(String num, int k) { + if (k >= num.length()) return "0"; + + char[] stack = new char[num.length()]; + int sPos = 0; + + for (char curr : num.toCharArray()) { + // 移动到新的字符上时,都去找当前的最大值,移除掉 + while (k > 0 && sPos > 0 && stack[sPos] > curr) { + sPos--; + k--; + } + + // 如果第一个位置是0的话,直接丢弃 + if (sPos != 0 || curr != '0') { + stack[sPos++] = curr; + } + } + + String res = new String(stack, 0, sPos - k); + return res.isEmpty() ? "0" : res; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_433_716.java b/Week 03/id_716/LeetCode_433_716.java new file mode 100644 index 000000000..533d16b7f --- /dev/null +++ b/Week 03/id_716/LeetCode_433_716.java @@ -0,0 +1,49 @@ +import java.util.LinkedList; +import java.util.Queue; + +// https://leetcode-cn.com/problems/minimum-genetic-mutation +// 最小基因变化 + +public class LeetCode_433_716 { + // 1. 0ms (100%), 33.8M (68.18%) + public int minMutation(String start, String end, String[] bank) { + if (start.equals(end)) return 0; + + // bfs + int level = 0; + Queue queue = new LinkedList<>(); + queue.offer(start); + boolean[] visited = new boolean[bank.length]; + + while (!queue.isEmpty()) { + int currSize = queue.size(); + while (currSize-- > 0) { + String curr = queue.poll(); + if (curr.equals(end)) return level; + + for (int i = 0; i < bank.length; i++) { + if (!visited[i] && isValid(curr, bank[i])) { + visited[i] = true; + queue.offer(bank[i]); + } + } + } + level++; + } + + return -1; + } + + private boolean isValid(String seq1, String seq2) { + int diffCnt = 0; + for (int i = 0; i < seq1.length(); i++) { + if (seq1.charAt(i) != seq2.charAt(i)) { + diffCnt++; + if (diffCnt > 1) { + return false; + } + } + } + return diffCnt == 1; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_515_716.java b/Week 03/id_716/LeetCode_515_716.java new file mode 100644 index 000000000..eecf4bb4b --- /dev/null +++ b/Week 03/id_716/LeetCode_515_716.java @@ -0,0 +1,62 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +// https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row +// 在每个树行中找最大值 + +public class LeetCode_515_716 { + // 1. bfs + public List largestValues1(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) return res; + + Queue queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + int size = queue.size(); + int max = Integer.MIN_VALUE; + while (size-- > 0) { + TreeNode curr = queue.poll(); + if (curr.val > max) max = curr.val; + + if (curr.left != null) queue.offer(curr.left); + if (curr.right != null) queue.offer(curr.right); + } + res.add(max); + } + return res; + } + + // 2. dfs + public List largestValues2(TreeNode root) { + List res = new ArrayList<>(); + dfs(root, 0, res); + return res; + } + + private void dfs(TreeNode node, int level, List res) { + if (node == null) return; + + if (res.size() < level + 1) { + res.add(Integer.MIN_VALUE); + } + if (node.val > res.get(level)) res.set(level, node.val); + + dfs(node.left, level + 1, res); + dfs(node.right, level + 1, res); + } +} + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_55_716.go b/Week 03/id_716/LeetCode_55_716.go new file mode 100644 index 000000000..0a7a25178 --- /dev/null +++ b/Week 03/id_716/LeetCode_55_716.go @@ -0,0 +1,15 @@ +package id_716 + +// https://leetcode-cn.com/problems/jump-game/ +// 跳跃游戏 + +// 贪心算法 +// 要点:从最后1个位置往前找,如果前面的位置能够到达指定的后面的位置,说明是可达的,然后就更新要判断的位置,一直到结束 +// 如果最后没有办法回到起始位置,说明不能到达最后一个位置 +func canJump(nums []int) bool { + pos := len(nums) - 1 + for i := pos; i >= 0; i-- { + if i + nums[i] >= pos { pos = i } + } + return pos == 0 +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_69_716.java b/Week 03/id_716/LeetCode_69_716.java new file mode 100644 index 000000000..531947db4 --- /dev/null +++ b/Week 03/id_716/LeetCode_69_716.java @@ -0,0 +1,88 @@ + +public class LeetCode_69_716 { + + // 1. 二分搜索 + // 1.1 + public int mySqrt11(int x) { + if (x == 0) return 0; + int left = 1, right = Integer.MAX_VALUE; + while (true) { + int mid = left + ((right - left) >> 1); + if (mid > x/mid) { + right = mid - 1; + } else { + if (mid + 1 > x/(mid + 1)) + return mid; + left = mid + 1; + } + } + } + + // 1.2 + public int mySqrt12(int x) { + // 平方根一定在 1 ~ (x/2 + 1)之间 + if (x == 0) return 0; + + int left = 1, right = (x >> 1); + while (left < right) { + int mid = left + ((right - left) >> 1); + + int sqrt = x / mid; + if (mid == sqrt) { + return mid; + } else if (mid > sqrt) { + right = mid - 1; + } else { + if (mid + 1 > x / (mid + 1)) return mid; + left = mid + 1; + } + } + + return left; + } + + // 1.3 + public int mySqrt13(int x) { + int left = 1, right = x, res = 0; + while (left <= right) { + int mid = left + ((right - left) >> 1); + if (mid <= x / mid) { + left = mid + 1; + res = mid; + } else { + right = mid - 1; + } + } + + return res; + } + + // 1.4 + public int mySqrt14(int x) { + if (x == 0 || x == 1) return x; + + int left = 1, right = x >> 1; + while (left + 1 < right) { + int mid = left + ((right - left) >> 1); + if (mid <= x / mid) { + left = mid; + } else { + right = mid - 1; + } + } + + return right <= x / right ? right : left; + } + + // 2 牛顿法,这个写法确实有些巧妙,收敛速度更快 + // 可以这么理解:从 x 和 1 开始从两端向中间收敛,r 的起始值是 x,x/r 的起始值是 1,随着 r 的减小,x/r 在增大 + // 这两个值都在向 x 的平方根收敛,当到达平方根时 r == x/r, 可以推测,r 是从大到小单调递减的 + public int mySqrt2(int x) { + if (x == 0) return 0; + long r = x; + while (r > x / r) { + r = (r + x / r) >> 1; + } + return (int) r; + } +} \ No newline at end of file diff --git a/Week 03/id_716/LeetCode_860_716.java b/Week 03/id_716/LeetCode_860_716.java new file mode 100644 index 000000000..d05e35354 --- /dev/null +++ b/Week 03/id_716/LeetCode_860_716.java @@ -0,0 +1,20 @@ + +// https://leetcode-cn.com/problems/lemonade-change +// 柠檬水找零 + +public class LeetCode_860_716 { + + // 利用贪心算法实现 + public boolean lemonadeChange(int[] bills) { + int fiveCnt = 0, tenCnt = 0; + for (int bill : bills) { + if (bill == 5) fiveCnt++; + else if (bill == 10) { fiveCnt--; tenCnt++; } + else if (tenCnt > 0) { tenCnt--; fiveCnt--; } + else fiveCnt -= 3; + + if (fiveCnt < 0) return false; + } + return true; + } +} diff --git a/Week 03/id_716/NOTE.md b/Week 03/id_716/NOTE.md index a6321d6e2..6e6d75188 100644 --- a/Week 03/id_716/NOTE.md +++ b/Week 03/id_716/NOTE.md @@ -1,4 +1,317 @@ # NOTE - +## Week 03 关键部分笔记 +### 深度优先搜索和广度优先搜索 + +- 深度优先搜索:DFS,Deep First Search + +代码模版 + +```python +# 递归写法 +visited = set() +def dfs(node, visited): + # terminator + if node in visited: + return + + visited.add(node) + + # process current node here + # ... + + # drill down + for next_node in node.children(): + if next_node not in visited: + dfs(next_node, visited) + + +# 非递归写法 +def DFS(root): + if root is Node: + return [] + visited, stack = [], [root] + + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + stack.push(nodes) + +``` + +- 广度优先搜索:BFS,Bread First Search + +代码模版 + +```python +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + # ... +``` + +- 题目 + (done) + (done) + (done, bfs + dfs) + (done) + + (done) + (done) + (done) + (done) + +- Topic:全面掌握深度优先搜索和广度优先搜索 + +1. 图的存储 +2. 实现BFS和DFS;解决问题时 BFS 和 DFS 能否相互转换 +3. 实现 Dijkstra 算法、Bellford 算法、Floyd 算法、A*算法 +4. 实现拓扑排序 Kahn 算法、DFS 算法 + +实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法 +实现图的深度优先搜索、广度优先搜索 +实现 Dijkstra 算法、A* 算法 +实现拓扑排序的 Kahn 算法、DFS 算法 + +岛屿个数,有效数独,迷宫问题 + +### 贪心算法 + +- 题目 + + + (done) + (done) + (done) + + (done) + (done) + +### 二分查找 + +- 前提 + +1. 单调性(单调递增或递减) +2. 存在上下界 (bounded) +3. 能够通过索引访问 (index accessable) + +- 代码模版 + +- 题目 + + (done) + (done) + + (done) + + +使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 +说明:同学们可以将自己的思路、代码写在第 3 周的学习总结中 + +--- + +### 【716-Week 03】第一次全方位学习贪心算法 + +这是训练营的第3周,本周的内容较上周少一些,主要涉及BFS,DFS,贪心算法和二分查找;其中二分查找的思想有在上周的总结中有所提及,做了一些分析,但贪心算法早在读大学时就有了解,可惜从来没有全方位的去学习和理解他适用的问题场景、他的优点和他的局限,本周特别的对贪心算法做了些功课。 + +在求解最优化问题的时候,需要经过一系列的步骤,在每个步骤中都会面临多种选择;对于其中的某些问题,可以简单高效的解决,相比于动态规划,贪心算法就是这样一类算法,在每一步中都做出当前来看最优的选择:通过局部最优的选择,来得出全局最优(可见,这种方式不是对所有问题都是有效的,而我们只需要关注那些有效的问题即可)。 + +#### 贪心算法的基本要素 + +下面一段关于贪心算法的原理,出自《算法导论》贪心算法章节 +> 贪心算法的一般性质: +> +> 1. 将最优化问题转化成这样的形式:对其做出一次选择后,只剩下一个子问题需要求解 +> 2. 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的 +> 3. 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构 + +可见,使用贪心算法解决问题的核心是:1. 贪心选择后,剩下一个子问题而且局部最优解能够构造出全局最优解;2. 最优子结构,贪心选择后的子问题与贪心选择的最优解组合可以得到原问题的最优解;这么说是比较抽象 + +#### 分析活动选择问题 + +从分析一个简单贪心算法的例子开始,活动选择问题是一个比较典型的应用贪心算法的例子,问题描述如下: + +> 有 n 个活动,每个活动都有起始时间,这些活动使用同一个资源,这个资源在某个时刻只能提供一个活动使用。如果两个活动的起始时间不重复,则他们是兼容的。在这个活动集合中求出最大兼容活动集。 +> 例子: +> start[] = {1, 3, 0, 5, 8, 5}; +> finish[] = {2, 4, 6, 7, 9, 9}; +> 输出:{0, 1, 3, 4} (0 1 3 4 是下标) + +对于能应用贪心算法的问题,最大的难度是如何证明贪心选择是安全的,大部分情况下,我们都是凭借着归纳法、感觉和经验,实际上这是可以证明的。 + +我们利用贪心算法的一般性质来分析一下活动选择问题,首先我们需要选定贪心的立足点,也就是我们在什么角度上分解出当前选择和子问题,现在我们以最早结束时间为贪心的对象,因为直观上来讲,越早结束的活动,留给后面的活动选择子问题越多的时间,所以我们贪心的选择最早结束的活动,现在来看: + +1. 做出一次选择后,是否只剩下一个子问题?是的,比如我们选择活动a1后,且a1是最早结束的活动,那么接下来的问题就是在剩下的集合中再选择一个最早结束的活动;依次类推,每一步都是重复之前的动作:做出当前看来最优的选择(最早结束的活动),求剩下活动集合的子问题的解 +2. 针对这个问题,贪心选择是安全的吗?可以证明,针对活动选择问题,在做出贪心选择后,总是存在最优解 +3. 是否能得到最优子结构?最优子结构,和最近重复性是有一些相似的,最优子结构就是可重复的子问题,这样就可以将复杂的问题拆解成更小的子问题的解 + +那么,求解活动选择问题的步骤如下: + +1. 对所有的活动根据结束时间排序,从小到大 +2. 选择第一个活动,因为他就是最早结束的活动 +3. 接着往后找最早结束的活动,同时要满足该活动的开始时间要大于等于上一个选择的活动的结束时间,一直到没有活动可以选择 + +代码实现: + +```java +// 假设活动已经是根据结束时间有序的 +public class ActivitySelection { + /** + * 求解最大的兼容活动集合, 返回下标的集合 + * s 表示活动开始时间的集合 + * f 表示活动结束时间的集合 + * n 表示活动的总数 + */ + public List maxActivites(int[] s, int[] f, int n) { + List res = new ArrayList<>(); + int selected = 0; + res.add(selected); + + // 求剩余子问题的解 + for (int j = 0; j < n; j++) { + // 该活动的开始时间要大于等于上一个选择的活动的结束时间 + // 就是下一个要选择的活动 + if (s[j] >= f[i]) { + selected = j; + res.add(selected); + } + } + return res; + } +} +``` + +#### 贪心算法的实际应用 + +1. 哈夫曼编码 +2. 最小生成树:Prim 算法和 Kruskal 算法 +3. 最短路径:Dijkstra 算法 + +以上都是贪心算法的一些典型的实际应用,每一个总结起来都需要花费大量的精力,留在以后慢慢分析,在这里立一个 Flag. +此外,将贪心算法和动态规划放在一起做对比,放在学习完动态规划后的总结中。 + +#### 相关题目练习 + +利用老师课上讲的利用贪心选择和最近重复性的原则,以及贪心算法的基本要素:证明贪心选择的安全性以及找出最优子结构,原问题的最优解可以通过组合当前的选择和子问题的最优解得到。 + +- [移掉 K 个数字](https://leetcode-cn.com/problems/remove-k-digits/) + +问题描述: +>给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。 +> +> 1. num 的长度小于 10002 且 ≥ k +> 2. num 不会包含任何前导零 + +题解: +这道题的初步感觉是挺简单的,但是仔细想了之后发现并不简单。 +可以把问题分解为:当前选择是移除1个数字使剩余后的数字最小;子问题是在剩余的数字中再选择一个1个数字使剩余的数字最小;可见具有重复性,而且是最近重复性,而且当前选择并不会影响将来的选择,都是选择最小的,使原问题的解最终最小 + +代码实现: + +```java +public String removeKdigits(String num, int k) { + if (k >= num.length()) return "0"; + + char[] stack = new char[num.length()]; + int sPos = 0; + + for (char curr : num.toCharArray()) { + // 移动到新的字符上时,都去找当前的最大值,移除掉 + while (k > 0 && sPos > 0 && stack[sPos] > curr) { + sPos--; + k--; + } + + // 如果第一个位置是0的话,直接丢弃 + if (sPos != 0 || curr != '0') { + stack[sPos++] = curr; + } + } + + String res = new String(stack, 0, sPos - k); + return res.isEmpty() ? "0" : res; +} +``` + +- [无重叠区间](https://leetcode-cn.com/problems/non-overlapping-intervals/) + +问题描述: +> 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 +> +> 1. 可以认为区间的终点总是大于它的起点。 +> 2. 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 + +- [任务调度器](https://leetcode-cn.com/problems/task-scheduler/) + +#### 参考 + +1. 算法导论 +2. 数据结构与算法分析 +3. [Greedy Algothrim](https://www.geeksforgeeks.org/greedy-algorithms/) + +### 思考题 + +思考题:使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +分析: + +- 理解题目的意思 + +输入是一个半有序的数组,首先我们假设数组是升序后做了旋转后得到的,所以有一些特点:在断点处的前后都是有序的,但整体无序;第一个元素大于最后一个元素 +输出是找到那个无序的索引位置,我们假设返回的是最小元素的位置索引i,自然的,i-1就是最大元素的位置索引 + +- 找解决思路 + +思路1:使用暴力方式,以此遍历数组中的每个元素,比较两个元素的大小,如果出现前面的值大于后面的值的地方,就是我们要找的;但是此种方法,时间复杂度是 O(n),复杂度有些高,考虑是否有更优化的解法 + +思路2:虽然数组是整体无序的,但是部分是有序的,可以借助这个特性使用二分查找;已知 `nums[0] > nums[nums.length-1]`, 我们使用二分查找获取 `nums[mid]`, 让 `nums[mid]` 和 `nums[nums.length-1]` 做比较,如果 `nums[mid]` 大,说明断点出在 `mid` 之前,就调整 `low` 的位置;否则在 `mid` 之后,调整 `high` 的位置,这样持续下去,直到找到那个位置 + +此外,mid元素和位置0的元素做比较,道理是一样的 + +综合分析思路1和思路2,思路2的时间复杂度是 O(logn), 思路1的时间复杂度是O(n), 这个角度来看,思路2优于思路1,选择思路2做代码实现 + +- 编写代码 + +```java +public class HomeWork1 { + /** + * 查找半有序数组的最小元素的索引(同理就是找无序的地方) + */ + public int findMinElementIndex(int[] nums) { + int low = 0, high = nums.length - 1; + int lastElement = nums[high]; + while (low < high) { + int mid = low + ((high - low) >> 1); + if (nums[mid] < lastElement) high = mid; + else low = mid + 1; + } + return low; + } +} +``` + +- 测试用例 + +```text +Test Case: +[10, 11, 12, 14, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[10, 9] +[12, 13, 1, 2] +[12] +[12, 13, 14] +``` diff --git a/Week 03/id_721/LeetCode_122_721.java b/Week 03/id_721/LeetCode_122_721.java new file mode 100644 index 000000000..952f8d636 --- /dev/null +++ b/Week 03/id_721/LeetCode_122_721.java @@ -0,0 +1,34 @@ +package greedy; + +/** + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + *

+ * 示例 1: + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + *   随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + */ +public class LC_122_StockTradeMaxProfit { + + /** + * 11:34 AM info + * Success: + * Runtime:1 ms,faster than 99.99% of Java online submissions. + * Memory Usage:36.7 MB, less than 93.36% of Java online submissions. + * 最大股票收益: + * 思路:如果前一天价格比后一天低,买入,并且在第二天卖出,并且继续走买入逻辑,判断当天低价格是否比后一天低(天眼模式) + */ + public int maxProfit(int[] prices) { + int profit = 0; + if (prices.length == 0) return profit; + for (int i = 0; i < prices.length; i++) { + if (i + 1 < prices.length && prices[i + 1] - prices[i] > 0) { + profit += prices[i + 1] - prices[i]; + } + } + return profit; + } +} diff --git a/Week 03/id_721/LeetCode_455_721.java b/Week 03/id_721/LeetCode_455_721.java new file mode 100644 index 000000000..c8bc24078 --- /dev/null +++ b/Week 03/id_721/LeetCode_455_721.java @@ -0,0 +1,35 @@ +package greedy; + +import java.util.Arrays; + +/** + * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。 + * 但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi , + * 这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j , + * 都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i , + * 这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + * 思路: + * 1. 给一个孩子的饼干应当尽量小并且又能满足该孩子,这样大饼干才能拿来满足满足度比较大的孩子 + * 2. 因为满足度最小的孩子最容易满足,所以先满足满足度最小的孩子 + * 最优:尽量多的孩子分到饼干,那么每个孩子的饼干最接近其满足度 + */ +public class LC_455_AssignCookie { + + /** + * 满足孩子,胃口最小的孩子,优先满足,并且使用最靠近的饼干 + */ + public int findContentChildren(int[] g, int[] s) { + if (g.length == 0 || s.length == 0) return 0; + Arrays.sort(g); + Arrays.sort(s); + int gi = 0, sj = 0; + while (gi < g.length && sj < s.length) { + if (g[gi] <= s[sj]) { + // 当前最优解,用最小饼干满足小孩子最小的胃口 + gi++; + } + sj++; + } + return gi; + } +} diff --git a/Week 03/id_731/LeetCode_127_731.txt b/Week 03/id_731/LeetCode_127_731.txt new file mode 100644 index 000000000..2dfc2d69f --- /dev/null +++ b/Week 03/id_731/LeetCode_127_731.txt @@ -0,0 +1,29 @@ +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set wordSet(wordList.begin(), wordList.end()); + if (wordSet.count(endWord) == 0) { + return 0; + } + unordered_map pathCnt = {{beginWord, 1}}; + queue q{{beginWord}}; + while (!q.empty()) { + string word = q.front(); + q.pop(); + for (int i = 0; i < word.size(); ++i) { + string newWord = word; + for (char ch = 'a'; ch <= 'z'; ++ch) { + newWord[i] = ch; + if (wordSet.count(newWord) > 0 && newWord == endWord) { + return pathCnt[word] + 1; + } + if (wordSet.count(newWord) > 0 && !pathCnt.count(newWord)) { + q.push(newWord); + pathCnt[newWord] = pathCnt[word] + 1; + } + } + } + } + return 0; + } +}; \ No newline at end of file diff --git a/Week 03/id_731/LeetCode_74_731.txt b/Week 03/id_731/LeetCode_74_731.txt new file mode 100644 index 000000000..7d238313b --- /dev/null +++ b/Week 03/id_731/LeetCode_74_731.txt @@ -0,0 +1,25 @@ +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + int m = matrix.size(); + if (m == 0) return false; + int n = matrix[0].size(); + if (n == 0) return false; + int l = 0; + int r = m * n; + while(l < r) { + int mid = l + (r - l)/2; + int tm = mid / n; + int tn = mid - n * tm; + int tmp = matrix[tm][tn]; + if (tmp == target) { + return true; + } else if (tmp < target) { + l = mid + 1; + } else { + r = mid; + } + } + return false; + } +}; \ No newline at end of file diff --git a/Week 03/id_736/LeetCode_153_736.go b/Week 03/id_736/LeetCode_153_736.go new file mode 100644 index 000000000..b5e79cce5 --- /dev/null +++ b/Week 03/id_736/LeetCode_153_736.go @@ -0,0 +1,29 @@ +package id_736 + +func findMin(nums []int) int { + l := 0 + r := len(nums)-1 + m := 0 + if len(nums) == 1 { + return nums[0] + } + + for l<=r { + m = l+(r-l)/2 + if m == 0 { + if nums[0] > nums[1] { + return nums[1] + } else { + return nums[0] + } + } + if nums[m] < nums[m-1] { + return nums[m] + } else if nums[m] > nums[0] { + l = m+1 + } else { + r = m-1 + } + } + return nums[0] +} \ No newline at end of file diff --git a/Week 03/id_736/LeetCode_33_736.go b/Week 03/id_736/LeetCode_33_736.go new file mode 100644 index 000000000..aa31ca4c8 --- /dev/null +++ b/Week 03/id_736/LeetCode_33_736.go @@ -0,0 +1,54 @@ +package id_736 + +//1. 先二分遍历找到分隔点index,特征是 < 前一个元素, >后一个元素; +//2. 把数组分成二个部分,[0,index-1], [index,length-1]; +//3. 分别使用二分查找,找到给定的值。 +//时间复杂度为log(n). 不确定有什么更好的办法 + +func search(nums []int, target int) int { + if len(nums) == 0 { + return -1 + } + + n := len(nums) - 1 + divisionIndex := findDivision(nums) + if divisionIndex == 0 || divisionIndex == -1 { + //非旋转排序数组 + return findTarget(nums, 0, n, target) + } + + res := findTarget(nums, 0, divisionIndex-1, target) + if res != -1 { + return res + } + return findTarget(nums, divisionIndex, n, target) +} + +//找到分割点 +func findDivision(nums []int) int { + low, high := 0, len(nums)-1 + for low < high { + mid := low + (high-low)>>1 + + if nums[high] < nums[mid] { + low = mid + 1 + } else { + high = mid + } + } + return low +} + +func findTarget(nums []int, low, high, target int) int { + for low <= high { + mid := low + (high-low)>>1 + if nums[mid] > target { + high = mid - 1 + } else if nums[mid] < target { + low = mid + 1 + } else { + return mid + } + } + return -1 +} diff --git a/Week 03/id_736/LeetCode_74_736.go b/Week 03/id_736/LeetCode_74_736.go new file mode 100644 index 000000000..05a9f6fd7 --- /dev/null +++ b/Week 03/id_736/LeetCode_74_736.go @@ -0,0 +1,38 @@ +package id_736 + + +func searchMatrix(matrix [][]int, target int) bool { + if len(matrix) < 1 || len(matrix[0]) < 1 { + return false + } + + // binary search for row's first elems + rowsStart, rowsEnd := 0, len(matrix)-1 + for rowsStart <= rowsEnd { + rowsMid := (rowsStart + rowsEnd) / 2 + if target < matrix[rowsMid][0] { + rowsEnd = rowsMid - 1 + continue + } + if target > matrix[rowsMid][len(matrix[0])-1] { + rowsStart = rowsMid + 1 + continue + } + + // binary search for current row + colsStart, colsEnd := 0, len(matrix[0])-1 + for colsStart <= colsEnd { + colsMid := (colsStart + colsEnd) / 2 + switch { + case target == matrix[rowsMid][colsMid]: + return true + case target < matrix[rowsMid][colsMid]: + colsEnd = colsMid - 1 + case target > matrix[rowsMid][colsMid]: + colsStart = colsMid + 1 + } + } + return false + } + return false +} diff --git a/Week 03/id_756/[200]Number of Islands.java b/Week 03/id_756/[200]Number of Islands.java new file mode 100644 index 000000000..61a600d32 --- /dev/null +++ b/Week 03/id_756/[200]Number of Islands.java @@ -0,0 +1,36 @@ +class Solution { + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } +} diff --git a/Week 03/id_756/[860]Lemonade Change.java b/Week 03/id_756/[860]Lemonade Change.java new file mode 100644 index 000000000..d8979b7a4 --- /dev/null +++ b/Week 03/id_756/[860]Lemonade Change.java @@ -0,0 +1,25 @@ +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; + } +} diff --git a/Week 03/id_766/LeetCode_122_766.java b/Week 03/id_766/LeetCode_122_766.java new file mode 100644 index 000000000..228afab5f --- /dev/null +++ b/Week 03/id_766/LeetCode_122_766.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int res = 0; + int len = prices.length; + for (int i = 0; i < len-1; i++) { + res += Math.max(prices[i+1] - prices[i], 0); + + } + return res; + + } +} +// @lc code=end + diff --git a/Week 03/id_766/LeetCode_200_766.java b/Week 03/id_766/LeetCode_200_766.java new file mode 100644 index 000000000..c2ae766dc --- /dev/null +++ b/Week 03/id_766/LeetCode_200_766.java @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @lc code=start +class Solution { + private int n; + private int m; + public int numIslands(char[][] grid) { + int count = 0; + n = grid.length; + if (n == 0) return 0; + m = grid[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) + if (grid[i][j] == '1') { + DFSMarking(grid, i, j); + ++count; + } + } + return count; + + } + + private void DFSMarking(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return; + grid[i][j] = '0'; + DFSMarking(grid, i + 1, j); + DFSMarking(grid, i - 1, j); + DFSMarking(grid, i, j + 1); + DFSMarking(grid, i, j - 1); + } +} +// @lc code=end + diff --git a/Week 05/id_006/LeetCode_64_006.java b/Week 05/id_006/LeetCode_64_006.java new file mode 100644 index 000000000..de2ac611f --- /dev/null +++ b/Week 05/id_006/LeetCode_64_006.java @@ -0,0 +1,14 @@ +public class Solution { + + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} diff --git a/Week 05/id_006/LeetCode_91_006.java b/Week 05/id_006/LeetCode_91_006.java new file mode 100644 index 000000000..5dd3a9fbe --- /dev/null +++ b/Week 05/id_006/LeetCode_91_006.java @@ -0,0 +1,30 @@ +class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + //help用来存储res以前的值 + help = res-help; + } else { + help = res; + } + + } + return res; + } +} diff --git a/Week 05/id_006/NOTE.md b/Week 05/id_006/NOTE.md index a6321d6e2..3ce847b41 100644 --- a/Week 05/id_006/NOTE.md +++ b/Week 05/id_006/NOTE.md @@ -1,4 +1,15 @@ -# NOTE +# 动态规划要点 +- 重复子问题 +- 最优子结构 - +# 由递归到记忆化搜索、到动态规划解决问题 +- 思考问题如何分治,拆解为子问题 +- 可以通过「自顶向下」的记忆化递归求解 +- 可以通过「自底向上」的动态规划解法 +# 通过动态规划的解题步骤 +- 找出重复子问题,利用分治思维分解 +- 定义状态 +- 定义DP方程 + +本周太忙了,练习不够,后续回来重新补充 diff --git a/Week 05/id_011/decode-ways.go b/Week 05/id_011/decode-ways.go new file mode 100644 index 000000000..375519efe --- /dev/null +++ b/Week 05/id_011/decode-ways.go @@ -0,0 +1,20 @@ +package algorithm00401 + +func numDecodings(s string) int { + if len(s) == 0 || s[:1] == "0" { + return 0 + } + a, b := 1, 1 + for i := 1; i < len(s); i++ { + if s[i:i+1] == "0" { + a = 0 + } + if s[i-1:i] == "1" || (s[i-1:i] == "2" && s[i:i+1] <= "6") { + a = a + b + b = a - b + } else { + b = a + } + } + return a +} diff --git a/Week 05/id_011/maximal-square.go b/Week 05/id_011/maximal-square.go new file mode 100644 index 000000000..a0b25199e --- /dev/null +++ b/Week 05/id_011/maximal-square.go @@ -0,0 +1,30 @@ +package algorithm00401 + +func maximalSquare(matrix [][]byte) int { + if len(matrix) == 0 { + return 0 + } + square := make([][]int, len(matrix)+1) + for i := range square { + square[i] = make([]innt, len(matrix[0])+1) + } + maxSquare := 0 + for i := 1; i < len(square); i++ { + for j := 1; j < len(square); j++ { + if matrix[i-1][j-1] == '1' { + square[i][j] = minInt(minInt(square[i-1][j], square[i][j-1]), square[i-1][j-1]) + 1 + if maxSquare < square[i] { + maxSquare = square[i][j] + } + } + } + } + return maxSquare * maxSquare +} + +func minInt(i, j int) int { + if i < j { + return i + } + return j +} diff --git a/Week 05/id_011/minimum-path-sum.go b/Week 05/id_011/minimum-path-sum.go new file mode 100644 index 000000000..98bd6b4b9 --- /dev/null +++ b/Week 05/id_011/minimum-path-sum.go @@ -0,0 +1,23 @@ +package algorithm00401 + +func minPathSum(grid [][]int) int { + for i := len(grid) - 1; i >= 0; i-- { + for j := len(grid[0]) - 1; j >= 0; j-- { + if i == len(grid)-1 && j != len(grid[0])-1 { + grid[i][j] = grid[i][j] + grid[i][j+1] + } else if i != len(grid)-1 && j == len(grid[0])-1 { + grid[i][j] = grid[i][j] + grid[i+1][j] + } else if i != len(grid)-1 && j != len(grid[0])-1 { + grid[i][j] = grid[i][j] + minInt(grid[i+1][j], grid[i][j+1]) + } + } + } + return grid[0][0] +} + +func minInt(i, j int) int { + if i < j { + return i + } + return j +} diff --git a/Week 05/id_011/split-array-largest-sum.go b/Week 05/id_011/split-array-largest-sum.go new file mode 100644 index 000000000..e435037bd --- /dev/null +++ b/Week 05/id_011/split-array-largest-sum.go @@ -0,0 +1,38 @@ +package algorithm00401 + +func splitArray(nums []int, m int) int { + l, r := 0, 0 + for i := 0; i < len(nums); i++ { + r += nums[i] + if l < nums[i] { + l = nums[i] + } + } + ans := r + for l <= r { + mid := l + (r-l)/2 + sum, cnt := 0, 1 + for i := 0; i < len(nums); i++ { + if sum+nums[i] > mid { + cnt++ + sum = nums[i] + } else { + sum += nums[i] + } + } + if cnt <= m { + ans = minInt(ans, mid) + r = mid - 1 + } else { + l = mid + 1 + } + } + return ans +} + +func minInt(i, j int) int { + if i < j { + return i + } + return j +} diff --git a/Week 05/id_016/LeetCode_120_016.js b/Week 05/id_016/LeetCode_120_016.js new file mode 100644 index 000000000..62013c536 --- /dev/null +++ b/Week 05/id_016/LeetCode_120_016.js @@ -0,0 +1,65 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-11-17 20:16:19 + * @LastEditTime: 2019-11-17 20:25:28 + */ +/* + * @lc app=leetcode id=120 lang=javascript + * + * [120] Triangle + * + * https://leetcode.com/problems/triangle/description/ + * + * algorithms + * Medium (40.98%) + * Likes: 1412 + * Dislikes: 164 + * Total Accepted: 208.5K + * Total Submissions: 504.3K + * Testcase Example: '[[2],[3,4],[6,5,7],[4,1,8,3]]' + * + * Given a triangle, find the minimum path sum from top to bottom. Each step + * you may move to adjacent numbers on the row below. + * + * For example, given the following triangle + * + * + * [ + * ⁠ [2], + * ⁠ [3,4], + * ⁠ [6,5,7], + * ⁠ [4,1,8,3] + * ] + * + * + * The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). + * + * Note: + * + * Bonus point if you are able to do this using only O(n) extra space, where n + * is the total number of rows in the triangle. + * + */ + +// @lc code=start +/** +递推方程 +1.重复性 problem(i,j) = min(sub(i,j),sub(i+1,j+1))+cur[i][j] +2.定义状态数组或者存贮 f[i][j] +3.DP方程 dep[i][j] = Math.min(dep[i + 1][j], dep[i + 1][j + 1]) + dep[i][j]; + * @param {number[][]} triangle + * @return {number} + */ +var minimumTotal = function(triangle) { + let dep = triangle; + for (let i = dep.length - 2; i >= 0; i--) { + for (let j = 0; j < dep[i].length; j++) { + dep[i][j] = Math.min(dep[i + 1][j], dep[i + 1][j + 1]) + dep[i][j]; + } + } + return dep[0][0] +}; +// @lc code=end +console.log(minimumTotal([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])); \ No newline at end of file diff --git a/Week 05/id_016/LeetCode_53_016.js b/Week 05/id_016/LeetCode_53_016.js new file mode 100644 index 000000000..72f7b0d8f --- /dev/null +++ b/Week 05/id_016/LeetCode_53_016.js @@ -0,0 +1,78 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-11-17 20:56:16 + * @LastEditTime: 2019-11-17 21:20:42 + */ +/* + * @lc app=leetcode id=53 lang=javascript + * + * [53] Maximum Subarray + * + * https://leetcode.com/problems/maximum-subarray/description/ + * + * algorithms + * Easy (44.75%) + * Likes: 5502 + * Dislikes: 234 + * Total Accepted: 688.1K + * Total Submissions: 1.5M + * Testcase Example: '[-2,1,-3,4,-1,2,1,-5,4]' + * + * Given an integer array nums, find the contiguous subarray (containing at + * least one number) which has the largest sum and return its sum. + * + * Example: + * + * + * Input: [-2,1,-3,4,-1,2,1,-5,4], + * Output: 6 + * Explanation: [4,-1,2,1] has the largest sum = 6. + * + * + * Follow up: + * + * If you have figured out the O(n) solution, try coding another solution using + * the divide and conquer approach, which is more subtle. + * + */ +// @lc code=start +/** +1.暴力求解,超时 时间复杂度是 O(n^2) +2.动态规划 dp[i] = max((dp[i-1] +nums[i]),nums[i]) + * @param {number[]} nums + * @return {number} + */ +// var maxSubArray = function(nums) { +// let len = nums.length; +// let res = -Infinity; +// for (let i = len; i > 0; i--) { +// let flag = true; +// let left = 1; +// let right = i; +// while (flag) { +// let cur = nums.slice(left - 1, right); +// res = Math.max( +// cur.reduce((prev, c) => prev + c, 0), +// res +// ); +// left++; +// right++; +// if (right > len) flag = false; +// } +// } +// return res; +// }; +var maxSubArray = function(nums) { + let dp = []; + dp[0] = nums[0]; + let res = nums[0]; + for (let i = 1; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); + res = Math.max(dp[i], res); + } + return res; +}; +// @lc code=end +console.log(maxSubArray([-2, 1, -3, 4, -4, 2, 5, -5, 20])); diff --git a/Week 05/id_016/LeetCode_70_016.js b/Week 05/id_016/LeetCode_70_016.js new file mode 100644 index 000000000..42cba608a --- /dev/null +++ b/Week 05/id_016/LeetCode_70_016.js @@ -0,0 +1,103 @@ +/* + * @lc app=leetcode id=70 lang=javascript + * + * [70] Climbing Stairs + * + * https://leetcode.com/problems/climbing-stairs/description/ + * + * algorithms + * Easy (45.24%) + * Likes: 2886 + * Dislikes: 98 + * Total Accepted: 509.8K + * Total Submissions: 1.1M + * Testcase Example: '2' + * + * You are climbing a stair case. It takes n steps to reach to the top. + * + * Each time you can either climb 1 or 2 steps. In how many distinct ways can + * you climb to the top? + * + * Note: Given n will be a positive integer. + * + * Example 1: + * + * + * Input: 2 + * Output: 2 + * Explanation: There are two ways to climb to the top. + * 1. 1 step + 1 step + * 2. 2 steps + * + * + * Example 2: + * + * + * Input: 3 + * Output: 3 + * Explanation: There are three ways to climb to the top. + * 1. 1 step + 1 step + 1 step + * 2. 1 step + 2 steps + * 3. 2 steps + 1 step + * + * + */ + +// @lc code=start +/** +1.斐波那契式的傻递归 时间复杂度是O(2^n) 空间复杂度O(1) +2.递归增加缓存 时间复杂度是O(2^n) 空间复杂度O(n) +3.迭代法 时间复杂度是O(n) 空间复杂度O(1) +4.动态规划 时间复杂度是O(n) 空间复杂度O(n) + * @param {number} n + * @return {number} + */ +// var climbStairs = function(n) { +// if (n === 1) return 1; +// if (n === 2) return 2; +// return climbStairs(n - 1) + climbStairs(n - 2); +// }; +// var climbStairs = function(n) { +// let cache = new Array(n).fill(1); +// let deal = n => { +// if (n === 1) return 1; +// if (n === 2) return 2; +// if (cache[n - 1] === 1) { +// cache[n - 1] = deal(n - 1) + deal(n - 2); +// } +// return cache[n - 1]; +// }; +// return deal(n); +// }; +// var climbStairs = function(n) { +// if (n === 1) return 1; +// if (n === 2) return 2; +// let x = 1; +// let y = 2; +// let res = 0; +// for (let i = 3; i <= n; i++) { +// res = x + y; +// x = y; +// y = res; +// } +// return res +// }; +/** + 1.最优子结构 opt[n] = opt[n-1] + opt[n-2] + 2.存储中间状态 opt[i] + 3.DP方程 opt[n] = opt[n-1] + opt[n-2] + */ +var climbStairs = function(n) { + if (n === 1) return 1; + if (n === 2) return 2; + let dep = []; + dep[0] = 1; + dep[1] = 2; + for (let i = 2; i < n; i++) { + dep[i] = dep[i - 1] + dep[i - 2]; + } + return dep[n - 1]; +}; +// @lc code=end + +console.log(climbStairs(5)); diff --git a/Week 05/id_021/algorithm.zip b/Week 05/id_021/algorithm.zip new file mode 100644 index 000000000..aa9e049b4 Binary files /dev/null and b/Week 05/id_021/algorithm.zip differ diff --git a/Week 05/id_031/LeetCode_621_031.java b/Week 05/id_031/LeetCode_621_031.java new file mode 100644 index 000000000..d33547389 --- /dev/null +++ b/Week 05/id_031/LeetCode_621_031.java @@ -0,0 +1,50 @@ +package id_031; + +import java.util.Arrays; + +/** + * 给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU + * 在任何一个单位时间内都可以执行一个任务,或者在待命状态。 + * + * 然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 + * + * 你需要计算完成所有任务所需要的最短时间。 + * + * 示例 1: + * + * 输入: tasks = ["A","A","A","B","B","B"], n = 2 输出: 8 执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B. 注: + * + * 任务的总个数为 [1, 10000]。 n 的取值范围为 [0, 100]。 + * + * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/task-scheduler 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_621_031 { + + public int leastInterval(char[] tasks, int n) { + + int[] map = new int[26]; + for (char c : tasks) { + map[c - 'A']++; + } + Arrays.sort(map); + int time = 0; + while (map[25] > 0) { + int i = 0; + while (i <= n) { + if (map[25] == 0) { + break; + } + if (i < 26 && map[25 - i] > 0) { + map[25 - i]--; + } + time++; + i++; + } + Arrays.sort(map); + } + return time; + + + } + +} diff --git a/Week 05/id_031/LeetCode_64_031.java b/Week 05/id_031/LeetCode_64_031.java new file mode 100644 index 000000000..51da2d62b --- /dev/null +++ b/Week 05/id_031/LeetCode_64_031.java @@ -0,0 +1,47 @@ +package id_031; + + +/** + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + *   [1,3,1], + * [1,5,1], + * [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/minimum-path-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_64_031 { + + public int minPathSum(int[][] grid) { + + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + + return dp[0][0]; + + } + + +} diff --git a/Week 05/id_041/LeetCode_64_041.java b/Week 05/id_041/LeetCode_64_041.java new file mode 100644 index 000000000..8abd88ffc --- /dev/null +++ b/Week 05/id_041/LeetCode_64_041.java @@ -0,0 +1,21 @@ +package MinPathSum; + +public class LeetCode_64_041 { + public int LeetCode_64_041(int[][] grid) { + for(int i = 0;i < grid.length; i++){ + for( int j = 0; j < grid[0].length; j++ ){ + if(i == 0 && j == 0) continue; + if(i == 0){ + grid[i][j] = grid[i][j-1] + grid[i][j]; + }else if(j == 0){ + grid[i][j] = grid[i-1][j] + grid[i][j]; + }else{ + grid[i][j] = Math.min(grid[i-1][j],grid[i][j-1])+grid[i][j]; + } + } + } + return grid[grid.length-1][grid[0].length-1]; + } + + +} diff --git a/Week 05/id_041/LeetCode_76_041.java b/Week 05/id_041/LeetCode_76_041.java new file mode 100644 index 000000000..d1142dfe2 --- /dev/null +++ b/Week 05/id_041/LeetCode_76_041.java @@ -0,0 +1,81 @@ +package minimum_window_substring; + +import org.omg.CORBA.INTERNAL; + +import java.util.HashMap; + +/** + * 给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。 + + 示例: + + 输入: S = "ADOBECODEBANC", T = "ABC" + 输出: "BANC" + 说明: + + 如果 S 中不存这样的子串,则返回空字符串 ""。 + 如果 S 中存在这样的子串,我们保证它是唯一的答案。 + * + * */ +public class LeetCode_76_041 { + public String minWindow(String s, String t) { + if(s == null || s.length()==0 || t == null || t.length() == 0) return ""; + //使用双指针思路解决 + int[] map = new int[128]; + for(char c: t.toCharArray()) map[c]++; + int counter=t.length(), begin=0, end=0, d=Integer.MAX_VALUE, head=0; + while(end0); + if(map[s.toCharArray()[end++]]-->0) counter--; //in t + while(counter==0){ //valid + if(end-begin map = new HashMap<>(); + for(char c : t.toCharArray()){ + if(map.containsKey(c)){ + map.put(c,map.get(c)+1); + }else{ + map.put(c,1); + } + } + int left = 0; + int minLeft = 0; + int minLen = s.length()+1; + int count = 0; + for(int right = 0; right < s.length(); right++){ + if(map.containsKey(s.charAt(right))){ + map.put(s.charAt(right),map.get(s.charAt(right))-1); + if(map.get(s.charAt(right)) >= 0){ + count ++; + } + while(count == t.length()){ + if(right-left+1 < minLen){ + minLeft = left; + minLen = right-left+1; + } + if(map.containsKey(s.charAt(left))){ + map.put(s.charAt(left),map.get(s.charAt(left))+1); + if(map.get(s.charAt(left)) > 0){ + count --; + } + } + left ++ ; + } + } + } + if(minLen>s.length()) return ""; + return s.substring(minLeft,minLeft+minLen); + } + public static void main(String[] args){ + LeetCode_76_041 ms = new LeetCode_76_041(); + String s = "ADOBECODEBANC", t = "ABC"; + System.out.println(ms.minWindow(s,t)); + } +} diff --git a/Week 05/id_046/LeetCode_221_046.java b/Week 05/id_046/LeetCode_221_046.java new file mode 100644 index 000000000..1718a7592 --- /dev/null +++ b/Week 05/id_046/LeetCode_221_046.java @@ -0,0 +1,15 @@ + public int maximalSquare(char[][] matrix) { + int row = matrix.length, col = row > 0 ? matrix[0].length : 0; + int[][] dp = new int[row+1][col+1]; + int maxLen = 0; + for(int i = 1; i <= row; i++){ + for(int j = 1; j <= col; j++){ + if(matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1]) + 1; + // 更新当前最大边长 + maxLen = Math.max(dp[i][j],maxLen); + } + } + } + return maxLen * maxLen; + } \ No newline at end of file diff --git a/Week 05/id_046/LeetCode_32_046.java b/Week 05/id_046/LeetCode_32_046.java new file mode 100644 index 000000000..3d9a19f96 --- /dev/null +++ b/Week 05/id_046/LeetCode_32_046.java @@ -0,0 +1,19 @@ + public int longestValidParentheses(String s) { + int res = 0; + Stack stack = new Stack(); + // 匹配初始括号对 + stack.push(-1); + for(int i = 0;i < s.length(); i++){ + if(s.charAt(i) == '('){ + stack.push(i); + }else{ + stack.pop(); + if(stack.isEmpty()){ + stack.push(i); + }else{ + res = Math.max(res,i-stack.peek()); + } + } + } + return res; + } \ No newline at end of file diff --git a/Week 05/id_046/LeetCode_64_046.java b/Week 05/id_046/LeetCode_64_046.java new file mode 100644 index 000000000..fae8a512f --- /dev/null +++ b/Week 05/id_046/LeetCode_64_046.java @@ -0,0 +1,13 @@ + public int minPathSum(int[][] grid) { + if(grid == null || grid.length == 0) return 0; + int row = grid.length; + int col = grid[0].length; + for(int i = 0; i < row; i++){ + for(int j = 0; j < col; j++){ + if(i == 0 && j > 0) grid[i][j] += grid[i][j-1]; + if(j == 0 && i > 0) grid[i][j] += grid[i-1][j]; + if(i >0 && j > 0) grid[i][j] += Math.min(grid[i-1][j],grid[i][j-1]); + } + } + return grid[row-1][col-1]; + } \ No newline at end of file diff --git a/Week 05/id_071/LeetCode_064_071.go b/Week 05/id_071/LeetCode_064_071.go new file mode 100644 index 000000000..6ac8b41fe --- /dev/null +++ b/Week 05/id_071/LeetCode_064_071.go @@ -0,0 +1,81 @@ +package week05 + +//1.1 https://leetcode-cn.com/problems/minimum-path-sum/ + +func minPathSum(grid [][]int) int { + R := len(grid) + if R == 0 { + return 0 + } + C := len(grid[0]) + if C == 0 { + return 0 + } + for c := 1; c != C; c++ { // first row + grid[0][c] += grid[0][c-1] + } + for r := 1; r != R; r++ { + grid[r][0] += grid[r-1][0] + for c := 1; c != C; c++ { + grid[r][c] += min(grid[r-1][c], grid[r][c-1]) + } + } + return grid[R-1][C-1] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func minPathSums(grid [][]int) int { + mlen := len(grid) + if mlen == 0 { + return 0 + } + nlen := len(grid[0]) + if nlen == 0 { + return 0 + } + + dp := initDP(mlen, nlen) + initFirstCol(dp, grid) + initFirstRow(dp, grid) + + for i := 1; i < mlen; i++ { + for j := 1; j < nlen; j++ { + dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] + } + } + return dp[mlen-1][nlen-1] +} + +func initDP(mlen, nlen int) [][]int { + dp := make([][]int, mlen) + for i := 0; i < mlen; i++ { + dp[i] = make([]int, nlen) + } + return dp +} + +func initFirstCol(dp, grid [][]int) { + for i := 0; i < len(dp); i++ { + if i == 0 { + dp[i][0] = grid[i][0] + } else { + dp[i][0] = grid[i][0] + dp[i-1][0] + } + } +} + +func initFirstRow(dp, grid [][]int) { + for i := 0; i < len(dp[0]); i++ { + if i == 0 { + dp[0][i] = grid[0][i] + } else { + dp[0][i] = grid[0][i] + dp[0][i-1] + } + } +} \ No newline at end of file diff --git a/Week 05/id_071/LeetCode_091_071.go b/Week 05/id_071/LeetCode_091_071.go new file mode 100644 index 000000000..da3b3a6e2 --- /dev/null +++ b/Week 05/id_071/LeetCode_091_071.go @@ -0,0 +1,34 @@ +//1.3 https://leetcode-cn.com/problems/decode-ways/ + +func numDecodings(s string) int { + if string(s[0]) == "0" { + return 0 + } + + table := make([]int, len(s)) + table[0] = 1 + + for i := 1; i < len(s); i++ { + if string(s[i]) == "0" && string(s[i-1]) == "0" { + return 0 + } + + if string(s[i]) != "0" { + table[i] = table[i-1] + } + + if string(s[i-1]) == "0" { + continue + } + + if n, _ := strconv.Atoi(s[i-1 : i+1]); n > 0 && n <= 26 { + if i == 1 { + table[i]++ + } else { + table[i] += table[i-2] + } + } + } + + return table[len(table)-1] +} \ No newline at end of file diff --git a/Week 05/id_071/NOTE.md b/Week 05/id_071/NOTE.md index a6321d6e2..61bf95810 100644 --- a/Week 05/id_071/NOTE.md +++ b/Week 05/id_071/NOTE.md @@ -1,4 +1,61 @@ # NOTE - +> DP dynamic programming + + 最近最简的重复性 + 分治 + 最优子结构 + divide & conquer + optional substructure + + + 分解 重复子问题 + 状态 存储数组 + DP 方程式 + +##### 0-1 背包 + + +##### Fibonacci 数列 + + +##### 路径计算 + + +##### 爬楼梯 + + f(n) = f(n-1) + f(n-2) + + 扩展 + 1. 1,2,3 + 2. 相邻两部的步伐不能相同 + +##### 最长公共子序列 + + +##### 三角形最小路径和 + + dp[i] = Max(nums[i],nums[i]+dp[i-1]) + + nums[i] + Max(0,dp[i-1]) + +##### 最大子序列和 + + + 当前元素自身最大,或者 包含之前最大 + + Max(i) = Max(i-1, 0) + a[i] + +##### 打家劫舍 + + [1,6,2,9,3,1,6,5,2,1] + + 升维 一维数组=> 二维 => 多维 + + a[i] = a[i-1] + nums[i] + + + a[i][0] true + a[i][1] false + + a[i][0] = Max(a[i-1][0], a[i-1][1]) + a[i][1] = Max(a[i-1][0], 0) + nums[i] diff --git a/Week 05/id_076/LeetCode_32_076.java b/Week 05/id_076/LeetCode_32_076.java new file mode 100644 index 000000000..0ffcf2d00 --- /dev/null +++ b/Week 05/id_076/LeetCode_32_076.java @@ -0,0 +1,37 @@ +package week05; + +/** + * + * 最长有效括号 + * + * dp[i]=dp[i−2]+2 + * dp[i]=dp[i−1]+dp[i−dp[i−1]−2]+2 + * + * 复杂度分析 + * 时间复杂度: O(n)O(n) 。遍历整个字符串一次,就可以将 dpdp 数组求出来。 + * 空间复杂度: O(n)O(n) 。需要一个大小为 nn 的 dpdp 数组。 + * + * @author tangzhenhua + * @date 2019/11/17 21:12 + */ +public class LeetCode_32_076 { + + + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } + + +} diff --git a/Week 05/id_076/LeetCode_64_076.java b/Week 05/id_076/LeetCode_64_076.java new file mode 100644 index 000000000..d6e56aafa --- /dev/null +++ b/Week 05/id_076/LeetCode_64_076.java @@ -0,0 +1,50 @@ +package week05; + +/** + * 动态规划 采用二维数组 + * + * 复杂度分析 + * 时间复杂度 :O(mn)O(mn)。遍历整个矩阵恰好一次。 + * 空间复杂度 :O(mn)O(mn)。额外的一个同大小矩阵。 + * @author tangzhenhua + * @date 2019/11/17 20:51 + */ +public class LeetCode_64_076 { + + + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + + public static void main(String[] args) { + int[][] grid = new int[3][3]; + grid[0][0] = 1; + grid[0][1] = 3; + grid[0][2] = 1; + + grid[1][0] = 1; + grid[1][1] = 5; + grid[1][2] = 1; + + grid[2][0] = 4; + grid[2][1] = 2; + grid[2][2] = 1; + + LeetCode_64_076 leet = new LeetCode_64_076(); + int min = leet.minPathSum(grid); + System.out.println(min); + } +} diff --git a/Week 05/id_076/NOTE.md b/Week 05/id_076/NOTE.md index a6321d6e2..e93991d3f 100644 --- a/Week 05/id_076/NOTE.md +++ b/Week 05/id_076/NOTE.md @@ -1,4 +1,16 @@ -# NOTE - - - +# NOTE + +第5周 动态规划 + +1.最优子结构 +2.存储中间状态 +3.递推公式(状态转移方程,DP方程) +fib:opt[n] = opt[n-1] + opt[n-2] +二维路径:opt[i, j] = opt[i+1, j] + opt[i, j+1](可能需要判断 a[i, j] 是否能走) + +4.递归、分治、回溯、动态规划 都是找到问题的共性,将一个问题拆分为子问题,进而求解 + 递归:要注意重复问题,可以增加 子问题cache去除重复计算。 + 分治:将一个大问题,拆分几个子问题,每个子问题继续进行递归拆分。最终将结果合并。 + 动态规划:分治 + 最优子结构,淘汰次优结构。 + +5.二维动态规划算是入门,复杂点的问题都是三维四维。 \ No newline at end of file diff --git a/Week 05/id_081/BestTimeToBuyAndSellStock.java b/Week 05/id_081/BestTimeToBuyAndSellStock.java new file mode 100644 index 000000000..288fbdfb6 --- /dev/null +++ b/Week 05/id_081/BestTimeToBuyAndSellStock.java @@ -0,0 +1,15 @@ +/** + * BestTimeToBuyAndSellStock + */ +public class BestTimeToBuyAndSellStock { + + public int maxProfit(int[] prices) { + int n = prices.length; + int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE; + for (int i = 0; i < n; i++) { + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, -prices[i]); + } + return dp_i_0; + } +} \ No newline at end of file diff --git a/Week 05/id_081/HouseRobber.java b/Week 05/id_081/HouseRobber.java new file mode 100644 index 000000000..031ceb059 --- /dev/null +++ b/Week 05/id_081/HouseRobber.java @@ -0,0 +1,22 @@ +import java.util.Arrays; + +public class HouseRobber { + + //当 index 为 nums.length - 1 时, 能偷盗的最大金额就是 nums[nums.length - 1]; + //当 index 为 nums.length - 2 时, 能偷盗的最大金额就是 nums[nums.length - 2]; + //index -> nums.length - 3: max = nums[index] + nums[index - 2]; + //最终让我们返回 max + public static int rob(int[] nums) { + int max = 0; + int[] dp = Arrays.copyOf(nums, nums.length + 2); + for(int i = nums.length - 1; i >= 0; i--){ + dp[i] = nums[i] + dp[i + 2]; + max = Math.max(dp[i], max); + } + return max; + } + + public static void main(String[] args) { + System.out.println(rob(new int[]{2,1, 1, 2})); + } +} \ No newline at end of file diff --git a/Week 05/id_081/HouseRobberII.java b/Week 05/id_081/HouseRobberII.java new file mode 100644 index 000000000..cdba7b35b --- /dev/null +++ b/Week 05/id_081/HouseRobberII.java @@ -0,0 +1,23 @@ +/** + * HouseRobberII + */ +import java.util.Arrays; + +public class HouseRobberII { + + public int rob(int[] nums) { + if(nums.length == 0) return 0; + if(nums.length == 1) return nums[0]; + return Math.max(_rob(Arrays.copyOfRange(nums, 0, nums.length - 1)), + _rob(Arrays.copyOfRange(nums, 1, nums.length))); + } + private int _rob(int[] nums) { + int pre = 0, cur = 0, tmp; + for(int num : nums) { + tmp = cur; + cur = Math.max(pre + num, cur); + pre = tmp; + } + return cur; + } +} \ No newline at end of file diff --git a/Week 05/id_081/NOTE.md b/Week 05/id_081/NOTE.md old mode 100644 new mode 100755 diff --git a/Week 05/id_081/Triangle.java b/Week 05/id_081/Triangle.java new file mode 100644 index 000000000..cc0c438a5 --- /dev/null +++ b/Week 05/id_081/Triangle.java @@ -0,0 +1,17 @@ +import java.util.List; + + +public class Triangle { + + public int minimumTotal(List> triangle) { + List> dp = triangle; + for(int i = triangle.size() - 1; i > 0; i--) { + for(int j = 1; j < triangle.get(i).size(); j++) { + triangle.get(i - 1).set(j / 2, triangle.get(i -1).get(j / 2) + Math.min(triangle.get(i).get(j), triangle.get(i).get(j - 1))); + } + } + + return dp.get(0).get(0); + } + +} \ No newline at end of file diff --git a/Week 05/id_081/UniquePaths.java b/Week 05/id_081/UniquePaths.java new file mode 100644 index 000000000..53220e41b --- /dev/null +++ b/Week 05/id_081/UniquePaths.java @@ -0,0 +1,52 @@ +import java.util.Arrays; + +public class UniquePaths { + + /* + * 暴力解法: + * 从 左上角 开始, 他只有两种走法,一种向下,一种向右 + * 直到走到 右下角 + */ + public static int uniquePaths(int m, int n) { + return _uniquePaths(0, 0, m, n); + } + + public static int _uniquePaths(int x, int y, int m, int n) { + if (x >= m || y >= n) return 0; + if (x == m - 1 && y == n - 1) return 1; + + return _uniquePaths(x + 1, y, m, n) + _uniquePaths(x, y + 1, m, n); + } + + //递推公式 F(m, n) = F(m - 1, n) + F(m, n - 1) + //我们假设 m 代表的是 X 轴,n 代表的是 Y 轴 + public static int uniquePaths_2(int m, int n) { + int[] dp = new int[m]; + for (int i = 0; i < n; i++) + for (int j = m - 1; j >= 0; j--) + if (j == m - 1) + dp[j] = 1; + else + dp[j] = dp[j] + dp[j + 1]; + return dp[0]; + } + + public static int uniquePathOfficial(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]; + } + + public static void main(String[] args) { + System.out.println(uniquePaths(23, 12)); + System.out.println(uniquePaths_2(23, 12)); + + + + } +} \ No newline at end of file diff --git a/Week 05/id_086/LeetCode_32_086.java b/Week 05/id_086/LeetCode_32_086.java new file mode 100644 index 000000000..8e5b23107 --- /dev/null +++ b/Week 05/id_086/LeetCode_32_086.java @@ -0,0 +1,34 @@ +# 32. 最长有效括号,有效括号为(), +# 有效括号是必须成对出现的,如果接连出现把连续出现的括号累加 + +class Solution { + public int longestValidParentheses(String s) { + int left = 0, right = 0, maxLength = 0; + for (int i=0; i < s.length(); i++) { + if( s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxLength = Math.max(maxLength,2*right); + } else if ( right>=left ) { + left = right = 0; + } + } + left = right = 0; + for (int i=s.length()-1; i>=0; i--) { + if (s.charAt(i) =='(') { + left++; + } else { + right++; + } + if ( left==right ) { + maxLength = Math.max(maxLength,2*left); + } else if (left >= right) { + left = right = 0; + } + } + return maxLength; + } +} diff --git a/Week 05/id_086/LeetCode_76_086.java b/Week 05/id_086/LeetCode_76_086.java new file mode 100644 index 000000000..f2b2ce302 --- /dev/null +++ b/Week 05/id_086/LeetCode_76_086.java @@ -0,0 +1,45 @@ +# 76、 最小覆盖串 + + +class Solution { + public String minWindow(String s, String t) { + int sCount = s.length(); + int tCount = t.length(); + if (sCount < tCount) { + return ""; + } + char[] sChar = s.toCharArray(); + char[] tChar = t.toCharArray(); + int[] map = new int[256];// 利用 ASSII码做映射 + for ( int i=0; i=0) { + count++; + } + if(count==tCount) { + while(map[sChar[L]]<0) { + map[sChar[L]]++; + L++; + } + if (R-L= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + help = res-help; + } else { + help = res; + } + + } + return res; + } +} \ No newline at end of file diff --git a/Week 05/id_091/Leetcode_312_091.py b/Week 05/id_091/Leetcode_312_091.py new file mode 100644 index 000000000..4e2be2901 --- /dev/null +++ b/Week 05/id_091/Leetcode_312_091.py @@ -0,0 +1,21 @@ +from typing import List + + +class Solution: + def maxCoins(self, nums: List[int]) -> int: + nums = [1] + nums + [1] + n = len(nums) + dp = [[0] * n for _ in range(n)] + for step in range(2, n): + for i in range(n): + if step == 2: + if i + step < n: + dp[i][i + step] = nums[i] * nums[i + 1] * nums[i + 2] + # print(i, i + step, dp[i][i+step]) + continue + for k in range(i + 1, i + step): + if i + step < n: + dp[i][i + step] = max(dp[i][k] + dp[k][i + step] + nums[i] * nums[k] * nums[i + step], + dp[i][i + step]) + # print(i, i + step, dp[i][i+step]) + return dp[0][n - 1] diff --git a/Week 05/id_091/Leetcode_32_091.py b/Week 05/id_091/Leetcode_32_091.py new file mode 100644 index 000000000..7b298720a --- /dev/null +++ b/Week 05/id_091/Leetcode_32_091.py @@ -0,0 +1,33 @@ +import collections + + +class LRUCache: + + def __init__(self, capacity): + self.dic = collections.OrderedDict() + self.remain = capacity + + def get(self, key): + if key not in self.dic: + return -1 + v = self.dic.pop(key) + self.dic[key] = v + return v + + def put(self, key, value): + if key in self.dic: + self.dic.pop(key) + else: + if self.remain > 0: + self.remain -= 1 + else: + self.dic.popitem(last=False) + self.dic[key] = value + + +if __name__ == '__main__': + capacity = ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] + obj = LRUCache(capacity) + obj.put('test', 'test') + param_1 = obj.get('test') + print(param_1) diff --git a/Week 05/id_091/Leetcode_64_091.py b/Week 05/id_091/Leetcode_64_091.py new file mode 100644 index 000000000..c392af7d2 --- /dev/null +++ b/Week 05/id_091/Leetcode_64_091.py @@ -0,0 +1,33 @@ +class Solution: + def minPathSum(self, grid: [[int]]) -> int: + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: + continue + elif i == 0: + grid[i][j] = grid[i][j - 1] + grid[i][j] + elif j == 0: + grid[i][j] = grid[i - 1][j] + grid[i][j] + else: + grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] + return grid[-1][-1] + + +def minPathSum(dp): + """ + 1. dp问题: dp[i][j] += min(dp[i-1][j], dp[i][j-1]) + """ + m, n = len(dp), len(dp[0]) + for i in range(m): + for j in range(n): + if i - 1 >= 0 and j - 1 >= 0: + dp[i][j] += min(dp[i - 1][j], dp[i][j - 1]) + elif i - 1 >= 0: + dp[i][j] += dp[i - 1][j] + elif j - 1 >= 0: + dp[i][j] += dp[i][j - 1] + + return dp[m - 1][n - 1] + + +print(minPathSum([[1, 3, 1], [1, 5, 1], [4, 2, 1]])) diff --git a/Week 05/id_101/[32]Longest Valid Parentheses.py b/Week 05/id_101/[32]Longest Valid Parentheses.py new file mode 100644 index 000000000..9a04ff044 --- /dev/null +++ b/Week 05/id_101/[32]Longest Valid Parentheses.py @@ -0,0 +1,123 @@ +#Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring. +# +# Example 1: +# +# +#Input: "(()" +#Output: 2 +#Explanation: The longest valid parentheses substring is "()" +# +# +# Example 2: +# +# +#Input: ")()())" +#Output: 4 +#Explanation: The longest valid parentheses substring is "()()" +# +# Related Topics String Dynamic Programming + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + ''' + 4 cases [ (), ((, )(, )) ] + + dp[i] is longest valid substring ending at ith index + if case 1 '()' + dp[i] = dp[i-2] + 2 + case 2 can be ignored, since only do calc when encountering ')' + case 3 is invalid + if case 4 '))' + dp[i-1] is longest valid substring ending at (i-1)th index + (.. ) ( (..len is j..) ) + i-j-2 i-j-1 i-1 + if index (i - dp[i-1] -1) is '(' + then + dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2 + ''' + + res = 0 + dp = [0] * len(s) + for i in range(1, len(s)): + if s[i] == '(': + continue + j = i-1 - dp[i-1] # for case '))', i-1 is 2nd last ')', j is index of '(' mapping to last ')' + if j >= 0 and s[j] == '(': + dp[i] = dp[i-1] + 2 + if j-1 >= 0: + dp[i] += dp[j-1] + res = max(res, dp[i]) + return res + + + def longestValidParencheses(self, s): + ''' + use Stack to push last valid index for char '(' + + :param s: + :type s: + :return: + :rtype: + ''' + stack = [-1] + res = 0 + for idx, ch in enumerate(s): + if ch == '(': + # append index when encountering '(' + stack.append(idx) + else: + # won't be empty since append dummy index -1 at the beginning + stack.pop() + # after pop, if stack still not empty + # then update max length by + # current index subtract peek of stack + if stack: + res = max(res, idx - stack[-1]) + # else append current index when stack is empty + else: + stack.append(idx) + return res + + def longestValidParentheses(self, s): + ''' + use O(1) space complexity + idea is to scan string twice + 1. from left to right, reset when ')' counter >= '(' counter + 2. from right to left, reset when '(' counter >= ')' counter + + use generic scan helper func + + :param s: + :type s: + :return: + :rtype: + ''' + return max(self.scan_helper(s, '('), + self.scan_helper(s[::-1], ')')) + + def scan_helper(self, s, benchmark): + res = 0 + cand_len, cnt = 0, 0 + for c in s: + if c == benchmark: + cnt += 1 + cand_len += 1 + else: + cnt -= 1 + if cnt < 0: + cnt, cand_len = 0, 0 # reset + else: + cand_len += 1 + if cnt == 0: + res = max(res, cand_len) + return res + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_101/[64]Minimum Path Sum.py b/Week 05/id_101/[64]Minimum Path Sum.py new file mode 100644 index 000000000..bb8527401 --- /dev/null +++ b/Week 05/id_101/[64]Minimum Path Sum.py @@ -0,0 +1,68 @@ +#Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. +# +# Note: You can only move either down or right at any point in time. +# +# Example: +# +# +#Input: +#[ +#  [1,3,1], +# [1,5,1], +# [4,2,1] +#] +#Output: 7 +#Explanation: Because the path 1→3→1→1→1 minimizes the sum. +# +# Related Topics Array Dynamic Programming + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def minPathSum(self, dp): + """ + :type dp: List[List[int]] + :rtype: int + """ + ''' + dp[i][j] is min sum till row i, col j + dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] + + use rolling array to reduce space complexity O(n) + dp[j] = min(dp[j], dp[j-1]) + grid[i][j] + ---OR--- + modify on original given input array to reduce space complexity to O(1) + ''' + m, n = len(dp), len(dp[0]) + for i in range(m): + for j in range(n): + if i-1 >= 0 and j-1 >= 0: + dp[i][j] += min(dp[i-1][j], dp[i][j-1]) + elif i-1 >= 0: + dp[i][j] += dp[i-1][j] + elif j-1 >= 0: + dp[i][j] += dp[i][j-1] + return dp[m-1][n-1] + + def minPathSumII(self, grid): + ''' + rolling array + :type grid: List[List[int]] + :rtype: int + ''' + m, n = len(dp), len(dp[0]) + dp = [0] * n + dp[0] = grid[0][0] + for i in range(1, n): + dp[i] = dp[i-1] + grid[0][i] + + for i in range(1, m): + dp[0] += grid[i][0] + for j in range(1, n): + dp[j] = min(dp[j-1], dp[j]) + grid[i][j] + return dp[-1] + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_106/120.triangle.java b/Week 05/id_106/120.triangle.java new file mode 100644 index 000000000..d73bc24bd --- /dev/null +++ b/Week 05/id_106/120.triangle.java @@ -0,0 +1,65 @@ +/* + * @lc app=leetcode id=120 lang=java + * + * [120] Triangle + * + * https://leetcode.com/problems/triangle/description/ + * + * algorithms + * Medium (41.04%) + * Likes: 1399 + * Dislikes: 164 + * Total Accepted: 207.7K + * Total Submissions: 502.9K + * Testcase Example: '[[2],[3,4],[6,5,7],[4,1,8,3]]' + * + * Given a triangle, find the minimum path sum from top to bottom. Each step + * you may move to adjacent numbers on the row below. + * + * For example, given the following triangle + * + * + * [ + * ⁠ [2], + * ⁠ [3,4], + * ⁠ [6,5,7], + * ⁠ [4,1,8,3] + * ] + * + * + * The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). + * + * Note: + * + * Bonus point if you are able to do this using only O(n) extra space, where n + * is the total number of rows in the triangle. + * + */ + +// @lc code=start +class Solution { + public int minimumTotal(List> triangle) { + int[] f = new int[triangle.size()+1]; + for(int i = triangle.size()-1; i >= 0; i--){ + for(int j = 0; j < triangle.get(i).size(); j++){ + f[j] = Math.min(f[j] , f[j+1]) + triangle.get(i).get(j); + } + } + return f[0]; + } +} +// @lc code=end +/** + * 子问题:每一个节点向下的路径只能有两条,将三角形看作二维数组,每个节点表示为 a[i][j] 路径表示为f[i][j] + * 则每个下一层子路径可以表示为 f[i+1][j] f[i+1][j+1] + * 最短路径的总和就可以表示为 f[i][j] = min(f[i+1][j] , f[i+1][j+1]) + a[i][j] + * + * j + *i [2], + * [3,4], + * [6,5,7], + * [4,1,8,3] + * + * 注意从下往上进行遍历,如果从上往下遍历j+1很难取 + */ + diff --git a/Week 05/id_106/322.coin-change.java b/Week 05/id_106/322.coin-change.java new file mode 100644 index 000000000..1f44a46d5 --- /dev/null +++ b/Week 05/id_106/322.coin-change.java @@ -0,0 +1,83 @@ +/* + * @lc app=leetcode id=322 lang=java + * + * [322] Coin Change + * + * https://leetcode.com/problems/coin-change/description/ + * + * algorithms + * Medium (32.15%) + * Likes: 2452 + * Dislikes: 87 + * Total Accepted: 267.9K + * Total Submissions: 826.2K + * Testcase Example: '[1,2,5]\n11' + * + * You are given coins of different denominations and a total amount of money + * amount. Write a function to compute the fewest number of coins that you need + * to make up that amount. If that amount of money cannot be made up by any + * combination of the coins, return -1. + * + * Example 1: + * + * + * Input: coins = [1, 2, 5], amount = 11 + * Output: 3 + * Explanation: 11 = 5 + 5 + 1 + * + * Example 2: + * + * + * Input: coins = [2], amount = 3 + * Output: -1 + * + * + * Note: + * You may assume that you have an infinite number of each kind of coin. + * + */ + +// @lc code=start +class Solution { + public int coinChange(int[] coins, int amount) { + int[] dp = new int[amount+1]; + for(int i=0;i amount?-1:dp[amount]; + } +} +// @lc code=end +/** + * dp + * 1 子问题 + * 2 状态表示 + * 3 状态转移方程 + * + * 数组内为硬币的面值 + * f(amount) 表示得到当前amount时使用硬币的最小个数,等于当前最小个数加上减去当前面值后其余面值的最少个数 + * f(amount) = min(f(n-k) k in [coins]) + 1 + * + * 类似上台阶问题 + * 高度为0时走0步 + * 高度为1时走一步 + * 高度为2时走一个两步或者两个一步 + * [1,2] + * dp[0,1,1,2,2,3,3] + * index 0 1 2 3 4 5 6 + * + * dp[i] = min(dp[i], dp[i-coins[j]] + 1) + * + * + * BFS + */ + diff --git a/Week 05/id_106/53.maximum-subarray.java b/Week 05/id_106/53.maximum-subarray.java new file mode 100644 index 000000000..fc48a9ed9 --- /dev/null +++ b/Week 05/id_106/53.maximum-subarray.java @@ -0,0 +1,55 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode id=53 lang=java + * + * [53] Maximum Subarray + * + * https://leetcode.com/problems/maximum-subarray/description/ + * + * algorithms + * Easy (44.79%) + * Likes: 5466 + * Dislikes: 227 + * Total Accepted: 682.8K + * Total Submissions: 1.5M + * Testcase Example: '[-2,1,-3,4,-1,2,1,-5,4]' + * + * Given an integer array nums, find the contiguous subarray (containing at + * least one number) which has the largest sum and return its sum. + * + * Example: + * + * + * Input: [-2,1,-3,4,-1,2,1,-5,4], + * Output: 6 + * Explanation: [4,-1,2,1] has the largest sum = 6. + * + * + * Follow up: + * + * If you have figured out the O(n) solution, try coding another solution using + * the divide and conquer approach, which is more subtle. + * + */ + +// @lc code=start +class Solution { + public int maxSubArray(int[] nums) { + int[] dp = nums.clone();//deep copy + for(int i=1; i< nums.length;++i){ + dp[i] = Math.max(dp[i-1]+nums[i], nums[i]); + } + Arrays.sort(dp); + return dp[dp.length - 1]; + } +} +// @lc code=end +/** + * dp + * 1 子问题 从后到前,取到现在位置最大的和与当前数字的最大值 + * 2 状态数组定义 sum[i] + * 3 递推方程 sum[i] = Max(sum[i-1]+nums[i], nums[i]) + * + * 因为如果当前数字前面所有数的和加上当前数后反而更小,说明前面包含负数,如此相当去滑动滤波器窗口将整个数组遍历一遍,并将和存到新数组中,最后取该新数组中最大的数即可 + */ diff --git a/Week 05/id_111/Leetcode120_111.py b/Week 05/id_111/Leetcode120_111.py new file mode 100644 index 000000000..a1d29e96b --- /dev/null +++ b/Week 05/id_111/Leetcode120_111.py @@ -0,0 +1,33 @@ +''' +给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 +例如,给定三角形: +[ + [2], + [3,4], + [6,5,7], + [4,1,8,3] +] +自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 +说明: +如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 +''' +# 暴力法 brute-force ,递归 ,n层:left or right : O2^n +'''DP + 1. 找重复性(分治)problem(i,j) = min(sub(i+1,j),sub(i+1, j+1)) + a[i,j] + 2. 定义状态数组 f[i,j] + 3. DP方程 : f[i,j] = min(f[i+1,j],f[i+1,j+1] + a[i,j]) + 找最小路径 +''' +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + ''' + DP方程: + f[i,j] = min(f[i+1,j],f[i+1,j+1] + a[i,j]) + ''' + #dp 直接赋值给到 triangle + dp=triangle + #开始循环 + for i in range(len(triangle)-2, -1, -1): + for j in range(len(triangle[i])): + dp[i][j] += min(dp[i+1][j],dp[i+1][j+1]) + return dp[0][0] diff --git a/Week 05/id_111/NOTE.md b/Week 05/id_111/NOTE.md index a6321d6e2..4f50e54c7 100644 --- a/Week 05/id_111/NOTE.md +++ b/Week 05/id_111/NOTE.md @@ -1,4 +1,52 @@ -# NOTE +# 动态规划笔记 +# 分治+回溯+递归+动态规划 +## 递归(recursive)代码模板 + 1. 递归终止条件 + 2. 处理当前层逻辑 + 3. 下探到下一层 drill down + 4. 恢复当前层状态 +## 分治 + 自相似性(将大问题分解成相似的小问题,解决问题后将结果聚合在一起) +### 分治代码模板 + 1. 递归终止条件 + 2. split 拆分 + 3. 调用递归函数,每个子问题都进行调用 + 4. subresult 合并结果 + 5. 恢复当前层状态 +## 思维感悟 + **人肉递归低效** + **找最近最简法,将其拆分为可重复解决的问题** + **数学归纳法** + 斐波那契状态数 +## 动态规划 Dynamic Programming (动态递归) + - http://wikipedia.moesalih.com/Dynamic_programming + - 最优子结构 + - 动态规划与递归或分治无根本上的区别(有无最优子结构) +共性:找重复子问题 +差异:最优子结构、中途可淘汰次优解(将指数级复杂度降到多项式级别) +### 实战例题 +**斐波那契数列 Fibonacci sequence** +傻递归 (指数级时间复杂度) +> int fib (int n){ + if (n <= 0){ + return 0; + ​​​ } + else if (n == 1){ + return 1; ​​} + else { return fib (n - 1) + fib(n-2); + ​​} + ​} + > +**简化代码** +- 一,简洁,使用表达式书写(未改变时间复杂度) +> JAVAint fib(int b)​{ return n<=1 ? n:fib(n-1)+fib(n-2);​​} +> +- 改变时间复杂度,加入缓存(可存放至数组,python 可用 LRU cache) +**记忆化搜索(加缓存)** +> +int fib (int n, int [] memo) { if (n <= 0) { return 0; ​​} else if (n == 1) { return 1; ​​} else if (memo [n] == 0){ memo [n] = fib (n - 1) + fib (n - 2); ​​} return memo[n];​​​} +- 简化上述代码 +> int fib (int n, int [] memo) { if (n <= 1) { return n; ​​} ​​if (memo [n] == 0){ ​#若值没有被计算过 memo [n] = fib (n - 1) + fib (n - 2); ​​} return memo[n];​​​} diff --git a/Week 05/id_111/leetcode70_111.py b/Week 05/id_111/leetcode70_111.py new file mode 100644 index 000000000..c522e2dab --- /dev/null +++ b/Week 05/id_111/leetcode70_111.py @@ -0,0 +1,26 @@ +#leetcode 70 climbing stairs +''' +假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 +每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? +注意:给定 n 是一个正整数。 +示例 1: +输入: 2 +输出: 2 +解释: 有两种方法可以爬到楼顶。 +1. 1 阶 + 1 阶 +2. 2 阶 +''' +class Solution: + def climbStairs(self, n: int) -> int: + ''' + DP方程: + F(N) = F(N-1) + F(N-2) + ''' + if n <= 1: + return n + memo = {} + memo[1] = 1 + memo[2] = 2 + for i in range(3, n+1): + memo[i] = memo[i-1] + memo[i-2] + return memo[n] diff --git a/Week 05/id_126/LeetCode_64_126.py b/Week 05/id_126/LeetCode_64_126.py new file mode 100644 index 000000000..cee14363c --- /dev/null +++ b/Week 05/id_126/LeetCode_64_126.py @@ -0,0 +1,9 @@ +class Solution: + def minPathSum(self, grid: [[int]]) -> int: + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: continue + elif i == 0: grid[i][j] = grid[i][j - 1] + grid[i][j] + elif j == 0: grid[i][j] = grid[i - 1][j] + grid[i][j] + else: grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] + return grid[-1][-1] diff --git a/Week 05/id_126/LeetCode_91_126.py b/Week 05/id_126/LeetCode_91_126.py new file mode 100644 index 000000000..1fd2a6a60 --- /dev/null +++ b/Week 05/id_126/LeetCode_91_126.py @@ -0,0 +1,24 @@ +class Solution: + def numDecodings(self, s: str) -> int: + dp = [0] * len(s) + # 考虑第一个字母 + if s[0] == "0": + return 0 + else: + dp[0] = 1 + if len(s) == 1: return dp[-1] + # 考虑第二个字母 + if s[1] != "0": + dp[1] += 1 + if 10 <= int(s[:2]) <= 26: + dp[1] += 1 + for i in range(2, len(s)): + # 当出现连续两个0 + if s[i - 1] + s[i] == "00": return 0 + # 考虑单个字母 + if s[i] != "0": + dp[i] += dp[i - 1] + # 考虑两个字母 + if 10 <= int(s[i - 1] + s[i]) <= 26: + dp[i] += dp[i - 2] + return dp[-1] diff --git a/Week 05/id_131/LeetCode_221_131.java b/Week 05/id_131/LeetCode_221_131.java new file mode 100644 index 000000000..88d9df4b1 --- /dev/null +++ b/Week 05/id_131/LeetCode_221_131.java @@ -0,0 +1,29 @@ +package com.lzhlyle.leetcode.self.no221; + +public class MaximalSquare_2 { + public int maximalSquare(char[][] matrix) { + // base condition + if (matrix == null || matrix.length < 1 || matrix[0].length < 1) return 0; + + int width = matrix[0].length; + int maxSide = 0; + + int[] dp = new int[width + 1]; + int northwest = 0; + + for (char[] chars : matrix) { + for (int j = 0; j < width; j++) { + int nextNorthwest = dp[j + 1]; + if (chars[j] == '1') { + dp[j + 1] = Math.min(Math.min(dp[j], dp[j + 1]), northwest) + 1; + maxSide = Math.max(maxSide, dp[j + 1]); + } else { + dp[j + 1] = 0; + } + northwest = nextNorthwest; + } + } + + return maxSide * maxSide; + } +} diff --git a/Week 05/id_131/LeetCode_621_131.java b/Week 05/id_131/LeetCode_621_131.java new file mode 100644 index 000000000..390f5d664 --- /dev/null +++ b/Week 05/id_131/LeetCode_621_131.java @@ -0,0 +1,25 @@ +package com.lzhlyle.leetcode.self.no621; + +import java.util.Arrays; + +public class TaskScheduler_2 { + public int leastInterval(char[] tasks, int n) { + // base condition + if (n == 0) return tasks.length; + if (tasks.length == 1) return 1; + + // 分为26组 + int[] map = new int[26]; + for (char task : tasks) { + map[task - 'A']++; + } + // 按组内次数排列 + Arrays.sort(map); // O(log(n)) + + int nonMostFrequencyCnt = 25; + while (nonMostFrequencyCnt >= 0 && map[nonMostFrequencyCnt] == map[25]) nonMostFrequencyCnt--; + + return Math.max(tasks.length, + (map[25] - 1) * (n + 1) + (25 - nonMostFrequencyCnt)); + } +} diff --git a/Week 05/id_131/LeetCode_64_131.java b/Week 05/id_131/LeetCode_64_131.java new file mode 100644 index 000000000..24e18c219 --- /dev/null +++ b/Week 05/id_131/LeetCode_64_131.java @@ -0,0 +1,25 @@ +package com.lzhlyle.leetcode.self.no64; + +public class MinimumPathSum { + public int minPathSum(int[][] grid) { + int width = grid.length; + int height = grid[0].length; + + // 预处理: 最下一行, 最右一列 + for (int column = height - 2; column >= 0; column--) { // 从倒数第二格开始 + grid[width - 1][column] += grid[width - 1][column + 1]; + } + + // 预处理: 最右一列 + for (int row = width - 2; row >= 0; row--) { // 从倒数第二行开始 + grid[row][height - 1] += grid[row + 1][height - 1]; + } + + for (int row = width - 2; row >= 0; row--) { // 从倒数第二行开始 + for (int column = height - 2; column >= 0; column--) { // 从倒数第二格开始 + grid[row][column] += Math.min(grid[row + 1][column], grid[row][column + 1]); + } + } + return grid[0][0]; + } +} diff --git a/Week 05/id_131/LeetCode_91_131.java b/Week 05/id_131/LeetCode_91_131.java new file mode 100644 index 000000000..f89b33a1e --- /dev/null +++ b/Week 05/id_131/LeetCode_91_131.java @@ -0,0 +1,19 @@ +package com.lzhlyle.leetcode.self.no91; + +public class DecodeWays_2 { + public int numDecodings(String s) { + // base condition + if (s == null || s.length() < 1 || s.startsWith("0")) return 0; + + char[] chars = s.toCharArray(); + int f0 = 0, f1 = 1; + for (int i = 1; i < chars.length; i++) { + int a1 = (chars[i] > '0') ? f0 + f1 : 0; + int a0 = (chars[i - 1] == '1' || (chars[i - 1] == '2' && chars[i] <= '6')) ? f1 : 0; + + f1 = a1; + f0 = a0; + } + return f0 + f1; + } +} diff --git a/Week 05/id_131/NOTE.md b/Week 05/id_131/NOTE.md index a6321d6e2..5af6c19c0 100644 --- a/Week 05/id_131/NOTE.md +++ b/Week 05/id_131/NOTE.md @@ -1,4 +1,4 @@ -# NOTE - - - +# NOTE +第五周 + + diff --git a/Week 05/id_136/LeetCode_621_136.java b/Week 05/id_136/LeetCode_621_136.java new file mode 100644 index 000000000..f62ef08dd --- /dev/null +++ b/Week 05/id_136/LeetCode_621_136.java @@ -0,0 +1,17 @@ +public class Solution { + public int leastInterval(char[] tasks, int n) { + int len = tasks.length; + int[] count = new int[26]; + int max = 0, maxNum = 0; + for (char c : tasks) { + count[c - 'A']++; + if (count[c - 'A'] > max) { + max = count[c - 'A']; + maxNum = 1; + } else if (count[c - 'A'] == max) { + maxNum++; + } + } + return Math.max(len, (max - 1) * (n + 1) + maxNum); + } +} diff --git a/Week 05/id_136/LeetCode_91_136.java b/Week 05/id_136/LeetCode_91_136.java new file mode 100644 index 000000000..6174c2b35 --- /dev/null +++ b/Week 05/id_136/LeetCode_91_136.java @@ -0,0 +1,22 @@ +public class Solution { + public int numDecodings(String s) { + if(s == null || s.length() == 0) { + return 0; + } + int n = s.length(); + int[] dp = new int[n+1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + for(int i = 2; i <= n; i++) { + int first = Integer.valueOf(s.substring(i-1, i)); + int second = Integer.valueOf(s.substring(i-2, i)); + if(first >= 1 && first <= 9) { + dp[i] += dp[i-1]; + } + if(second >= 10 && second <= 26) { + dp[i] += dp[i-2]; + } + } + return dp[n]; + } +} diff --git a/Week 05/id_141/LeetCode_32_141.java b/Week 05/id_141/LeetCode_32_141.java new file mode 100644 index 000000000..74e9708d2 --- /dev/null +++ b/Week 05/id_141/LeetCode_32_141.java @@ -0,0 +1,23 @@ +package app; + +/** + * LongestValidParentheses + * 32. 最长有效括号 + */ +public class LongestValidParentheses { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} \ No newline at end of file diff --git a/Week 05/id_141/LeetCode_64_141.java b/Week 05/id_141/LeetCode_64_141.java new file mode 100644 index 000000000..ad97f381f --- /dev/null +++ b/Week 05/id_141/LeetCode_64_141.java @@ -0,0 +1,24 @@ +package app; + +/** + * MinPathSum 64. 最小路径和 + */ +public class MinPathSum { + + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } +} \ No newline at end of file diff --git a/Week 05/id_151/LeetCode_221_151.cpp b/Week 05/id_151/LeetCode_221_151.cpp new file mode 100644 index 000000000..ffcdbb0be --- /dev/null +++ b/Week 05/id_151/LeetCode_221_151.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int maximalSquare(vector>& matrix) { + if (matrix.empty() || matrix[0].empty()) + return 0; + + vector> dp(matrix.size()+1, vector(matrix[0].size() + 1, 0)); + + char m = matrix[0][0] - '0'; + for (int y = 1; y <= matrix.size(); ++y) { + for (int x = 1; x <= matrix[y-1].size(); ++x) { + if (matrix[y-1][x-1] == '1') { + dp[y][x] = min(min(dp[y-1][x], dp[y][x-1]), dp[y-1][x-1]) + 1; + m = max(m, dp[y][x]); + } + } + } + + return m*m; + } +}; diff --git a/Week 05/id_151/LeetCode_32_151.cpp b/Week 05/id_151/LeetCode_32_151.cpp new file mode 100644 index 000000000..95d7166ad --- /dev/null +++ b/Week 05/id_151/LeetCode_32_151.cpp @@ -0,0 +1,35 @@ +class Solution { +public: + int longestValidParentheses(string s) { + /* + i. 子问题 problem(i) + ii. 状态数组定义 dp[i] 当前位置所能匹配的括号数 + iii. DP方程 + if f(i) == ')' then + if f(i-1) == '(' then + f(i) = f(i-2) + 2 + else + if s(i- f(i-1) - 1) == '(' + f(i) = f(i-1) + f(i - f(i-1) - 2) + 2 + */ + + vector dp(s.size(), 0); + int res = 0; + for (int i = 0; i < s.size(); ++i) { + if (s[i] == ')') { + if (i - 1 >= 0 && s[i-1] == '(') { + dp[i] = (i - 2 >= 0 ? dp[i-2] : 0) + 2; + } else if (i - 1 >= 0 && s[i-1] == ')') { + int idx = i - dp[i-1] - 2; + if (idx + 1>= 0 && s[idx+1] == '(') { + dp[i] = dp[i-1] + (idx >= 0 ? dp[idx] : 0) + 2; + } + } + + res = max(res, dp[i]); + } + } + + return res; + } +}; diff --git a/Week 05/id_151/LeetCode_64_151.cpp b/Week 05/id_151/LeetCode_64_151.cpp new file mode 100644 index 000000000..07656e96f --- /dev/null +++ b/Week 05/id_151/LeetCode_64_151.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + int minPathSum(vector>& grid) { + /* + i. 子问题 m(x,y) = grid[x][y] + min(m(x-1,y), m(x,y-1)) + ii. 状态定义 dp[x][y] 从前面到这个位置的最小值 + iii. DP方程 m(x,y) = grid[x][y] + min(m(x-1,y), m(x,y-1)) + */ + if (grid.empty() || grid[0].empty()) + return 0; + auto dp = grid; + for (int y = 1; y < dp.size(); ++y) + dp[y][0] = dp[y-1][0] + grid[y][0]; + for (int x = 1; x < dp[0].size(); ++x) + dp[0][x] = dp[0][x-1] + grid[0][x]; + + if (grid[0].size() == 1) + return dp[grid.size()-1][0]; + + for (int y = 1; y < grid.size(); ++y) { + for (int x = 1; x < grid[y].size(); ++x) { + dp[y][x] = grid[y][x] + min(dp[y-1][x], dp[y][x-1]); + } + } + + return dp[grid.size()-1][grid[0].size()-1]; + } +}; diff --git a/Week 05/id_151/LeetCode_91_151.cpp b/Week 05/id_151/LeetCode_91_151.cpp new file mode 100644 index 000000000..5bc7513af --- /dev/null +++ b/Week 05/id_151/LeetCode_91_151.cpp @@ -0,0 +1,46 @@ +class Solution { +public: + int numDecodings(string s) { + if (s.empty() || s[0] == '0') + return 0; + /* + "226" + '2' 1 + '2' 2 + + i. 子问题: f(i) = max(s(i) + f(i - 1), if (s(i-1,i) <= 'Z') s(i-1,i) + f(i - 2)) + ii. 状态定义: dp[i] 到i位置所能decode的个数 + iii. DP方程: + */ + + vector dp(s.size(), 1); + for (int i = 0; i < s.size(); ++i) { + if (i - 1 >= 0) { + string tmp(s, i-1, 2); + if (tmp == "00") + return 0; + if (s[i] == '0') { + dp[i-1] = 0; + } + //cout << "tmp=" << tmp << endl; + if (atoi(tmp.c_str()) <= 26) { + if (i - 2 >= 0) { + dp[i] = dp[i-1] + dp[i-2]; + } else { + dp[i] = dp[i-1] + 1; + } + } else { + dp[i] = dp[i-1]; + } + } + } + + /* + for (int i = 0; i < dp.size(); ++i) + cout << dp[i] << ","; + cout << endl; + */ + + return dp[s.size()-1]; + } +}; diff --git a/Week 05/id_156/72_java.java b/Week 05/id_156/72_java.java new file mode 100644 index 000000000..e9f475876 --- /dev/null +++ b/Week 05/id_156/72_java.java @@ -0,0 +1,20 @@ +class Solution { + public int minDistance(String word1, String word2) { + int n1 = word1.length(); + int n2 = word2.length(); + int[][] dp = new int[n1 + 1][n2 + 1]; + + for (int j = 1; j <= n2; j++) dp[0][j] = dp[0][j - 1] + 1; + + for (int i = 1; i <= n1; i++) dp[i][0] = dp[i - 1][0] + 1; + + for (int i = 1; i <= n1; i++) { + for (int j = 1; j <= n2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1]; + else dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; + } + } + return dp[n1][n2]; + } +} + diff --git a/Week 05/id_156/91_java.java b/Week 05/id_156/91_java.java new file mode 100644 index 000000000..095afb085 --- /dev/null +++ b/Week 05/id_156/91_java.java @@ -0,0 +1,20 @@ +class Solution { + public int numDecodings(String s) { + if (s.charAt(0) == '0') return 0; + + int[] dp = new int[s.length() + 1]; + dp[0] = dp[1] = 1; + + for (int i = 2; i <= s.length(); i++) { + + if (s.charAt(i - 1) != '0') { + dp[i] += dp[i - 1]; + } + + if ((s.charAt(i - 2) == '1') || (s.charAt(i - 2) == '2' && s.charAt(i - 1) <= '6')) { + dp[i] += dp[i - 2]; + } + } + return dp[s.length()]; + } +} diff --git a/Week 05/id_161/LogestValidParentheses b/Week 05/id_161/LogestValidParentheses new file mode 100644 index 000000000..818a2076b --- /dev/null +++ b/Week 05/id_161/LogestValidParentheses @@ -0,0 +1,17 @@ +public class Solution { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} \ No newline at end of file diff --git a/Week 05/id_161/MaxSqual b/Week 05/id_161/MaxSqual new file mode 100644 index 000000000..d30b9ad11 --- /dev/null +++ b/Week 05/id_161/MaxSqual @@ -0,0 +1,16 @@ +public class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } +} \ No newline at end of file diff --git a/Week 05/id_161/NumDecoding b/Week 05/id_161/NumDecoding new file mode 100644 index 000000000..e49a5b947 --- /dev/null +++ b/Week 05/id_161/NumDecoding @@ -0,0 +1,23 @@ +public int numDecodings(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; + if (s.charAt(len - 1) != '0') { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + continue; + } + int ans1 = dp[i + 1]; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + + } + return dp[0]; +} diff --git a/Week 05/id_171/DecodeWaysSol.cs b/Week 05/id_171/DecodeWaysSol.cs new file mode 100644 index 000000000..b06122b31 --- /dev/null +++ b/Week 05/id_171/DecodeWaysSol.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace Poplar.Algorithm.WeekFive +{ + class DecodeWaysSol + { + public int NumDecodings(string s) + { + if (s[0] == '0') + { + return 0; + } + int pre = 1, cur = 1; + for (int i = 1; i < s.Length; i++) + { + int tmp = cur; + if (s[i] == '0') + { + if (s[i - 1] == '1' || s[i - 1] == '2') + { + cur = pre; + } + else + { + return 0; + } + } + else if (s[i - 1] == '1' || (s[i - 1] == '2' && s[i] >= '1' && s[i] <= '6')) + { + cur = cur + pre; + } + pre = tmp; + } + return cur; + } + } +} diff --git a/Week 05/id_171/MinimumPathSumSol.cs b/Week 05/id_171/MinimumPathSumSol.cs new file mode 100644 index 000000000..95aa9092f --- /dev/null +++ b/Week 05/id_171/MinimumPathSumSol.cs @@ -0,0 +1,46 @@ +using System; + +namespace Poplar.Algorithm.WeekFive +{ + ///

+ /// 最小路径和 + /// https://leetcode.com/problems/minimum-path-sum/ + /// https://leetcode-cn.com/problems/minimum-path-sum/ + /// + public class MinimumPathSumSol + { + /// + /// 动态规划。 + /// 定义状态f(i,j)是到出口的最小路径。 + /// dp方程:dp(i, j) = a[i][j] + min(dp(i + 1, j), dp(i, j + 1)) + /// + /// + /// + public int MinPathSum(int[][] grid) + { + var container = new int[grid[0].Length]; + for (int i = container.Length - 1; i >= 0; i--) + { + container[i] = (i == container.Length - 1) + ? grid[grid.Length - 1][i] + : grid[grid.Length - 1][i] + container[i + 1]; + } + for (int i = grid.Length - 2; i >= 0; i--) + { + var curLine = grid[i]; + for (int j = curLine.Length - 1; j >= 0; j--) + { + if (j == curLine.Length - 1) + { + container[j] = curLine[j] + container[j]; + } + else + { + container[j] = curLine[j] + Math.Min(container[j + 1], container[j]); + } + } + } + return container[0]; + } + } +} diff --git a/Week 05/id_176/LeetCode_32_176.py b/Week 05/id_176/LeetCode_32_176.py new file mode 100644 index 000000000..7ada5c475 --- /dev/null +++ b/Week 05/id_176/LeetCode_32_176.py @@ -0,0 +1,15 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + n = len(s) + if n == 0: return 0 + dp = [0] * n + res = 0 + for i in range(n): + if i>0 and s[i] == ")": + if s[i - 1] == "(": + dp[i] = dp[i - 2] + 2 + elif s[i - 1] == ")" and i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == "(": + dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2] + if dp[i] > res: + res = dp[i] + return res diff --git a/Week 05/id_176/LeetCode_64_176.swift b/Week 05/id_176/LeetCode_64_176.swift new file mode 100644 index 000000000..2d3165756 --- /dev/null +++ b/Week 05/id_176/LeetCode_64_176.swift @@ -0,0 +1,23 @@ +class Solution { + func minPathSum(_ grid: [[Int]]) -> Int { + let width = grid.count + let height = grid[0].count + var dp = [[Int]](repeating: [Int](repeating: 0, count: height), count: width) + for i in 0.. 0 + let jMark = j > 0 + if iMark && jMark { + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] + } else if iMark { + dp[i][j] = dp[i - 1][j] + grid[i][j] + } else if jMark { + dp[i][j] = dp[i][j - 1] + grid[i][j] + } else { + dp[i][j] = grid[i][j] + } + } + } + return (dp.last?.last)! + } +} diff --git a/Week 05/id_176/NOTE.md b/Week 05/id_176/NOTE.md index a6321d6e2..2d53a844e 100644 --- a/Week 05/id_176/NOTE.md +++ b/Week 05/id_176/NOTE.md @@ -2,3 +2,16 @@ +动态规划 和 递归或者分治 没有根本上的区别(关键看有无最优的子结构) + +共性:找到重复子问题 + +差异性:最优子结构、中途可以淘汰次优解 + +重点在于寻找递推方程 + + + +1. 分治(找子问题) +2. 状态数组定义 +3. 写DP方程 \ No newline at end of file diff --git a/Week 05/id_181/LeetCode_64_181.js b/Week 05/id_181/LeetCode_64_181.js new file mode 100644 index 000000000..1233a4731 --- /dev/null +++ b/Week 05/id_181/LeetCode_64_181.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function (grid) { + console.log(grid) + if (grid.length === 0) return 0; + const len_n = grid.length; + const len_m = grid[0].length; + + var temp = [[grid[0][0]]]; + for (let i = 1; i < len_m; i++) { + temp[0][i]=grid[0][i] + temp[0][i-1]; + } + for(let i =1;i int: + if not s or s[0] == '0': + return 0 + dp = [None] * len(s) + dp[0] = 1 + if len(s) > 1: + if s[1] == '0': + if int(s[0:2]) <= 26: + dp[1] = 1 + else: + return 0 # 此时该序列无法翻译 + else: + if int(s[0:2]) <= 26: + dp[1] = 2 + else: + dp[1] = 1 # 只有一种结果 + + for i in range(2, len(s)): # 从 2 开始 + if s[i] == '0': + if s[i-1] == '0': # 两个相邻的0 + return 0 + else: + if int(s[i-1:i+1]) <= 26: + dp[i] = dp[i-2] + else: # 以0结尾 大于26 直接返回 0 + return 0 + else: # s[i] 不为 ‘0’ + if s[i-1] == '0': # 前一个为 ‘0’ + dp[i] = dp[i-1] + else: # 前一个不为 ‘0’ + if int(s[i-1:i+1]) <= 26: # s[i-1] 和 s[i] 组成的数 <= 26 + dp[i] = dp[i-1] + dp[i-2] + else: # s[i-1] 和 s[i] 组成的数 > 26 + dp[i] = dp[i-1] + + return dp[len(s) - 1] diff --git a/Week 05/id_196/LeetCode_32_196.py b/Week 05/id_196/LeetCode_32_196.py new file mode 100644 index 000000000..fc70f2dee --- /dev/null +++ b/Week 05/id_196/LeetCode_32_196.py @@ -0,0 +1,45 @@ +#给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 +# +# 示例 1: +# +# 输入: "(()" +#输出: 2 +#解释: 最长有效括号子串为 "()" +# +# +# 示例 2: +# +# 输入: ")()())" +#输出: 4 +#解释: 最长有效括号子串为 "()()" +# +# Related Topics 字符串 动态规划 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + + class Solution: + def longestValidParentheses(self, s: str) -> int: + n = len(s) + if n == 0: return 0 + dp = [0] * n + res = 0 + for i in range(n): + if i > 0 and s[i] == ")": + if s[i - 1] == "(": + dp[i] = dp[i - 2] + 2 + elif s[i - 1] == ")" and i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == "(": + dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2] + if dp[i] > res: + res = dp[i] + return res + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_196/LeetCode_64_196.py b/Week 05/id_196/LeetCode_64_196.py new file mode 100644 index 000000000..4552af910 --- /dev/null +++ b/Week 05/id_196/LeetCode_64_196.py @@ -0,0 +1,43 @@ +#给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 +# +# 说明:每次只能向下或者向右移动一步。 +# +# 示例: +# +# 输入: +#[ +#  [1,3,1], +# [1,5,1], +# [4,2,1] +#] +#输出: 7 +#解释: 因为路径 1→3→1→1→1 的总和最小。 +# +# Related Topics 数组 动态规划 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + + class Solution: + def minPathSum(self, grid: [[int]]) -> int: + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: + continue + elif i == 0: + grid[i][j] = grid[i][j - 1] + grid[i][j] + elif j == 0: + grid[i][j] = grid[i - 1][j] + grid[i][j] + else: + grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] + return grid[-1][-1] + + 1 +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_201/LeetCode_32_longestValidParentheses b/Week 05/id_201/LeetCode_32_longestValidParentheses new file mode 100644 index 000000000..e37ba0c3d --- /dev/null +++ b/Week 05/id_201/LeetCode_32_longestValidParentheses @@ -0,0 +1,41 @@ +package com.ann.leetCode.medium; + +import java.util.Stack; + +public class LeetCode32LongestValidParenthese { + public int longestValidParentheses(String s) { + int longestV = 0; + Stack st = new Stack(); + st.push(-1); + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '(') { + st.push(i); + } else { + st.pop(); + if (st.isEmpty()) { + st.push(i); + } else { + longestV = Math.max(longestV, i - st.peek()); + } + } + } + return longestV; + } + + /** + * dp + * @param s + * @return + */ + public int longestValidParentheses1(String s) { + int maxN = 0; + int[] validParenthesesLen = new int[s.length()]; + for (int i = 1; i < s.length(); ++i) { + if (s.charAt(i) == ')' && i - validParenthesesLen[i - 1] >= 1 && s.charAt(i - validParenthesesLen[i - 1] - 1) == '(') { + validParenthesesLen[i] = validParenthesesLen[i - 1] + 2 + (i - validParenthesesLen[i - 1] >= 2 ? validParenthesesLen[i - validParenthesesLen[i - 1] - 2]: 0); + maxN = Math.max(maxN, validParenthesesLen[i]); + } + } + return maxN; + } +} diff --git a/Week 05/id_201/LeetCode_64_minPathSum b/Week 05/id_201/LeetCode_64_minPathSum new file mode 100644 index 000000000..689a752af --- /dev/null +++ b/Week 05/id_201/LeetCode_64_minPathSum @@ -0,0 +1,114 @@ +package com.ann.leetCode.medium; + +public class LeetCode_64_MinPathSum { + + /** + * 自顶向下 + 记忆数组 MEMO + * 时间复杂度:O(M*N) + * 空间复杂度:O(M*N) + * @param grid + * @return + */ + public int minPathSum(int[][] grid) { + int[][] visited = new int[grid.length][grid[0].length]; + visitGrid(grid, 0, 0, visited, 0); + return visited[grid.length - 1][grid[0].length - 1]; + } + + public void visitGrid(int[][] grid, int currentX, int currentY, int[][] visited, int preSum) { + if (currentX >= grid.length || currentY >= grid[0].length) + return; + if (visited[currentX][currentY] == 0 || preSum + grid[currentX][currentY] < visited[currentX][currentY]) { + visited[currentX][currentY] = preSum + grid[currentX][currentY]; + visitGrid(grid, currentX + 1, currentY, visited, visited[currentX][currentY]); + visitGrid(grid, currentX, currentY + 1, visited, visited[currentX][currentY]); + } + } + + public int visitGrid1(int[][] grid, int currentX, int currentY, int[][] visited) { + if (currentX >= grid.length || currentY >= grid[0].length) + return Integer.MAX_VALUE; + if ((currentX == grid.length -1 && currentY == grid[0].length - 1)) + return grid[currentX][currentY]; + if (visited[currentX][currentY] == 0) { + visited[currentX][currentY] = grid[currentX][currentY] + + Math.min(visitGrid1(grid, currentX + 1, currentY, visited), + visitGrid1(grid, currentX, currentY + 1, visited)); + } + return visited[currentX][currentY]; + } + + /** + * #3 + * bottom-up 时间复杂度为O(M*N) + * 空间复杂度: O(1) + * M:行数 N:列数 + * @param grid + * @return + */ + public int minPathSum1(int[][] grid) { + int maxX = grid.length - 1, maxY = grid[0].length - 1; + for (int i = maxX - 1; i >=0; --i) { + grid[i][maxY] += grid[i + 1][maxY]; + } + for (int j = maxY - 1; j >= 0; --j) { + grid[maxX][j] += grid[maxX][j + 1]; + } + for (int i = maxX - 1; i >= 0; --i) { + for (int j = maxY - 1; j >= 0; --j) { + if (grid[i + 1][j] <= grid[i][j + 1]) { + grid[i][j] += grid[i + 1][j]; + } else { + grid[i][j] += grid[i][j + 1]; + } + } + } + return grid[0][0]; + } + + /** + * #4 IMPROVEMENT OF #3 + * @param grid + * @return + */ + public int minPathSum2(int[][] grid) { + int maxX = grid.length - 1, maxY = grid[0].length - 1; + for (int i = maxX; i >= 0; --i) { + for (int j = maxY; j >= 0; --j) { + if (i == maxX && j == maxY) { + continue; + } else if (i == maxX) { + grid[i][j] += grid[i][j + 1]; + } else if (j == maxY) { + grid[i][j] += grid[i + 1][j]; + } else if (grid[i + 1][j] <= grid[i][j + 1]) { + grid[i][j] += grid[i + 1][j]; + } else { + grid[i][j] += grid[i][j + 1]; + } + } + } + return grid[0][0]; + } + + /** + * 动态规划 使用一维数组 + * @param grid + * @return + */ + public int minPathSum3(int[][] grid) { + + return grid[0][0]; + } + + /** + * 从坐上角开始 + * 动态规划 使用一维数组 + * @param grid + * @return + */ + public int minPathSum4(int[][] grid) { + + return grid[0][0]; + } +} diff --git a/Week 05/id_216/Week05.java b/Week 05/id_216/Week05.java new file mode 100644 index 000000000..83b85064c --- /dev/null +++ b/Week 05/id_216/Week05.java @@ -0,0 +1,38 @@ +public class Week05 { + + public Week05() { + + } + + //32 + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } + + + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j + 1]); + } + } + return grid[0][0]; + } +} diff --git a/Week 05/id_241/LeetCode_120_241.java b/Week 05/id_241/LeetCode_120_241.java new file mode 100644 index 000000000..2813b7283 --- /dev/null +++ b/Week 05/id_241/LeetCode_120_241.java @@ -0,0 +1,16 @@ +import java.util.*; +/** + *三角形最小路径和 + */ +public class Solution { + public int minimumTotal(List> triangle) { + int size = triangle.size(); + int[] arr = new int[size + 1]; + for (int i = size - 1; i >= 0; i--) { + for (int j = 0; j <= i; j++) { + arr[j] = Math.min(arr[j], arr[j + 1]) + triangle.get(i).get(j); + } + } + return arr[0]; + } +} \ No newline at end of file diff --git a/Week 05/id_241/LeetCode_152_241.java b/Week 05/id_241/LeetCode_152_241.java new file mode 100644 index 000000000..a85a41408 --- /dev/null +++ b/Week 05/id_241/LeetCode_152_241.java @@ -0,0 +1,20 @@ +import java.util.*; +/** + *乘积最大子序列 + */ +public class Solution { + public int maxProduct(int[] nums) { + int imax = 1, imin = 1, max = Integer.MIN_VALUE; + for (int num : nums) { + if (num < 0) { + int tmp = imax; + imax = imin; + imin = tmp; + } + imax = Math.max(imax * num, num); + imin = Math.min(imin * num, num); + max = Math.max(max, imax); + } + return max; + } +} \ No newline at end of file diff --git a/Week 05/id_246/LeetCode_32_246.py b/Week 05/id_246/LeetCode_32_246.py new file mode 100644 index 000000000..e781949a1 --- /dev/null +++ b/Week 05/id_246/LeetCode_32_246.py @@ -0,0 +1,70 @@ +''' +longest-valid-parentheses_32 + +给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + +示例 1: + +输入: "(()" +输出: 2 +解释: 最长有效括号子串为 "()" +示例 2: + +输入: ")()())" +输出: 4 +解释: 最长有效括号子串为 "()()" +''' + +#stack +def longestValidParentheses_1(s): + if not s: return 0 + res = 0 + stack = [-1] + for i in range(len(s)): + if s[i] == '(': + stack.append(i) + print(i, stack) + else: + stack.pop() + print(i, stack) + if not stack: + stack.append(i) + print(i, stack) + else: + res = max(res, i-stack[-1]) + print(i,stack,res) + return res + +#stack_2 +def longestValidParentheses_2(s): + stack = [0] + longest = 0 + + for c in s: + if c == '(': + stack.append(0) + else: + if len(stack)>1: + val = stack.pop() + stack[-1] += val+2 + longest = max(longest, stack[-1]) + else: + stack = 0 + return longest + + +#dp +def longestValidParentheses_3(s): + n = len(s) + if n == 0: return 0 + dp = [0]*n + res = 0 + for i in range(n): + if i > 0 and s[i] == ')': + if s[i-1] == '(': + dp[i] = dp[i-2] + 2 + elif s[i-1] == ')' and i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == "(": + dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2] + if dp[i] > res: + res = dp[i] + return res \ No newline at end of file diff --git a/Week 05/id_246/LeetCode_621_246.py b/Week 05/id_246/LeetCode_621_246.py new file mode 100644 index 000000000..81d2b4bfd --- /dev/null +++ b/Week 05/id_246/LeetCode_621_246.py @@ -0,0 +1,38 @@ +''' +task-scheduler_621 + +给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。 + +然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 + +你需要计算完成所有任务所需要的最短时间。 + +示例: +输入: tasks = ["A","A","A","B","B","B"], n = 2 +输出: 8 +执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B. +注: + +任务的总个数为 [1, 10000]。 +n 的取值范围为 [0, 100]。 +''' + +#贪心 +def leastInterval(tasks, n): + length = len(tasks) + if length <= 1: + return length + + task_map = dict() + for task in tasks: + task_map[task] = task_map.get(task,0)+1 + task_sort = sorted(task_map.items(), key=lambda x:x[1], reverse=True) + + max_task_count = task_sort[0][1] + res = (max_task_count-1)*(n+1) + + for sort in task_sort: + if sort[1] == max_task_count: + res += 1 + + return res if res >= length else length diff --git a/Week 05/id_246/LeetCode_64_246.py b/Week 05/id_246/LeetCode_64_246.py new file mode 100644 index 000000000..98f079431 --- /dev/null +++ b/Week 05/id_246/LeetCode_64_246.py @@ -0,0 +1,30 @@ +''' +minimum-path-sum_64 + +给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 + +示例: +输入: +[ +  [1,3,1], + [1,5,1], + [4,2,1] +] +输出: 7 +解释: 因为路径 1→3→1→1→1 的总和最小。 +''' + +#dp +def minPathSum(grid): + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: continue + elif i == 0: + grid[i][j] = gird[i][j-1] + grid[i][j] + elif j == 0: + grid[i][j] = grid[i-1][j] + grid[i][j] + else: + grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] + return grid[-1][-1] \ No newline at end of file diff --git a/Week 05/id_246/LeetCode_72_246.py b/Week 05/id_246/LeetCode_72_246.py new file mode 100644 index 000000000..face79164 --- /dev/null +++ b/Week 05/id_246/LeetCode_72_246.py @@ -0,0 +1,42 @@ +''' +edit-distance_72 + +给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 + +你可以对一个单词进行如下三种操作: +插入一个字符 +删除一个字符 +替换一个字符 + +示例: +输入: word1 = "horse", word2 = "ros" +输出: 3 + +解释: +horse -> rorse (将 'h' 替换为 'r') +rorse -> rose (删除 'r') +rose -> ros (删除 'e') +''' + +#dp +def minDistance(word1, word2): + n, m = len(word1), len(word2) + if n*m == 0: + return n+m + + d = [[0] * (m+1) for _ in range(n+1)] + + for i in range(n+1): + d[i][0] = i + for j in range(m+1): + d[0][j] = j + + for i in range(1, n+1): + for j in range(1, m+1): + left = d[i-1][j] + 1 + down = d[i][j-1] + 1 + left_down = d[i-1][j-1] + if word1[i-1] != word2[j-1]: + left_down += 1 + d[i][j] = min(left, down, left_down) + return d[n][m] \ No newline at end of file diff --git a/Week 05/id_246/LeetCode_91_246.py b/Week 05/id_246/LeetCode_91_246.py new file mode 100644 index 000000000..d6664937f --- /dev/null +++ b/Week 05/id_246/LeetCode_91_246.py @@ -0,0 +1,68 @@ +''' +decode-ways_91 + +一条包含字母 A-Z 的消息通过以下方式进行了编码: + +'A' -> 1 +'B' -> 2 +... +'Z' -> 26 +给定一个只包含数字的非空字符串,请计算解码方法的总数。 + +示例 1: +输入: "12" +输出: 2 +解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + +示例 2: +输入: "226" +输出: 3 +解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +''' + +#dp_1 +def numDecodings_1(s): + if not s or s[0] == '0': + return 0 + dp = [None] * len(s) + dp[0] = 1 + if len(s) > 1: + if s[1] == '0': + if int(s[0:2]) <= 26: + dp[1] = 1 + else: + return 0 + else: + if int(s[0:2]) <= 26: + dp[1] = 2 + else: + dp[1] = 1 + else: + return 1 + + for i in range(2, len(s)): + if s[i] == '0': + if s[i-1] == '0': + return 0 + else: + if int(s[i-1:i+1]) <= 26: + dp[i] = dp[i-2] + else: + return 0 + else: + if s[i-1] == '0': + dp[i] = dp[i-1] + else: + if int(s[i-1:i+1]) <= 26: # s[i-1] 和 s[i] 组成的数 <= 26 + dp[i] = dp[i-1] + dp[i-2] + else: + dp[i] = dp[i-1] + + return dp[len(s)-1] + +#dp_2 +def numDecodings_2(s): + pp, p = 1, int(s[0] != '0') + for i in range(1, len(s)): + pp, p = p, pp*(9< int(s[i-1:i+1]) <= 26) + p*(int(s[i]) >0) + return p diff --git a/Week 05/id_246/NOTE.md b/Week 05/id_246/NOTE.md index a6321d6e2..19b981e07 100644 --- a/Week 05/id_246/NOTE.md +++ b/Week 05/id_246/NOTE.md @@ -1,4 +1,11 @@ # NOTE +【关键点】 - +1. 动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构) + 共性:找到重复子问题 + 差异性:最优子结构、中途可以淘汰次优解 +2. 动态规划框架: + 【1】最优子结构 opt[n] = best_of(opt[n-1], opt[n-2], …) + 【2】 储存中间状态:opt[i] + 【3】 递推公式(状态转移方程或者 DP 方程) \ No newline at end of file diff --git a/Week 05/id_251/LeetCode_32_251.py b/Week 05/id_251/LeetCode_32_251.py new file mode 100644 index 000000000..2fd1ecbd1 --- /dev/null +++ b/Week 05/id_251/LeetCode_32_251.py @@ -0,0 +1,109 @@ +# 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 +# +# 示例 1: +# +# 输入: "(()" +# 输出: 2 +# 解释: 最长有效括号子串为 "()" +# +# +# 示例 2: +# +# 输入: ")()())" +# 输出: 4 +# 解释: 最长有效括号子串为 "()()" +# +# Related Topics 字符串 动态规划 + +""" +1、 暴力法 +2、 stack 方法 +3、 DP +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + max_len = 0 + for i in range(len(s)): + for j in range(i + 2, len(s) + 1, 2): + if self.isValid(s[i:j]): + max_len = max(j - i, max_len) + return max_len + + def isValid(self, s): + stack = [] + for c in s: + if c == '(': + stack.append('(') + elif stack: + stack.pop() + else: + return False + return not stack + + +class Solution2(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + stack = [-1] + max_len = 0 + for i in range(len(s)): + if s[i] == '(': + stack.append(i) + else: + stack.pop() + if not stack: + stack.append(i) + else: + max_len = max(max_len, i - stack[-1]) + return max_len + + +# DP +class Solution3(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + """ + DP + a. 重复性 + if s(i) is ')': + if s(i - 1) is '(': + problem(i) = sub(i - 2) + 2 + if i - sub(i - 1) > 0 and s[i - sub[i - 1] - 1] == '(': + problem(i) = sub(i - 1) + sub(i - sub(i - 1) - 2) + 2 + b. 定义状态数组 f[i] + c. dp方程 + if s[i] == ')': + if s[i - 1] == '(': + dp[i] = dp[i - 2] + 2 + elif i - dp[i - 1] > 0 and s[i - dp[i - 1] - 1] == '(': + dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 + """ + dp = [0] * len(s) + max_len = 0 + for i in range(1, len(s)): + if s[i] == ')': + if s[i - 1] == '(': + dp[i] = dp[i - 2] + 2 + elif i - dp[i - 1] > 0 and s[i - dp[i - 1] - 1] == '(': + dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 + max_len = max(max_len, dp[i]) + return max_len + + +if __name__ == '__main__': + S = Solution2() + s = ')()' + print(S.longestValidParentheses(s)) diff --git a/Week 05/id_251/LeetCode_62_251.py b/Week 05/id_251/LeetCode_62_251.py new file mode 100644 index 000000000..79cc3e3a7 --- /dev/null +++ b/Week 05/id_251/LeetCode_62_251.py @@ -0,0 +1,138 @@ +# 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 +# +# 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 +# +# 问总共有多少条不同的路径? +# +# +# +# 例如,上图是一个7 x 3 的网格。有多少可能的路径? +# +# 说明:m 和 n 的值均不超过 100。 +# +# 示例 1: +# +# 输入: m = 3, n = 2 +# 输出: 3 +# 解释: +# 从左上角开始,总共有 3 条路径可以到达右下角。 +# 1. 向右 -> 向右 -> 向下 +# 2. 向右 -> 向下 -> 向右 +# 3. 向下 -> 向右 -> 向右 +# +# +# 示例 2: +# +# 输入: m = 7, n = 3 +# 输出: 28 +# Related Topics 数组 动态规划 + +""" +1、 暴力递归 2^(m + n) 超时 +2、 递归记忆化 O(m * n), 空间O(m * n) +3、 DP O(m * n), 空间O(m * n) +4、 DP 优化 O(m * n), 空间O(m) or O(n) + +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + if m == 1 or n == 1: + return 1 + + return self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1) + + +dic = {} +class Solution2(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + if m == 1 or n == 1: + return 1 + if (m, n) not in dic: + dic[(m, n)] = self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1) + + return dic[(m, n)] + + +class Solution3(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + """ + DP: + a. 重复性 problem(i, j) = sub(i - 1, j) + sub(i, j - 1) + b. 定义状态数组 f[i, j] + c. DP方程 dp[i, j] = dp[i - 1, j] + dp[i, j - 1] + """ + dp = [[1 for _ in range(n)] for _ in range(m)] + for i in range(1, m): + for j in range(1, n): + dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + return dp[-1][-1] + +# dp 优化1 +class Solution4(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + pre = [1] * n + cur = [1] * n + for i in range(1, m): + for j in range(1, n): + cur[j] = pre[j] + cur[j - 1] + pre = cur[:] + return cur[-1] + +# dp 优化2 +class Solution5(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + cur = [1] * n + for i in range(1, m): + for j in range(1, n): + cur[j] += cur[j - 1] + return cur[-1] + + +if __name__ == '__main__': + s = Solution() + print(s.uniquePaths(2, 3)) + print(s.uniquePaths(3, 2)) + print(s.uniquePaths(7, 3)) + s = Solution2() + print(s.uniquePaths(2, 3)) + print(s.uniquePaths(3, 2)) + print(s.uniquePaths(7, 3)) + print(s.uniquePaths(28, 14)) + s = Solution3() + print(s.uniquePaths(2, 3)) + print(s.uniquePaths(3, 2)) + print(s.uniquePaths(7, 3)) + print(s.uniquePaths(28, 14)) + s = Solution4() + print(s.uniquePaths(2, 3)) + print(s.uniquePaths(3, 2)) + print(s.uniquePaths(7, 3)) + print(s.uniquePaths(28, 14)) diff --git a/Week 05/id_251/LeetCode_64_251.py b/Week 05/id_251/LeetCode_64_251.py new file mode 100644 index 000000000..ec840f492 --- /dev/null +++ b/Week 05/id_251/LeetCode_64_251.py @@ -0,0 +1,83 @@ +# 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 +# +# 说明:每次只能向下或者向右移动一步。 +# +# 示例: +# +# 输入: +# [ +#  [1,3,1], +# [1,5,1], +# [4,2,1] +# ] +# 输出: 7 +# 解释: 因为路径 1→3→1→1→1 的总和最小。 +# +# Related Topics 数组 动态规划 + +""" +1、 暴力递归 超时 +2、 DP O(m*n) 额外空间O(m*n) +3、 DP 优化 O(m*n) 不使用额外空间 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + m, n = len(grid) - 1, len(grid[0]) - 1 + return self.calculate(grid, m, n) + + def calculate(self, grid, m, n): + if m == 0: + return sum(grid[0][:n + 1]) + if n == 0: + return sum([i[0] for i in grid[:m + 1]]) + return grid[m][n] + min(self.calculate(grid, m - 1, n), self.calculate(grid, m, n - 1)) + + +class Solution2(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + """ + DP: + a. 重复性 problem(i, j) = grid(i,j) + min(sub(i - 1, j),sub(i, j - 1)) + b. 定义状态数组 f[i, j] + c. DP方程 dp[i, j] = grid[i,j] + min(dp[i - 1, j],dp[i, j - 1]) + """ + m, n = len(grid), len(grid[0]) + dp = [[0 for _ in range(n)] for _ in range(m)] + dp[0][0] = grid[0][0] + for i in range(1, n): + dp[0][i] = dp[0][i - 1] + grid[0][i] + for i in range(1, m): + dp[i][0] = dp[i - 1][0] + grid[i][0] + for i in range(1, m): + for j in range(1, n): + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] + return dp[-1][-1] + + +# 空间优化 +class Solution3(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + m, n = len(grid), len(grid[0]) + for i in range(1, n): + grid[0][i] += grid[0][i - 1] + for i in range(1, m): + grid[i][0] += grid[i - 1][0] + for i in range(1, m): + for j in range(1, n): + grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]) + return grid[-1][-1] diff --git a/Week 02/id_251/LeetCode_70_251.py b/Week 05/id_251/LeetCode_70_251.py similarity index 84% rename from Week 02/id_251/LeetCode_70_251.py rename to Week 05/id_251/LeetCode_70_251.py index 8b12af91a..6e411bb40 100644 --- a/Week 02/id_251/LeetCode_70_251.py +++ b/Week 05/id_251/LeetCode_70_251.py @@ -26,7 +26,7 @@ """ 1 朴素递归 (1) 递归终止条件 f(1) = 1, f(2) = 2; (2) 递归公式 f(n) = f(n - 1) + f(n - 2) 时间空间O(2^n) -2 递推公式 时间(1) 空间O(n) +2 递推公式 时间(1) 空间O(n) DP 3 递归 + 记忆化 空间时间O(n) """ @@ -47,7 +47,7 @@ def simple_recursion(self, n): return 2 return self.simple_recursion(n - 1) + self.simple_recursion(n - 2) - # 2 递推 + # 2 递推 DP def iteration(self, n): if n == 1: return 1 @@ -56,6 +56,15 @@ def iteration(self, n): second, first = first + second, second return second + # 2 递推 DP list DP:方程 F(N) = F(N-1) + F(N-2) + def iteration_DP(self, n): + if n == 1: + return 1 + dp = [1, 2] + [0] * (n - 2) + for i in range(2, n): + dp[i] = dp[i - 1] + dp[i - 2] + return dp[-1] + # 斐波那契 def iteration1(self, n): a, b = 0, 1 @@ -71,5 +80,3 @@ def memorization_recursion(self, n): if n not in self.dic: self.dic[n] = self.memorization_recursion(n - 1) + self.memorization_recursion(n - 2) return self.dic[n] - - # leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 05/id_251/\347\210\254\346\245\274\346\242\257\351\227\256\351\242\230\346\211\251\345\261\225.py" "b/Week 05/id_251/\347\210\254\346\245\274\346\242\257\351\227\256\351\242\230\346\211\251\345\261\225.py" new file mode 100644 index 000000000..b33805410 --- /dev/null +++ "b/Week 05/id_251/\347\210\254\346\245\274\346\242\257\351\227\256\351\242\230\346\211\251\345\261\225.py" @@ -0,0 +1,80 @@ +""" +一、可以走1、2、3步时,有几种情况 +f(1) = 1 +f(2) = f(1) + 1 = 2 +f(3) = f(1) + f(2) + 1 = 4 +DP 方程 +dp[n] = dp[n - 1] + dp[n - 2] + dp[n - 3] +""" + + +def climb_stairs_3(n): + dp = [1, 2, 4] + [0] * (n - 3) if n >= 3 else [1, 2, 4] + for i in range(3, n): + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3] + return dp[n - 1] + + +# 空间优化 +def climb_stairs_3_(n): + a, b, c = 0, 1, 1 + for _ in range(1, n): + c, b, a = a + b + c, c, b + return c + + +""" +二、可以走1、2、3步,且相邻两步不可相同,有几种情况 +DP +a、重复性 + problem(n, 1) = sub(n - 1, 2) + sub(n - 1, 3) + problem(n, 2) = sub(n - 2, 1) + sub(n - 2, 3) + problem(n, 3) = sub(n - 3, 1) + sub(n - 3, 2) + problem(n) = problem(n, 1) + problem(n, 2) + problem(n, 3) +""" + + +def climb_stairs_different(n): + dp = [[0] * 4 for _ in range(n + 1)] + dp[1][1] = 1 + dp[2][2] = 1 + dp[3][1], dp[3][2], dp[3][3] = 1, 1, 1 + for i in range(4, n + 1): + dp[i][1] = dp[i - 1][2] + dp[i - 1][3] + dp[i][2] = dp[i - 2][1] + dp[i - 2][3] + dp[i][3] = dp[i - 3][1] + dp[i - 3][2] + return dp[n][1] + dp[n][2] + dp[n][3] + + +# 空间优化 +def climb_stairs_different_(n): + if n <= 2: + return 1 + f11, f12, f13 = 1, 0, 0 + f21, f22, f23 = 0, 1, 0 + f31, f32, f33 = 1, 1, 1 + for _ in range(3, n): + # 4 + f31, f32, f33, f21, f22, f23, f11, f12, f13 = f32 + f33, f21 + f23, f11 + f12, f31, f32, f33, f21, f22, f23 + return f31 + f32 + f33 + + +if __name__ == '__main__': + print(climb_stairs_3(3)) + print(climb_stairs_3(4)) + print(climb_stairs_3(5)) + print(climb_stairs_3_(3)) + print(climb_stairs_3_(4)) + print(climb_stairs_3_(5)) + print(climb_stairs_different(3)) + print(climb_stairs_different(4)) + print(climb_stairs_different(5)) + print(climb_stairs_different(6)) + print(climb_stairs_different(7)) + print(climb_stairs_different(8)) + print(climb_stairs_different_(3)) + print(climb_stairs_different_(4)) + print(climb_stairs_different_(5)) + print(climb_stairs_different_(6)) + print(climb_stairs_different_(7)) + print(climb_stairs_different_(8)) diff --git a/Week 05/id_256/LeetCode_198_256.js b/Week 05/id_256/LeetCode_198_256.js new file mode 100644 index 000000000..de3351b79 --- /dev/null +++ b/Week 05/id_256/LeetCode_198_256.js @@ -0,0 +1,35 @@ +/* + * @lc app=leetcode.cn id=198 lang=javascript + * + * [198] 打家劫舍 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function(nums) { + // 方案一 不理解 + // let currMax = 0; + // let prevMax = 0; + // for(let key in nums) { + // let temp = currMax; + // currMax = Math.max(prevMax + nums[key], currMax); + // prevMax = temp; + // } + // return currMax; + + //DP + let len = nums.length; + if (len == 0) return 0; + let dp = new Array(len + 1); + dp[0] = 0; + dp[1] = nums[0]; + for (let i = 2; i <= len; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); + } + return dp[len]; + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 05/id_256/LeetCode_213_256.js b/Week 05/id_256/LeetCode_213_256.js new file mode 100644 index 000000000..cda5df153 --- /dev/null +++ b/Week 05/id_256/LeetCode_213_256.js @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=213 lang=javascript + * + * [213] 打家劫舍 II + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function(nums) { + //DP + var n = nums.length; + if(n == 1){ + return nums[0]; + }else if(n == 0){ + return 0; + } + function dpGO(nums){ + let dp = new Array(n); + dp[0] = 0; + dp[1] = nums[0]; + for (let i = 2; i < n; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); + } + return dp[n-1]; + } + var need1 = dpGO(nums.slice(1)); + var need2 = dpGO(nums.slice(0,nums.length-1)); + return Math.max(need1,need2); +}; +// @lc code=end + diff --git a/Week 05/id_256/LeetCode_62_256.js b/Week 05/id_256/LeetCode_62_256.js new file mode 100644 index 000000000..d537c5704 --- /dev/null +++ b/Week 05/id_256/LeetCode_62_256.js @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=62 lang=javascript + * + * [62] 不同路径 + */ + +// @lc code=start +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function(m, n) { + // 方法一二维递推 + // let arr = new Array(n); + // for (let i = 0; i < n; i++) { + // let m_arr = new Array(m); + // arr[i] = m_arr; + // } + // for (let i = 1; i <= n; i++) { + // for (let j = 1; j <= m; j++) { + // if (i == 1 || j == 1) { + // arr[n - i][m - j] = 1; + // } else { + // arr[n - i][m - j] = arr[n - i][m - j + 1] + arr[n - i + 1][m - j]; + // } + // } + // } + // return arr[0][0]; + // 方法二 一维递推 + let temp_arr = new Array(n); + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (i == 0 || j == 0) { + temp_arr[j] = 1; + } else { + temp_arr[j] = temp_arr[j] + temp_arr[j - 1]; + } + } + } + return temp_arr[n - 1]; +}; +// @lc code=end diff --git a/Week 05/id_256/LeetCode_63_256.js b/Week 05/id_256/LeetCode_63_256.js new file mode 100644 index 000000000..1251ad9f5 --- /dev/null +++ b/Week 05/id_256/LeetCode_63_256.js @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=63 lang=javascript + * + * [63] 不同路径 II + */ + +// @lc code=start +/** + * @param {number[][]} obstacleGrid + * @return {number} + */ +var uniquePathsWithObstacles = function(obstacleGrid) { + let R = obstacleGrid.length; + let C = obstacleGrid[0].length; + if (obstacleGrid[0][0] == 1) return 0; + obstacleGrid[0][0] = 1; + for (let i = 1; i < R; i++) { + obstacleGrid[i][0] = + obstacleGrid[i][0] == 0 && obstacleGrid[i - 1][0] == 1 ? 1 : 0; + } + for (let i = 1; i < C; i++) { + obstacleGrid[0][i] = + obstacleGrid[0][i] == 0 && obstacleGrid[0][i - 1] == 1 ? 1 : 0; + } + for (let i = 1; i < R; i++) { + for (let j = 1; j < C; j++) { + if (obstacleGrid[i][j] == 0) { + obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1]; + } else { + obstacleGrid[i][j] = 0; + } + } + } + return obstacleGrid[R - 1][C - 1]; +}; +// @lc code=end diff --git a/Week 05/id_256/LeetCode_647_256.js b/Week 05/id_256/LeetCode_647_256.js new file mode 100644 index 000000000..3cd15d14b --- /dev/null +++ b/Week 05/id_256/LeetCode_647_256.js @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=647 lang=javascript + * + * [647] 回文子串 + */ + +// @lc code=start +/** + * @param {string} s + * @return {number} + */ +var countSubstrings = function(s) { + //方案一 索引向外扩张法 + let count = 0; + function find(s, left, right) { + while(left >= 0 && right < s.length && s[left] == s[right]) { + count++; + left--; + right++; + } + } + for(let i = 0; i < s.length; i++) { + find(s, i, i); + find(s, i, i+1); + } + return count; + // 方案二 动态规划 (看不懂,暂放) + // let dp = Array.from({length: s.length}, _ => new Array(s.length).fill(0)); + // for (let i = s.length-1; i >= 0; i--) { + // for (let j = i; j < s.length; j++) { + // if (j == i) dp[i][j] = true; // 只有一个字符时 + // if (s[i] == s[j]) { // 两个及两个以上字符时 + // if (i+1 == j) { + // dp[i][j] = true; // 如果是两个字符 + // } else if (i < s.length-1 && dp[i+1][j-1]) dp[i][j] = true; // 如果更小的回文存在 + // }0 + // } + // } + // let count = 0; + // for (let i = s.length-1; i >= 0; i--) { + // for (let j = i; j < s.length; j++) { + // if (dp[i][j]) count++; + // } + // } + // return count; +}; +// @lc code=end + diff --git a/Week 05/id_256/LeetCode_64_256.js b/Week 05/id_256/LeetCode_64_256.js new file mode 100644 index 000000000..2b89f6ab0 --- /dev/null +++ b/Week 05/id_256/LeetCode_64_256.js @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=64 lang=javascript + * + * [64] 最小路径和 + */ + +// @lc code=start +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function(grid) { + //DP + let m = grid.length; + if (m == 0) return 0; + let n = grid[0].length; + if (n == 0) return 0; + for (let i = m - 1; i >= 0; i--) { + for (let j = n - 1; j >= 0; j--) { + if (i == m - 1 && j == n - 1) continue; + if (i == m - 1) { + grid[i][j] = grid[i][j] + grid[i][j + 1]; + continue; + } + if (j == n - 1) { + grid[i][j] = grid[i][j] + grid[i + 1][j]; + continue; + } + grid[i][j] = Math.min( + grid[i][j] + grid[i + 1][j], + grid[i][j] + grid[i][j + 1] + ); + } + } + return grid[0][0]; + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 05/id_276/LeetCode_53_276.java b/Week 05/id_276/LeetCode_53_276.java new file mode 100644 index 000000000..d75ac7dd5 --- /dev/null +++ b/Week 05/id_276/LeetCode_53_276.java @@ -0,0 +1,21 @@ +public class LeetCode_53_276 { +/* //重复性:f(i) = math(f(i-1), 0) + a[i] + public int maxSubArray(int[] nums) { + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + for (int i = 1; i < dp.length; ++i) + dp[i] = Math.max(dp[i-1], 0) + nums[i]; + int max = Integer.MIN_VALUE; + for (int i = 0; i< dp.length; ++i) if (dp[i] > max) max = dp[i]; + return max; + }*/ + public int maxSubArray(int[] nums) { + int max = nums[0]; + for (int i = 1; i < nums.length; ++i) { + nums[i] = Math.max(nums[i-1], 0) + nums[i]; + if (nums[i] > max) max = nums[i]; + } + return max; + } + +} diff --git a/Week 05/id_276/LeetCode_64_276.java b/Week 05/id_276/LeetCode_64_276.java new file mode 100644 index 000000000..74985e68a --- /dev/null +++ b/Week 05/id_276/LeetCode_64_276.java @@ -0,0 +1,24 @@ +public class LeetCode_64_276 { + public int minPathSum(int[][] grid) { + //重复性 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + int R = grid.length, C = grid[0].length; + for (int i = 0; i < R; ++ i) { + for (int j = 0; j < C; ++ j) { + if (i < 1 ) grid[i][j] += j < 1 ? 0 : grid[i][j-1]; + else if (j < 1 ) grid[i][j] += grid[i-1][j]; + else grid[i][j] = Math.min(grid[i-1][j], grid[i][j-1]) + grid[i][j]; + } + } + return grid[R-1][C-1]; + } + /*public int minPathSum(int[][] grid) { + //重复性 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + int R = grid.length, C = grid[0].length; + for (int i = 0; i < R; ++ i) { + for (int j = 0; j < C; ++ j) { + grid[i][j] = Math.min(i < 1 ? 0 :grid[i-1][j], j < 1 ? 0 : grid[i][j-1]) + grid[i][j]; + } + } + return grid[R-1][C-1];*/ + } +} diff --git a/Week 05/id_281/LeetCode_32_281.java b/Week 05/id_281/LeetCode_32_281.java new file mode 100644 index 000000000..45d7b2e31 --- /dev/null +++ b/Week 05/id_281/LeetCode_32_281.java @@ -0,0 +1,21 @@ +public class Solution { + + public int longestValidParentheses(String s) { + int maxans = 0; + Stack stack = new Stack<>(); + stack.push(-1); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + maxans = Math.max(maxans, i - stack.peek()); + } + } + } + return maxans; + } +} diff --git a/Week 05/id_281/LeetCode_64_281.java b/Week 05/id_281/LeetCode_64_281.java new file mode 100644 index 000000000..8bc0a5beb --- /dev/null +++ b/Week 05/id_281/LeetCode_64_281.java @@ -0,0 +1,15 @@ +public class Solution { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + return grid[0][0]; + } +} diff --git a/Week 05/id_286/LeetCode_1143_286.java b/Week 05/id_286/LeetCode_1143_286.java new file mode 100644 index 000000000..cd2228649 --- /dev/null +++ b/Week 05/id_286/LeetCode_1143_286.java @@ -0,0 +1,34 @@ +package com.uanei; + +public class LeetCode_1143_286 { + + public int longestCommonSubsequence(String text1, String text2) { + // 解题技巧:二维 -- 行列排列 + // [*,a,b,c,d] + // [c,*,*,*,*] + // [f,*,*,*,*] + // [e,*,*,*,*] + // [g,*,*,*,*] + + char[] s1 = text1.toCharArray(); + char[] s2 = text2.toCharArray(); + // 定义中间状态 + int[][] dp = new int[s1.length + 1][s2.length + 1]; + + for (int i = 1; i < s1.length + 1; i++) { + for (int j = 1; j < s2.length + 1; j++) { + // 如果最后一个字符相同,前边的子结果+1 + if (s1[i - 1] == s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } + // 如果最后一个字符不相同,去掉行或列的字符,求子结果 + else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + return dp[s1.length][s2.length]; + } + +} diff --git a/Week 05/id_286/LeetCode_120_286.java b/Week 05/id_286/LeetCode_120_286.java new file mode 100644 index 000000000..97392840e --- /dev/null +++ b/Week 05/id_286/LeetCode_120_286.java @@ -0,0 +1,25 @@ +package com.uanei; + +import java.util.List; + +public class LeetCode_120_286 { + + public int minimumTotal(List> triangle) { + // 此处是因为第i行的元素个数是i+1,所以需要加1 + int[] A = new int[triangle.size() + 1]; + // 自底向上,每一层都求出最小的结果 + for (int i = triangle.size() - 1; i >= 0; i--) { + // 对每一行的结果进行求解 + for (int j = 0; j < triangle.get(i).size(); j++) { + // 注意: A 数组是记录每一行的求解结果,所以最终顶部的结果就是A[0] + // 第一个 A[j] 是第 i,j 这个位置的结果 + // 第二个 A[j] 是下边一行中左边的结果 + // A[j+1] 是下边一行中右边哪个位置的结果 + // i,j 位置的结果 = 左角的结果和右角的结果的最小值 + i,j位置本身元素的值。 + A[j] = Math.min(A[j], A[j + 1]) + triangle.get(i).get(j); + } + } + return A[0]; + } + +} diff --git a/Week 05/id_286/LeetCode_198_286.java b/Week 05/id_286/LeetCode_198_286.java new file mode 100644 index 000000000..3394a9442 --- /dev/null +++ b/Week 05/id_286/LeetCode_198_286.java @@ -0,0 +1,51 @@ +package com.uanei; + +public class LeetCode_198_286 { + + public int rob(int[] nums) { + // 将一维数组变成二维数组 + // a[i][1|0] 0 表示要偷,1表示不偷 + if (nums == null || nums.length == 0) { + return 0; + } + + int n = nums.length; + int[][] a = new int[n][2]; + + a[0][0] = 0; // 不偷 + a[0][1] = nums[0]; // 要偷 + + for (int i = 1; i < n; i++) { + // i 不偷,则比较i-1偷和不偷的最大值 + a[i][0] = Math.max(a[i - 1][0], a[i - 1][1]); + // i 要偷,则 i-1 不能偷 + a[i][1] = a[i - 1][0] + nums[i]; + } + + return Math.max(a[n - 1][0], a[n - 1][1]); + } + + public int rob1(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } + + int n = nums.length; + int[] a = new int[n]; + + a[0] = nums[0]; + a[1] = Math.max(nums[0], nums[1]); + int res = Math.max(a[0], a[1]); + for (int i = 2; i < n; i++) { + // 第i天偷的结果 = i-1 不偷 或者 i-2 偷 + 第 i 天偷的金额 + a[i] = Math.max(a[i - 1] + 0, a[i - 2] + nums[i]); + res = Math.max(res, a[i]); + } + + return res; + } + +} diff --git a/Week 05/id_286/LeetCode_322_286.java b/Week 05/id_286/LeetCode_322_286.java new file mode 100644 index 000000000..cf76ba509 --- /dev/null +++ b/Week 05/id_286/LeetCode_322_286.java @@ -0,0 +1,51 @@ +package com.uanei; + +public class LeetCode_322_286 { + + public int coinChange(int[] coins, int amount) { + // f(s)= f(s-c)+1 表示对于金额s最少的硬币数 + // 其中c表示最后一枚硬币的面值,如果 s-c = 0,则 + 1 表示s的金额需要一枚硬币表示 + // 解法:自顶向下的动态规划 + if (amount < 1) return 0; + else return change(coins, amount, new int[amount]); + } + + // 分治子问题 + // 定义状态 + // dp方程 + + /** + * @param coins 硬币 + * @param rem 剩余金额 + * @param count + * @return + */ + private int change(int[] coins, int rem, int[] count) { + // 无法完整表示金额,所以返回-1 + if (rem < 0) return -1; + // 如果恰好能表示完金额,返回0 + if (rem == 0) return 0; + // 从历史记忆当中查看当前金额的表示结果 + // 因为int数组默认是0,所以如果不等于0,则说明有历史存储记录 + if (count[rem - 1] != 0) return count[rem - 1]; + + int min = Integer.MAX_VALUE; + for (int coin : coins) { + // 子结构继续递归 + int res = change(coins, rem - coin, count); + // 等于0,表示刚好能表示完金额 + // 大于0,则表示子结果能用res个硬币表示 + // 最后将子结果和当前存储的最小硬币数进行比较,如果res比历史最小硬币数还小,则更新最小结果 + if (res >= 0 && res < min) { + min = res + 1; + } + } + + // 存储当前金额的最小硬币数量 + count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min; + + // rem-1 是因为为了在数组中记忆金额,且数组长度为rem,则最大下标为rem-1 + return count[rem - 1]; + } + +} diff --git a/Week 05/id_286/LeetCode_53_286.java b/Week 05/id_286/LeetCode_53_286.java new file mode 100644 index 000000000..f3224b10c --- /dev/null +++ b/Week 05/id_286/LeetCode_53_286.java @@ -0,0 +1,23 @@ +package com.uanei; + +public class LeetCode_53_286 { + + public int maxSubArray(int[] nums) { + // 结果 = 要么自身最大,要么之前的结果加上自身最大 + int re = nums[0]; + int sum = 0; + for (int num : nums) { + // 大于0,则对结果有增益效果 + if (sum > 0) { + sum += num; + } else { + // 小于等于0,说明没有啥用了,直接将sum更新为当前遍历的元素 + sum = num; + } + // 无论是单个元素还是多个元素的和,最大的值已经保留到结果当中 + re = Math.max(re, sum); + } + return re; + } + +} diff --git a/Week 05/id_286/LeetCode_62_286.java b/Week 05/id_286/LeetCode_62_286.java new file mode 100644 index 000000000..fdcf380f9 --- /dev/null +++ b/Week 05/id_286/LeetCode_62_286.java @@ -0,0 +1,39 @@ +package com.uanei; + +public class LeetCode_62_286 { + + public int uniquePaths(int m, int n) { + // 递归 -- 自顶向下 + // 动态规划 -- 自底向上,从一个开始就推导结果和最优 + // dp[i][j] 表示第i,j的位置的有多少中结果 + int[][] dp = new int[m][n]; + // 初始化第一行为1 + for (int i = 0; i < n; i++) { + dp[0][i] = 1; + } + // 初始化第一列的所有行为1 + for (int i = 0; i < m; i++) { + dp[i][0] = 1; + } + + // 初始化结果如下 +// [x,x,x,x,x,1] +// [x,x,x,x,x,1] +// [x,x,x,x,x,1] +// [x,x,x,x,x,1] +// [x,x,x,x,x,1] +// [1,1,1,1,1,finish] + + // i = 1 是从右下角开始向上,第一行已经初始化了,不需要计算 + // 从计算第二行开始,列也是一样的,从第二列开始,即索引下标为 1 + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + // 指定节点的走法 = 下边格子的走法 + 右边格子的走法 + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + + return dp[m - 1][n - 1]; + } + +} diff --git a/Week 05/id_296/LeetCode_32_296.java b/Week 05/id_296/LeetCode_32_296.java new file mode 100644 index 000000000..fdf32da57 --- /dev/null +++ b/Week 05/id_296/LeetCode_32_296.java @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=32 lang=java + * + * [32] 最长有效括号 + */ + +// @lc code=start +class Solution { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + //右括号前边是左括号 + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + //右括号前边是右括号,并且除去前边的合法序列的前边是左括号 + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} +// @lc code=end + diff --git a/Week 05/id_296/LeetCode_64_296.java b/Week 05/id_296/LeetCode_64_296.java new file mode 100644 index 000000000..94e93db6d --- /dev/null +++ b/Week 05/id_296/LeetCode_64_296.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} +// @lc code=end + diff --git a/Week 05/id_306/CoinChange.java b/Week 05/id_306/CoinChange.java new file mode 100644 index 000000000..805b2273c --- /dev/null +++ b/Week 05/id_306/CoinChange.java @@ -0,0 +1,56 @@ +package sf.week5; + +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/11/18. + * 力扣题目地址:https://leetcode-cn.com/problems/coin-change/ + */ +public class CoinChange { + + /** + * dp 自下而上 + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + int max = amount + 1; + int[] dp = new int[amount + 1]; + Arrays.fill(dp, max); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.length; j++) { + if (coins[j] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } + + /** + * dp 自上而下 + * @param coins + * @param amount + * @return + */ + public int coinChange2(int[] coins, int amount) { + if (amount < 1) return 0; + return coinChange(coins, amount, new int[amount]); + } + + private int coinChange(int[] coins, int rem, int[] count) { + if (rem < 0) return -1; + if (rem == 0) return 0; + if (count[rem - 1] != 0) return count[rem - 1]; + int min = Integer.MAX_VALUE; + for (int coin : coins) { + int res = coinChange(coins, rem - coin, count); + if (res >= 0 && res < min) + min = 1 + res; + } + count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min; + return count[rem - 1]; + } +} diff --git a/Week 05/id_306/DecodeWays.java b/Week 05/id_306/DecodeWays.java new file mode 100644 index 000000000..b4435368d --- /dev/null +++ b/Week 05/id_306/DecodeWays.java @@ -0,0 +1,102 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/19. + * 力扣题目地址:https://leetcode-cn.com/problems/decode-ways/ + */ +public class DecodeWays { + /** + * dp 方法一空间占用较大 + * @param s + * @return + */ + public int numDecodings(String s) { + + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; //将递归法的结束条件初始化为 1 + //最后一个数字不等于 0 就初始化为 1 + if (s.charAt(len - 1) != '0') { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + //当前数字时 0 ,直接跳过,0 不代表任何字母 + if (s.charAt(i) == '0') { + continue; + } + int ans1 = dp[i + 1]; + //判断两个字母组成的数字是否小于等于 26 + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + + } + return dp[0]; + } + + /** + * dp 方法二 优化空间 + * @param s + * @return + */ + public int numDecodings1(String s) { + int len = s.length(); + int[] dp = new int[3]; + dp[len % 3] = 1; + if (s.charAt(len - 1) != '0') { + dp[(len - 1) % 3] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + dp[i % 3] = 0; //这里很重要,因为空间复用了,不要忘记归零 + continue; + } + int ans1 = dp[(i + 1) % 3]; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[(i + 2) % 3]; + } + dp[i % 3] = ans1 + ans2; + + } + return dp[0]; + } + + /** + * dp 方法二 再次优化空间 + * @param s + * @return + */ + public int numDecodings5(String s) { + int len = s.length(); + int end = 1; + int cur = 0; + if (s.charAt(len - 1) != '0') { + cur = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + end = cur;//end 前移 + cur = 0; + continue; + } + int ans1 = cur; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = end; + } + end = cur; //end 前移 + cur = ans1 + ans2; + + } + return cur; + } +} diff --git a/Week 05/id_306/EditDistance.java b/Week 05/id_306/EditDistance.java new file mode 100644 index 000000000..9730d30e5 --- /dev/null +++ b/Week 05/id_306/EditDistance.java @@ -0,0 +1,25 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/19. + * 力扣题目地址:https://leetcode-cn.com/problems/edit-distance/ + */ +public class EditDistance { + public int minDistance(String word1, String word2) { + int wLen1 = word1.length(); + int wLen2 = word2.length(); + int[][] dp = new int[wLen1 + 1][wLen2 + 1]; + // 第一行 + for (int j = 1; j <= wLen2; j++) dp[0][j] = dp[0][j - 1] + 1; + // 第一列 + for (int i = 1; i <= wLen1; i++) dp[i][0] = dp[i - 1][0] + 1; + + for (int i = 1; i <= wLen1; i++) { + for (int j = 1; j <= wLen2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1]; + else dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; + } + } + return dp[wLen1][wLen2]; + } +} diff --git a/Week 05/id_306/HouseRobber.java b/Week 05/id_306/HouseRobber.java new file mode 100644 index 000000000..48a29f6ff --- /dev/null +++ b/Week 05/id_306/HouseRobber.java @@ -0,0 +1,63 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/19. + * 力扣题目地址:https://leetcode-cn.com/problems/house-robber/ + */ +public class HouseRobber { + /** + * 打家劫舍 解法一 二维数组 + * @param nums + * @return + */ + public int rob(int[] nums) { + if(null==nums ||0==nums.length) + return 0; + int len = nums.length; + int [][]dp =new int[len][2]; + dp[0][0] = 0; + dp[0][1] = nums[0]; + for(int i = 1; i < len; i++) { + dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]); + dp[i][1] =dp[i-1][0]+nums[i]; + } + return Math.max(dp[len-1][0], dp[len-1][1]); + } + + /** + * 打家劫舍 解法二 一维数组 + * @param nums + * @return + */ + public int rob1(int[] nums) { + if(null==nums ||0==nums.length) + return 0; + if(1==nums.length) + return nums[0]; + int len = nums.length; + int[] dp = new int[len]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + int res=Math.max(dp[0], dp[1]); + for(int i = 2; i < len; i++) { + dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]); + res=Math.max(res, dp[i]); + } + return res; + } + + /** + * 打家劫舍 解法三 不用数组 + * @param nums + * @return + */ + public int rob2(int[] nums) { + int pre = 0, cur = 0, tmp; + for(int num : nums) { + tmp = cur; + cur = Math.max(pre + num, cur); + pre = tmp; + } + return cur; + } +} diff --git a/Week 05/id_306/LongestCommonSubsequence.java b/Week 05/id_306/LongestCommonSubsequence.java new file mode 100644 index 000000000..a43f875b5 --- /dev/null +++ b/Week 05/id_306/LongestCommonSubsequence.java @@ -0,0 +1,61 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/18. + * 力扣题目地址:https://leetcode-cn.com/problems/longest-common-subsequence/ + */ +public class LongestCommonSubsequence { + + /** + * 用二维数组的方式 + * @param text1 + * @param text2 + * @return + */ + public int longestCommonSubsequence(String text1, String text2) { + int n1 = text1.length(); + int n2 = text2.length(); + int[][] dp = new int[n1 + 1][n2 + 1]; + for (int i = 1; i <= n1; i++) { + for (int j = 1; j <= n2; j++) { + if (text1.charAt(i - 1) == text2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + 1; + else dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); + } + } + return dp[n1][n2]; + } + + /** + * 用一维数组的方式,有些地方还要仔细想想 + * @param text1 + * @param text2 + * @return + */ + public int longestCommonSubsequence2(String text1, String text2) { + if (text1 == null || text2 == null) return 0; + int len1 = text1.length(), len2 = text2.length(); + if (len1 == 0 || len2 == 0) return 0; + char[] colText, rowText; + if (len1 > len2) { + colText = text2.toCharArray(); + rowText = text1.toCharArray(); + } else { + colText = text1.toCharArray(); + rowText = text2.toCharArray(); + } + int[] dp = new int[colText.length + 1]; + for (int i = 1; i <= rowText.length; i++) { + int tmp = 0; + for (int j = 1; j <= colText.length; j++) { + int prev = tmp; + tmp = dp[j]; + if (rowText[i - 1] == colText[j - 1]) { + dp[j] = prev + 1; + } else { + dp[j] = Math.max(dp[j], dp[j - 1]); + } + } + } + return dp[colText.length]; + } +} diff --git a/Week 05/id_306/LongestParentheses.java b/Week 05/id_306/LongestParentheses.java new file mode 100644 index 000000000..aa901cb90 --- /dev/null +++ b/Week 05/id_306/LongestParentheses.java @@ -0,0 +1,67 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/19. + * 力扣题目地址:https://leetcode-cn.com/problems/edit-distance/ + */ +public class LongestParentheses { + + /** + * 动态规划 一维数组 + * @param s + * @return + */ + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + // 右括号前边是左括号 + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + // 右括号前边是右括号,并且除去前边的合法序列的前边是左括号 + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } + + /** + * 神奇的解法 看题解看到的 很有意思 + * https://leetcode-cn.com/problems/longest-valid-parentheses/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-7/ + * @param s + * @return + */ + public int longestValidParentheses2(String s) { + int left = 0, right = 0, maxlength = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * right); + } else if (right >= left) { + left = right = 0; + } + } + left = right = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * left); + } else if (left >= right) { + left = right = 0; + } + } + return maxlength; + } +} diff --git a/Week 05/id_306/MaximumProductSubarray.java b/Week 05/id_306/MaximumProductSubarray.java new file mode 100644 index 000000000..8882d2013 --- /dev/null +++ b/Week 05/id_306/MaximumProductSubarray.java @@ -0,0 +1,29 @@ +package sf.week5; + +/** + * Created by LynnSun on 2019/11/18. + * 力扣题目地址:https://leetcode-cn.com/problems/maximum-product-subarray/ + * + */ +public class MaximumProductSubarray { + /** + * 顺着和最大的思路想的,但是还是借鉴了最优秀的解法 + * @param nums + * @return + */ + public int maxProduct(int[] nums) { + int max = Integer.MIN_VALUE, imax = 1, imin = 1; + for(int i=0; i 0) { + sum += num; + } else { + sum = num; + } + ans = Math.max(ans, sum); + } + return ans; + } +} diff --git a/Week 05/id_306/Triangle.java b/Week 05/id_306/Triangle.java new file mode 100644 index 000000000..343a64d80 --- /dev/null +++ b/Week 05/id_306/Triangle.java @@ -0,0 +1,50 @@ +package sf.week5; + +import java.util.List; + +/** + * Created by LynnSun on 2019/11/18. + * 力扣题目地址:https://leetcode-cn.com/problems/triangle/ + */ +public class Triangle { + /** + * 自底向上,动态规划 + * @param triangle + * @return + */ + public int minimumTotal(List> triangle) { + int row = triangle.size(); + int[] minlen = new int[row+1]; + for (int level = row-1;level>=0;level--){ + for (int i = 0;i<=level;i++){ //第i行有i+1个数字 + minlen[i] = Math.min(minlen[i], minlen[i+1]) + triangle.get(level).get(i); + } + } + return minlen[0]; + } + + int row; + Integer[][] memo; + /** + * 记忆化搜索,自顶向下 + * @param triangle + * @return + */ + public int minimumTotal2(List> triangle) { + row = triangle.size(); + memo = new Integer[row][row]; + return helper(0,0, triangle); + } + private int helper(int level, int c, List> triangle){ + // System.out.println("helper: level="+ level+ " c=" + c); + if (memo[level][c]!=null) + return memo[level][c]; + if (level==row-1){ + return memo[level][c] = triangle.get(level).get(c); + } + int left = helper(level+1, c, triangle); + int right = helper(level+1, c+1, triangle); + return memo[level][c] = Math.min(left, right) + triangle.get(level).get(c); + } + +} diff --git a/Week 05/id_306/UniquePathsDP.java b/Week 05/id_306/UniquePathsDP.java new file mode 100644 index 000000000..19dfb941a --- /dev/null +++ b/Week 05/id_306/UniquePathsDP.java @@ -0,0 +1,44 @@ +package sf.week5; + +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/11/18. + * 力扣题目地址:https://leetcode-cn.com/problems/unique-paths/ + */ +public class UniquePathsDP { + /** + * 动态规划解法1 时间复杂度 O(m*n) + * @param m + * @param n + * @return + */ + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for (int i = 0; i < n; i++) dp[0][i] = 1; + for (int i = 0; i < m; i++) dp[i][0] = 1; + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + + /** + * 动态规划解法2 时间复杂度 O(m*n) 但空间复杂度比第一种解法低为 O(n) + * @param m + * @param n + * @return + */ + public int uniquePaths2(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]; + } +} diff --git a/Week 05/id_311/LeetCode_32_Solution.java b/Week 05/id_311/LeetCode_32_Solution.java new file mode 100644 index 000000000..f2228e0e8 --- /dev/null +++ b/Week 05/id_311/LeetCode_32_Solution.java @@ -0,0 +1,53 @@ +class Solution { + public int longestValidParentheses(String s) { + int left = 0; + int right = 0; + int maxLength = 0; + for(int i = 0; i < s.length(); i++){ + if(s.charAt(i) == '('){ + left++; + }else{ + right++; + } + if(left == right){ + maxLength = Math.max(maxLength, 2 * left); + }else if(right >= left){ + left = right = 0; + } + } + left = right = 0; + for(int i = s.length() - 1; i >= 0; i--){ + if(s.charAt(i) == '('){ + left++; + }else{ + right++; + } + if(left == right){ + maxLength = Math.max(maxLength, 2 * left); + }else if(left >= right){ + left = right = 0; + } + } + return maxLength; + } +} + + +class Solution { + public int longestValidParentheses(String s) { + int maxLength = 0; + int[] dp = new int[s.length()]; + for(int i = 1; i < s.length(); i++){ + if(s.charAt(i) == ')'){ + if(s.charAt(i - 1) == '('){ + dp[i] = (i >= 2? dp[i - 2] : 0) + 2; + }else if(i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] -1) == '('){ + dp[i] = (i - dp[i - 1] -2 > 0? dp[i - dp[i - 1] -2] : 0 ) + dp[i - 1] + 2; + } + } + maxLength = Math.max(maxLength, dp[i]); + + } + return maxLength; + } +} \ No newline at end of file diff --git a/Week 05/id_311/LeetCode_64_Solution.java b/Week 05/id_311/LeetCode_64_Solution.java new file mode 100644 index 000000000..e261f24a3 --- /dev/null +++ b/Week 05/id_311/LeetCode_64_Solution.java @@ -0,0 +1,16 @@ +class Solution { + public int minPathSum(int[][] grid) { + for(int i = grid.length - 1; i >= 0; i--){ + for(int j = grid[0].length - 1; j >= 0; j--){ + if(i == grid.length -1 && j != grid[0].length - 1){ + grid[i][j] = grid[i][j] + grid[i][j + 1]; + }else if(i != grid.length -1 && j == grid[0].length - 1){ + grid[i][j] = grid[i][j] + grid[i+1][j]; + }else if(i != grid.length -1 && j != grid[0].length - 1){ + grid[i][j] = grid[i][j] + Math.min(grid[i+1][j], grid[i][j + 1]); + } + } + } + return grid[0][0]; + } +} \ No newline at end of file diff --git a/Week 05/id_321/LeetCode_221_321.java b/Week 05/id_321/LeetCode_221_321.java new file mode 100644 index 000000000..d47c48faa --- /dev/null +++ b/Week 05/id_321/LeetCode_221_321.java @@ -0,0 +1,45 @@ +package week04; + +public class MaximalSquare221 { + + /* + * ̬滮 + */ + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } + + /* + * ̬滮ռŻ + */ + public int maximalSquare2(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[] dp = new int[cols + 1]; + int maxsqlen = 0, prev = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + int temp = dp[j]; + if (matrix[i - 1][j - 1] == '1') { + dp[j] = Math.min(Math.min(dp[j - 1], prev), dp[j]) + 1; + maxsqlen = Math.max(maxsqlen, dp[j]); + } else { + dp[j] = 0; + } + prev = temp; + } + } + return maxsqlen * maxsqlen; + } + +} diff --git a/Week 05/id_321/LeetCode_64_321.java b/Week 05/id_321/LeetCode_64_321.java new file mode 100644 index 000000000..caf8e3297 --- /dev/null +++ b/Week 05/id_321/LeetCode_64_321.java @@ -0,0 +1,63 @@ +package week04; + +public class MinPathSum64 { + /* + * ά鶯̬滮 ʱ临Ӷo(m*n) ռ临Ӷo(m*n) + */ + public class Solution { + public int minPathSum1(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + } + + /* + * һάռŻ + */ + public int minPathSum2(int[][] grid) { + int[] dp = new int[grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + dp[j] = grid[i][j] + dp[j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[j] = grid[i][j] + dp[j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]); + else + dp[j] = grid[i][j]; + } + } + return dp[0]; + } + + /* + * ҪĿռ + */ + public int minPathSum3(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j + 1]); + } + } + return grid[0][0]; + } + +} diff --git a/Week 05/id_321/LeetCode_72_321.java b/Week 05/id_321/LeetCode_72_321.java new file mode 100644 index 000000000..ce46552b2 --- /dev/null +++ b/Week 05/id_321/LeetCode_72_321.java @@ -0,0 +1,27 @@ +package week04; + +public class MinDistance72 { + // Ե + public int minDistance(String word1, String word2) { + int n1 = word1.length(); + int n2 = word2.length(); + int[][] dp = new int[n1 + 1][n2 + 1]; + // һ + for (int j = 1; j <= n2; j++) + dp[0][j] = dp[0][j - 1] + 1; + // һ + for (int i = 1; i <= n1; i++) + dp[i][0] = dp[i - 1][0] + 1; + + for (int i = 1; i <= n1; i++) { + for (int j = 1; j <= n2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) + dp[i][j] = dp[i - 1][j - 1]; + else + dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; + } + } + return dp[n1][n2]; + } + +} diff --git a/Week 05/id_321/LeetCode_91_321.java b/Week 05/id_321/LeetCode_91_321.java new file mode 100644 index 000000000..aa8548e3e --- /dev/null +++ b/Week 05/id_321/LeetCode_91_321.java @@ -0,0 +1,159 @@ +package week04; + +import java.util.HashMap; + +public class NumDecodings91 { + /* + * ⷨ1ݹ + */ + public int numDecodings1(String s) { + return getAns(s, 0); + } + + private int getAns(String s, int start) { + // ֵ󷵻 1 + if (start == s.length()) { + return 1; + } + // ͷ 0,0 Ӧκĸֱӷ 0 + if (s.charAt(start) == '0') { + return 0; + } + // õһֵĻֵĽ뷽ʽ + int ans1 = getAns(s, start + 1); + int ans2 = 0; + // жǰDzСڵ 26 + if (start < s.length() - 1) { + int ten = (s.charAt(start) - '0') * 10; + int one = s.charAt(start + 1) - '0'; + if (ten + one <= 26) { + ans2 = getAns(s, start + 2); + } + } + return ans1 + ans2; + } + + /* + * ⷨ2ⷨһĵݹУһЩѾĽ㣬ǿ memoization + * һܾͱ棬ڶʱֱóͿ + */ + public int numDecodings2(String s) { + HashMap memoization = new HashMap<>(); + return getAns(s, 0, memoization); + } + + private int getAns(String s, int start, HashMap memoization) { + if (start == s.length()) { + return 1; + } + if (s.charAt(start) == '0') { + return 0; + } + // ж֮ǰǷ + int m = memoization.getOrDefault(start, -1); + if (m != -1) { + return m; + } + int ans1 = getAns(s, start + 1, memoization); + int ans2 = 0; + if (start < s.length() - 1) { + int ten = (s.charAt(start) - '0') * 10; + int one = s.charAt(start + 1) - '0'; + if (ten + one <= 26) { + ans2 = getAns(s, start + 2, memoization); + } + } + // + memoization.put(start, ans1 + ans2); + return ans1 + ans2; + } + + /* + * ⷨ3̬滮 dp [ i ] = dp[ i + 1 ] + dp [ i + 2 ] + */ + public int numDecodings3(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; // ݹ鷨ĽʼΪ 1 + // һֲ 0 ͳʼΪ 1 + if (s.charAt(len - 1) != '0') { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + // ǰʱ 0 ֱ0 κĸ + if (s.charAt(i) == '0') { + continue; + } + int ans1 = dp[i + 1]; + // жĸɵǷСڵ 26 + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + + } + return dp[0]; + } + + /* + * ̬滮ռŻ + */ + public int numDecodings4(String s) { + int len = s.length(); + int[] dp = new int[3]; + dp[len % 3] = 1; + if (s.charAt(len - 1) != '0') { + dp[(len - 1) % 3] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + dp[i % 3] = 0; // ҪΪռ临ˣҪǹ + continue; + } + int ans1 = dp[(i + 1) % 3]; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[(i + 2) % 3]; + } + dp[i % 3] = ans1 + ans2; + + } + return dp[0]; + } + + /* + * ̬滮ռŻ + */ + public int numDecodings5(String s) { + int len = s.length(); + int end = 1; + int cur = 0; + if (s.charAt(len - 1) != '0') { + cur = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + end = cur;// end ǰ + cur = 0; + continue; + } + int ans1 = cur; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = end; + } + end = cur; // end ǰ + cur = ans1 + ans2; + + } + return cur; + } + +} diff --git a/Week 05/id_336/LeetCode_336_32.js b/Week 05/id_336/LeetCode_336_32.js new file mode 100644 index 000000000..26efafe52 --- /dev/null +++ b/Week 05/id_336/LeetCode_336_32.js @@ -0,0 +1,24 @@ +// #### 解法:动态规划 +/** + * @param {string} s + * @return {number} + */ +var longestValidParentheses = function(s) { + var max = 0; + var n = s.length; + var dp = new Array(n).fill(0); + for(var i = 1;i < n;i++){ + if(s[i] == ')'){ + // 右括号前边是左括号 + if(s[i-1] == '('){ + dp[i] = ( i >= 2 ? dp[i-2] : 0) + 2; + } + // 当前右括号前边是右括号,并且前一个合法子序列的前边是左括号和当前右括号组成一对,则最长子序列个数加2 + else if(i - dp[i-1] > 0 && s[i - dp[i-1] - 1] == '('){ + dp[i] = dp[i-1] + ( (i - dp[i-1] >= 2) ? dp[i - dp[i-1] - 2] : 0 ) + 2; + } + max = Math.max(max,dp[i]); + } + } + return max; +}; \ No newline at end of file diff --git a/Week 05/id_336/LeetCode_336_64.js b/Week 05/id_336/LeetCode_336_64.js new file mode 100644 index 000000000..154129b78 --- /dev/null +++ b/Week 05/id_336/LeetCode_336_64.js @@ -0,0 +1,24 @@ +// #### 解法:动态规划 +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function(grid) { + var n = grid.length; + var m = grid[0].length; + var dp = Array.from(new Array(n),() => new Array(m)); + for(var i = 0;i < n;i++){ + for(var j = 0;j < m;j++){ + if( i != 0 && j!= 0){ + dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j]; + }else if(i == 0 && j!=0){ + dp[i][j] = dp[i][j-1]+grid[i][j]; + }else if(i != 0 && j==0){ + dp[i][j] = dp[i-1][j]+grid[i][j]; + }else if(i == 0 && j==0){ + dp[i][j] = grid[i][j]; + } + } + } + return dp[n-1][m-1]; +}; \ No newline at end of file diff --git a/Week 05/id_346/LeetCode_32_346.java b/Week 05/id_346/LeetCode_32_346.java new file mode 100644 index 000000000..0bbab1d14 --- /dev/null +++ b/Week 05/id_346/LeetCode_32_346.java @@ -0,0 +1,51 @@ +package suanfa; + +import java.util.Stack; + +/** + * @auther: TKQ + * @Title: LeetCode_32_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-17 01:41 + */ +public class LeetCode_32_346 { + + + //栈 + public int longestValidParentheses(String s) { + Stack stack = new Stack(); + int max=0; + int left = -1; + for(int j=0;j= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} diff --git a/Week 05/id_346/LeetCode_64_346.java b/Week 05/id_346/LeetCode_64_346.java new file mode 100644 index 000000000..bf97bd7dc --- /dev/null +++ b/Week 05/id_346/LeetCode_64_346.java @@ -0,0 +1,25 @@ +package suanfa; + +/** + * @auther: TKQ + * @Title: LeetCode_64_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-17 02:02 + */ +public class LeetCode_64_346 { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + return grid[0][0]; + } +} diff --git a/Week 05/id_361/NOTE.md b/Week 05/id_361/NOTE.md index a6321d6e2..cd26ef0b4 100644 --- a/Week 05/id_361/NOTE.md +++ b/Week 05/id_361/NOTE.md @@ -1,4 +1,19 @@ -# NOTE - + +#### 动态规划核心 +动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构) +共性: 找到重复子问题->计算机指令集 +差异性:最优子结构、中途可以淘汰次优解 + +- 人肉递归效率低、很累 +- 找到最近最简方法,将其拆解成可重复解决的问题 +- 数学归纳法思维(抵制人肉递归的诱惑) + +#### 解题步骤 +分治(找子问题) +状态数组定义 +写DP方程 + + +[重点题目](https://leetcode-cn.com/problems/house-robber-ii/description/) diff --git a/Week 05/id_361/leetCode_32_361.js b/Week 05/id_361/leetCode_32_361.js new file mode 100644 index 000000000..e18eed669 --- /dev/null +++ b/Week 05/id_361/leetCode_32_361.js @@ -0,0 +1,92 @@ +/** + * @param {string} s + * @return {number} + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * 栈和取最优解 + */ +var longestValidParentheses = function(s) { + var max = 0; + var stack = [-1]; + for(var i = 0;i < s.length;i++){ + if(s[i] == '('){ + stack.push(i); + }else{ + stack.pop(); + if(stack.length == 0){ + stack.push(i); + }else{ + max = Math.max(max,i - stack[stack.length-1]); + } + } + } + return max; +}; + + +/** + * @param {string} s + * @return {number} + * 两边夹逼 直观法 + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +var longestValidParentheses = function(s) { + var max = 0; + var left = 0; + var right = 0; + for(var i = 0;i < s.length;i++){ + if(s[i] == '('){ + left++; + }else{ + right++; + } + if( left == right){ + max = Math.max(max,2 * left); + }else if(right > left){ + left = right = 0; + } + } + left = right = 0; + for(var i = s.length-1;i >= 0;i--){ + if(s[i] == '('){ + left++; + }else{ + right++; + } + if(left == right){ + max = Math.max(max,right * 2); + }else if(left > right){ + left = right = 0; + } + } + return max; +}; + + +/** + * @param {string} s + * @return {number} + * 动态规划 + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ +var longestValidParentheses = function(s) { + var max = 0; + var n = s.length; + var dp = new Array(n).fill(0); + for(var i = 1;i < n;i++){ + if(s[i] == ')'){ + // 右括号前边是左括号 + if(s[i-1] == '('){ + dp[i] = ( i >= 2 ? dp[i-2] : 0) + 2; + } + // 当前右括号前边是右括号,并且前一个合法子序列的前边是左括号和当前右括号组成一对,则最长子序列个数加2 + else if(i - dp[i-1] > 0 && s[i - dp[i-1] - 1] == '('){ + dp[i] = dp[i-1] + ( (i - dp[i-1] >= 2) ? dp[i - dp[i-1] - 2] : 0 ) + 2; + } + max = Math.max(max,dp[i]); + } + } + return max; +}; diff --git a/Week 05/id_361/leetCode_647_361.js b/Week 05/id_361/leetCode_647_361.js new file mode 100644 index 000000000..2b9d63fd8 --- /dev/null +++ b/Week 05/id_361/leetCode_647_361.js @@ -0,0 +1,45 @@ +/** + * @param {string} s + * @return {number} + */ +var countSubstrings = function(s) { + let count = 0; + function find(s, i, j) { + while (i >= 0 && j new Array(s.length).fill(0)); + for (let i = s.length-1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (j == i) dp[i][j] = true; // 只有一个字符时 + if (s[i] == s[j]) { // 两个及两个以上字符时 + if (i+1 == j) { + dp[i][j] = true; // 如果是两个字符 + } else if (i < s.length-1 && dp[i+1][j-1]) dp[i][j] = true; // 如果更小的回文存在 + } + } + } + let count = 0; + for (let i = s.length-1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (dp[i][j]) count++; + } + } + return count; +}; diff --git a/Week 05/id_361/leetCode_76_361.js b/Week 05/id_361/leetCode_76_361.js new file mode 100644 index 000000000..0287ffd82 --- /dev/null +++ b/Week 05/id_361/leetCode_76_361.js @@ -0,0 +1,66 @@ +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +var minWindow = function(s, t) { + if (s.length === 0 || t.length === 0) return ""; + let tMap = new Map(); // 目标子串t的辅助map,用于记录t中每个字符的出现次数 + // 对tMap进行初始化,记录每一个字符出现的次数 + for (let i = 0; i < t.length; i++) { + let char = t[i]; + if (tMap.has(char)) { + tMap.set(char, tMap.get(char) + 1); + } else { + tMap.set(char, 1); + } + } + + let windowMap = new Map(); // 滑动窗口的辅助map,用于记录当前滑动窗口中各个字符出现的次数 + let matchNum = 0; // 记录滑动窗口中对应字符匹配到t中字符的个数 + + let left = 0, right = 0; // 定义左右指针 + + let miniLength = -1, // 记录最小长度 + miniLeft = 0, // 长度最小是左指针下标 + miniRight = 0; // 长度最小时右指针下标 + + while (right < s.length) { + let char = s[right]; + // 对windowMap进行初始化 + if (windowMap.has(char)) { + windowMap.set(char, windowMap.get(char)+1); + } else { + windowMap.set(char, 1); + } + + // 如果某一个字符的次数匹配成功,则matchNum个数加1 + if (tMap.has(char) && windowMap.get(char) === tMap.get(char)) { + matchNum++ + } + + // 如果已匹配成功字符的个数等于tMap的长度,则说明当前滑动窗口中已经存在t + // 则对滑动窗口进行优化 + while (matchNum === tMap.size) { + char = s[left]; + // 只有当滑动窗口长度小于当前最小覆盖子串的长度时,才重新计算miniLeft和miniRight + // 第一次时需要计算 + if (miniLength === -1 || right - left + 1 < miniLength) { + miniLength = right- left + 1; + miniLeft = left; + miniRight = right; + } + + // 删除滑动窗口中的char,修改windowMap中char的个数 + windowMap.set(char, windowMap.get(char) - 1); + + // 如果当前字符的个数小于t中需求的个数,则匹配到的字符个数matchNum减1 + if (tMap.has(char) && windowMap.get(char) < tMap.get(char)) { + matchNum--; + } + left++; + } + right++; + } + return miniLength === -1 ? "" : s.substring(miniLeft, miniRight+1); +}; diff --git a/Week 05/id_366/Leetcode_32_366.java b/Week 05/id_366/Leetcode_32_366.java new file mode 100644 index 000000000..339cf3d98 --- /dev/null +++ b/Week 05/id_366/Leetcode_32_366.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=32 lang=java + * + * [32] 最长有效括号 + */ + +// @lc code=start +class Solution { + public int longestValidParentheses(String s) { + int max = 0; + Stack stack = new Stack(); + stack.push(-1); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + max = Math.max(max, i - stack.peek()); + } + } + } + return max; + } +} +// @lc code=end + diff --git a/Week 05/id_366/Leetcode_64_366.java b/Week 05/id_366/Leetcode_64_366.java new file mode 100644 index 000000000..59bf8cab5 --- /dev/null +++ b/Week 05/id_366/Leetcode_64_366.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + int[][] res = grid; + int i = 0; + int j = 0; + for (i = 0; i < grid.length; i++) { + for (j = 0; j < grid[0].length; j ++) { + if (i == 0 && j == 0) { + continue; + } else if (i == 0 && j > 0) { + res[i][j] = res[i][j - 1] + grid[i][j]; + } else if (i > 0 && j == 0) { + res[i][j] = res[i - 1][j] + grid[i][j]; + } else { + res[i][j] = Math.min(res[i - 1][j], res[i][j - 1]) + grid[i][j]; + } + } + } + return res[i - 1][j - 1]; + } +} +// @lc code=end + diff --git a/Week 05/id_366/Leetcode_72_366.java b/Week 05/id_366/Leetcode_72_366.java new file mode 100644 index 000000000..0d96efb07 --- /dev/null +++ b/Week 05/id_366/Leetcode_72_366.java @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=72 lang=java + * + * [72] 编辑距离 + */ + +// @lc code=start +class Solution { + public int minDistance(String word1, String word2) { + int column = word1.length(); + int row = word2.length(); + if (row == 0 || column ==0) return Math.max(row, column); + int[][] grid = new int[row + 1][column + 1]; + for (int j = 1; j <= column; j++ ) { + grid[0][j] = j; + } + for (int i = 1; i <= row; i++) { + grid[i][0] = i; + } + for (int i = 1; i < row + 1; i++) { + for (int j = 1; j < column +1; j++) { + if (word1.charAt(j - 1) == word2.charAt(i - 1)) { + //grid[i][j] = Math.min(Math.min(grid[i - 1][j], grid[i][j - 1]), grid[i - 1][j - 1]); + grid[i][j] = grid[i - 1][j - 1]; + } else { + grid[i][j] = Math.min(Math.min(grid[i - 1][j], grid[i][j - 1]), grid[i - 1][j - 1]) + 1; + } + } + } + return grid[row][column]; + } +} +// @lc code=end + diff --git a/Week 05/id_371/Leetcode_1143_371.java b/Week 05/id_371/Leetcode_1143_371.java new file mode 100644 index 000000000..eec73c409 --- /dev/null +++ b/Week 05/id_371/Leetcode_1143_371.java @@ -0,0 +1,44 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-12 10:32 + **/ + +public class Leetcode_1143_371 { + public static void main(String[] args) { + String text1 = "abcde", text2 = "ace"; + int i = longestCommonSubsequence(text1, text2); + System.out.println("i = " + i); + } + + /** + * 仿解1:动态规划(自顶向下) + * + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode-cn.com/problems/longest-common-subsequence/solution/chao-xiang-xi-dong-tai-gui-hua-jie-fa-by-shi-wei-h/ + */ + public static int longestCommonSubsequence(String text1, String text2) { + + int m = text1.length(); + int n = text2.length(); + char[] charArr1 = text1.toCharArray(); + char[] charArr2 = text2.toCharArray(); + + int[][] dp = new int[m + 1][n + 1]; + for (int i = 1; i < m + 1; i++) { + for (int j = 1; j < n + 1; j++) { + //保存并更新最优解(状态转移方程) + if (charArr1[i - 1] == charArr2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); + } + } + } + + return dp[m][n]; + } + +} diff --git a/Week 05/id_371/Leetcode_120_371.java b/Week 05/id_371/Leetcode_120_371.java new file mode 100644 index 000000000..7d4cf2e78 --- /dev/null +++ b/Week 05/id_371/Leetcode_120_371.java @@ -0,0 +1,109 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-12 15:45 + **/ + +public class Leetcode_120_371 { + + public static void main(String[] args) { + List> triangle = new ArrayList<>(); + triangle.add(Arrays.asList(2)); + triangle.add(Arrays.asList(3, 4)); + triangle.add(Arrays.asList(6, 5, 7)); + triangle.add(Arrays.asList(4, 1, 8, 3)); + int shortPath = minimumTotal3(triangle); + System.out.println("shortPath = " + shortPath); + } + + /** + * 仿解3:dP(自底向上) +去掉额外的缓存数组 + * + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode.com/problems/triangle/discuss/38730/DP-Solution-for-Triangle + */ + public static int minimumTotal3(List> triangle) { + int row = triangle.size(); + for (int level = row - 2; level >= 0; level--) { + for (int col = 0; col <= level; col++) { + //得到这一行与下一行相邻数的和的最小值 + int res = Math.min(triangle.get(level + 1).get(col), triangle.get(level + 1).get(col + 1)) + triangle.get(level).get(col); + triangle.get(level).set(col, res); + } + } + return triangle.get(0).get(0); + } + + /** + * 仿解2:dP(自底向上) + * + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode.com/problems/triangle/discuss/38730/DP-Solution-for-Triangle + * @link https://leetcode-cn.com/problems/triangle/solution/di-gui-ji-yi-hua-sou-suo-zai-dao-dp-by-crsm/ + */ + public static int minimumTotal2(List> triangle) { + int row = triangle.size(); + int[] dp = new int[row + 1]; + for (int level = row - 1; level >= 0; level--) { + for (int col = 0; col <= level; col++) { + dp[col] = Math.min(dp[col], dp[col + 1]) + triangle.get(level).get(col); + } + } + return dp[0]; + } + + /** + * 仿解1:DFS+记忆化数组 = 自顶向下的dp + * + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode-cn.com/problems/triangle/solution/di-gui-ji-yi-hua-sou-suo-zai-dao-dp-by-crsm/ + * @link https://leetcode.com/problems/triangle/discuss/159686/Java-Recursive-greaterTop-Down-greater-Bottom-up-greater-Bottom-Up-%2B-Optimal-Spacee + */ + public static int minimumTotal1(List> triangle) { + int row = triangle.size(); + //记忆化数组,因为相邻节点很多要重复计算 + Integer[][] memo = new Integer[row][row]; + + return recur(0, 0, row, triangle, memo); + } + + private static int recur(int level, int col, int row, List> triangle, Integer[][] memo) { + if (memo[level][col] != null) { + return memo[level][col]; + } + if (level == row - 1) { + return triangle.get(level).get(col); + } + int left = recur(level + 1, col, row, triangle, memo); + int right = recur(level + 1, col + 1, row, triangle, memo); + return memo[level][col] = Math.min(left, right) + triangle.get(level).get(col); + } + + /** + * 原解1:暴力(没考虑到:每一步只能移动到下一行中相邻的结点上。) + * + * @author Shaobo.Qian + * @date 2019/11/12 + */ + public static int minimumTotal(List> triangle) { + if (triangle == null || triangle.size() == 0) return 0; + int shortPath = 0; + for (int i = 0; i < triangle.size(); i++) { + int lineMin = Integer.MAX_VALUE; + List subList = triangle.get(i); + for (int j = 0; j < subList.size(); j++) { + lineMin = Math.min(lineMin, subList.get(j)); + } + shortPath += lineMin; + } + return shortPath; + } +} diff --git a/Week 05/id_371/Leetcode_121_371.java b/Week 05/id_371/Leetcode_121_371.java new file mode 100644 index 000000000..42871d19c --- /dev/null +++ b/Week 05/id_371/Leetcode_121_371.java @@ -0,0 +1,82 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 14:45 + **/ + +public class Leetcode_121_371 { + public static void main(String[] args) { + int[] prices = {7, 1, 5, 3, 6, 4}; + int res = maxProfit1(prices); + System.out.println("res = " + res); + } + /** + * 仿解2: dp+降维度(注意一下状态转移方程,新状态只和相邻的一个状态有关,其实不用整个 dp 数组,只需要一个变量储存相邻的那个状态就足够了,这样可以把空间复杂度降到 O(1)) + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int maxProfit2(int[] prices) { + int n = prices.length; + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE; + for (int i = 0; i < n; i++) { + //2.状态转移方程 + // (从 dp[i-1]->dp[i][0]是如何转移的)-->现实含义,以更高的价格卖出股票 + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + // (从 dp[i-1]->dp[i][1]是如何转移的) -->现实含义,以更低的价格买入股票 + dp_i_1 = Math.max(dp_i_1, -prices[i]); + } + return dp_i_0; + } + + /** + * 仿解1:dp + * + * @author Shaobo.Qian + * @date 2019/11/17 + * @link https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + */ + public static int maxProfit1(int[] prices) { + int n = prices.length; + if (n <= 1) return 0; + //1.定义需要维护的状态(如果状态之间相互影响,就需要同通过增加维度来表示) + //1.1需要维护天数,下面 for 循环中的i + //1.2需要维护是否持有 0:不持有 1:持有 + int[][] dp = new int[n][2]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + for (int i = 1; i < n; i++) { + //2.状态转移方程 + // (从 dp[i-1]->dp[i][0]是如何转移的)-->现实含义,以更高的价格卖出股票 + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); + // (从 dp[i-1]->dp[i][1]是如何转移的) -->现实含义,以更低的价格买入股票 + dp[i][1] = Math.max(dp[i - 1][1], -prices[i]); + } + return dp[n - 1][0]; + } + + /** + * 原解 dp(循环+记忆化-->自顶向下) -->未解除 + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public int maxProfit(int[] prices) { + //1.定义需要维护的状态(最大值索引要大于最小值索引) + //1.1 最小值索引 + int minIndex = 0; + int[] min = new int[]{}; + //1.2 最大值索引 + int maxIndex = 0; + + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[maxIndex]) { + maxIndex = i; + } else if (prices[i] < prices[maxIndex]) { + + } + } + return 0; + } +} diff --git a/Week 05/id_371/Leetcode_123_371.java b/Week 05/id_371/Leetcode_123_371.java new file mode 100644 index 000000000..1a4204c91 --- /dev/null +++ b/Week 05/id_371/Leetcode_123_371.java @@ -0,0 +1,65 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 17:48 + **/ + +public class Leetcode_123_371 { + public static void main(String[] args) { +// int[] prices = {3, 3, 5, 0, 0, 3, 1, 4}; +// int[] prices = {1,2,3,4,5}; + int[] prices = {7, 6, 4, 3, 1}; + int res = maxProfit(prices); + System.out.println("res = " + res); + } + + /** + * 仿解1:dp(自底向上) + * + * @author Shaobo.Qian + * @date 2019/11/21 + * @link https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + */ + public static int maxProfit(int[] prices) { + //1.需要维护的状态:天数,是否持有,交易次数 + //状态转移方程: + //dp[i][2][0] = Math.max(dp[i-1][2][0],dp[i-1][2][1]+price) ==>第二次卖出 + //dp[i][2][1] = Math.max(dp[i-1][2][1],dp[i-1][1][0]-price) ===>第二次买入,产生交易(k:1->2) + //dp[i][1][0] = Math.max(dp[i-1][1][0],dp[i-1][1][1]+price) ==>第一次卖出 + //dp[i][1][1] = Math.max(dp[i-1][1][1],dp[i-1][0][0]-price) ===>第一次买入,产生交易(k:0->1) + + //1.初始化状态变量 + int dp_i10 = 0;//1.1记录第一次卖出产生的收益 + int dp_i11 = Integer.MIN_VALUE;//1.2第一次为了持有产生的代价 + int dp_i20 = 0;//1.3记录第二次卖出产生的收益 + int dp_i21 = Integer.MIN_VALUE;//1.4第二次持有产生的代价 + //自顶向上,状态变换方程 + for (int price : prices) { + dp_i20 = Math.max(dp_i20, dp_i21 + price); + dp_i21 = Math.max(dp_i21, dp_i10 - price); + dp_i10 = Math.max(dp_i10, dp_i11 + price); + dp_i11 = Math.max(dp_i11, -price); + } + return dp_i20; + } +/* + public static int maxProfit(int[] prices) { + //1.需要维护的状态:天数,是否持有,交易次数 + //状态转移方程: + // dp[i][0] = Math.max(dp[i-1][0],dp[i-1][0] + prices[i]) + // dp[i][1] = Math.max(dp[i-1][1],dp[i-2][0] - prices[i] + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE; + int dp_pre_0 = 0; + for (int i = 0; i < prices.length; i++) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]); + dp_pre_0 = temp; + } + return dp_i_0; + } +*/ + +} diff --git a/Week 05/id_371/Leetcode_152_371.java b/Week 05/id_371/Leetcode_152_371.java new file mode 100644 index 000000000..865e3f933 --- /dev/null +++ b/Week 05/id_371/Leetcode_152_371.java @@ -0,0 +1,78 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-12 18:52 + **/ + +public class Leetcode_152_371 { + public static void main(String[] args) { + +// int[] nums = {2, 3, -2, 4};//2,3 ==>6 + int[] nums = {-2, 0, -1, 3, 4, -2, -5, -8, -3, -3, 10};//2,3 ==>6 + int ans = maxProduct1(nums); + System.out.println("ans = " + ans); + } + + /** + * 仿解1:dp + * + * @author Shaobo.Qian + * @date 2019/11/17 + * @link https://leetcode-cn.com/problems/maximum-product-subarray/solution/hua-jie-suan-fa-152-cheng-ji-zui-da-zi-xu-lie-by-g/ + */ + public static int maxProduct1(int[] nums) { + //1.确定需要维护的状态 + //1.1哪个节点作为终点的最大连续子乘积最大? + int max = Integer.MIN_VALUE; + //1.2当前节点为终点的最大连续子乘积 + int currMax = 1; + //1.3当前节点为终点的最小连续子乘积 + int currMin = 1; + //2.dp 方程(循环+记忆化) + for (int num : nums) { + if (num < 0) { + int temp = currMax; + currMax = currMin; + currMin = temp; + } + //3.子问题的解 + currMax = Math.max(num, currMax * num); + currMin = Math.min(num, currMin * num); + max = Math.max(max, currMax); + } + + return max; + } + + /** + * 原解1:dp(未解出) + * + * @author Shaobo.Qian + * @date 2019/11/12 + */ + public static int maxProduct(int[] nums) { + + int maxEndHere = nums[0]; + int maxSoFar = nums[0]; + for (int i = 1; i < nums.length; i++) { + + //最优子结构 + if (maxEndHere >= 0 && nums[i] < 0) { + if (i < nums.length - 1 && nums[i + 1] < 0) { + maxEndHere = maxEndHere * nums[i] * nums[i + 1]; + i++; + } else { + maxEndHere = nums[i]; + } + } else { + maxEndHere = Math.max(nums[i], maxEndHere * nums[i]); + } +// maxEndHere = Math.max(nums[i], maxEndHere * nums[i]); + //状态转移方程 + maxSoFar = Math.max(maxSoFar, maxEndHere); + } + + return maxSoFar; + } +} diff --git a/Week 05/id_371/Leetcode_188_371.java b/Week 05/id_371/Leetcode_188_371.java new file mode 100644 index 000000000..38a1c200d --- /dev/null +++ b/Week 05/id_371/Leetcode_188_371.java @@ -0,0 +1,71 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-21 19:10 + **/ + +public class Leetcode_188_371 { + + /** + * 仿解1:dp(自顶向上) + * + * @author Shaobo.Qian + * @date 2019/11/21 + * @link https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + * @question : 1.dp[i-2][0]-price,是正确的吗 临时变量 + */ + public int maxProfit(int max_k, int[] prices) { //k:交易的次数 + //dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+price) + //dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-price) + int n = prices.length; + if (max_k > n / 2) return maxProfit_k_inf(prices); + int[][][] dp = new int[n][max_k + 1][2]; //k+1,防止越界 k = 0 表示没有发生交易 + for (int i = 0; i < n; i++) { + for (int k = max_k; k >= 1; k--) { + if (i - 1 == -1) {// base case(说明处在第1天) + dp[i][k][0] = 0; + dp[i][k][1] = -prices[i]; //第一天持有的代价 + continue; + } + dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]); + dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]); + } + + } + return dp[n - 1][max_k][0]; + } + + private int maxProfit_k_inf(int[] prices) { + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE;//第0天持有的代价 + + for (int price : prices) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + price); + dp_i_1 = Math.max(dp_i_1, temp - price); + } + + return dp_i_0; + } + +/* + public int maxProfit(int k, int[] prices) { + //dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+price) + //dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-price) + + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE; + int dp_pre_0 = 0; + for (int i = 0; i < prices.length; i++) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]); + dp_pre_0 = temp; + } + + return dp_i_0; + } +*/ + +} diff --git a/Week 05/id_371/Leetcode_198_371.java b/Week 05/id_371/Leetcode_198_371.java new file mode 100644 index 000000000..5649175cf --- /dev/null +++ b/Week 05/id_371/Leetcode_198_371.java @@ -0,0 +1,57 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 11:04 + **/ + +public class Leetcode_198_371 { + + public static void main(String[] args) { + int[] nums = {2, 7, 9, 3, 1}; + int res = rob1(nums); + System.out.println("res = " + res); + + } + + /** + * 仿解1:dp 方程+自底向上 + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int rob1(int[] nums) { + int len = nums.length; + if (len == 0) return 0; + //1.建立 dp 方程 + int[] dp = new int[len + 1]; + dp[0] = 0; + dp[1] = nums[0]; + //2.自底向上 + for (int i = 2; i <= len; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]); + } + return dp[len]; + } + + /** + * 原解1:dp(未解出) + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int rob(int[] nums) { + //1.需要维护的状态 + //1.1 奇数节点和 + int oddSum = 0; + //1.2偶数节点和 + int evenSum = 0; + //2.循环+记忆化(自定向下) + for (int i = 0; i < nums.length; i++) { + //3.各部分子问题的解 + if (i % 2 == 0) oddSum += nums[i]; + else evenSum += nums[i]; + } + return Math.max(oddSum, evenSum); + } +} diff --git a/Week 05/id_371/Leetcode_213_371.java b/Week 05/id_371/Leetcode_213_371.java new file mode 100644 index 000000000..f10b5169f --- /dev/null +++ b/Week 05/id_371/Leetcode_213_371.java @@ -0,0 +1,44 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 11:54 + **/ + +public class Leetcode_213_371 { + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 1}; + int res = rob(nums); + System.out.println("res = " + res); + } + + /** + * 原解1:dp(自底向上) + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int rob(int[] nums) { + int len = nums.length; + if (len == 0) return 0; + if (len == 1) return nums[0]; + //1.定义需要维护的撞他提 + //1.1 需要维护的状态(1...n-1)-->子问题1:不包含最后一个元素的数组 + int[] dp = new int[len]; + dp[0] = 0; + dp[1] = nums[0]; + //1.2需要维护的状态 (2...n)-->子问题2:不包含第一个元素的数组 + int[] dp1 = new int[len]; + dp1[0] = 0; + dp1[1] = nums[1]; + //2.对子问题求解 + for (int i = 2; i < len; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]); + dp1[i] = Math.max(dp1[i - 2] + nums[i], dp1[i - 1]); + } + //3.合并结果 + return Math.max(dp[len - 1], dp1[len - 1]); + } + +} diff --git a/Week 05/id_371/Leetcode_221_371.java b/Week 05/id_371/Leetcode_221_371.java new file mode 100644 index 000000000..cf24a8671 --- /dev/null +++ b/Week 05/id_371/Leetcode_221_371.java @@ -0,0 +1,61 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-30 15:36 + **/ + +public class Leetcode_221_371 { + + /** + * 仿解1:dp:自顶向下(循环+记忆化) + * + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode-cn.com/problems/maximal-square/solution/zui-da-zheng-fang-xing-by-leetcode/ + */ + public int maximalSquare(char[][] matrix) { + //矩阵中当前1位置,最大正方形的边长 + //dp(i,j)=min(dp(i-1,j),dp(i,j-1),dp(i-1,j-1))+1 + + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1];//对 dp 的主动赋值是从 dp[1][1]开始的,方便根据 dp 方程计算 (dp[1][1]对应 matrix[0][0]),dp[1][1]开始,一直到 dp[rows][cols],所以 dp 的空间是 new int[rows + 1][cols + 1]; + int maxsqlen = 0;//最大正方形边长 + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i - 1][j - 1] == '1') { // matrix[i-1][j-1] :矩阵当前的单元格 + dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } + + /** + * 防解2:dp 空间优化(循环+记忆化) + * + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode-cn.com/problems/maximal-square/solution/zui-da-zheng-fang-xing-by-leetcode/ + */ + public int maximalSquare1(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[] dp = new int[cols + 1]; + int maxsqlen = 0; + int prev = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + int temp = dp[j];//上一个dp[j] + if (matrix[i - 1][j - 1] == '1') { + dp[j] = Math.min(Math.min(dp[j - 1], prev), dp[j]) + 1;//等式左边 dp[j]为当前层的 dp[j],等式右边为上一层的 dp[j] + maxsqlen = Math.max(maxsqlen, dp[j]); + } else { + dp[j] = 0; + } + prev = temp; + } + } + return maxsqlen * maxsqlen; + } +} diff --git a/Week 05/id_371/Leetcode_309_371.java b/Week 05/id_371/Leetcode_309_371.java new file mode 100644 index 000000000..957281b89 --- /dev/null +++ b/Week 05/id_371/Leetcode_309_371.java @@ -0,0 +1,26 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-22 06:38 + **/ + +public class Leetcode_309_371 { + + public int maxProfit(int[] prices) { + //dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+price) + //dp[i][1] = Math.max(dp[i-1][1],dp[i-2][0]-price) + + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE; + int dp_pre_0 = 0; + for (int i = 0; i < prices.length; i++) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]);//每次 sell 之后要等一天才能继续交易,第 i 天选择 buy 的时候,要从 i-2 的状态转移,而不是 i-1 ;即 dp[i-2][0]是持有的利润 - 今天的股票价格prices[i] + dp_pre_0 = temp; + } + return dp_i_0; + } + +} diff --git a/Week 05/id_371/Leetcode_32_371.java b/Week 05/id_371/Leetcode_32_371.java new file mode 100644 index 000000000..5e0649576 --- /dev/null +++ b/Week 05/id_371/Leetcode_32_371.java @@ -0,0 +1,87 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 21:33 + **/ + +public class Leetcode_32_371 { + public static void main(String[] args) { + +// String s = ")()())"; +// String s = "(()"; + String s = "()(())"; + System.out.println("s = " + longestValidParentheses1(s)); + + } + + + /** + * 仿解1: + * + * @author Shaobo.Qian + * @date 2019/11/17 + * @link https://leetcode.com/problems/longest-valid-parentheses/discuss/14278/Two-Java-solutions-with-explanation.-Stack-and-DP.-Short-and-easy-to-understand. + * @key 状态转移方程是如何推导出来的? + */ + public static int longestValidParentheses1(String s) { + int len = s.length(); + //1.定义需要维护的状态 + int[] dp = new int[len]; + int result = 0; + int leftCount = 0; + char[] chars = s.toCharArray(); + for (int i = 0; i < len; i++) { + if (chars[i] == '(') { + leftCount++; + } else if (leftCount > 0) { + dp[i] = dp[i - 1] + 2; + dp[i] += i - dp[i] >= 0 ? dp[i - dp[i]] : 0; + result = Math.max(result, dp[i]); + } + } + return result; + } + + /** + * 原解:dp (未解出) + * + * @author Shaobo.Qian + * @date 2019/11/17 + */ + public static int longestValidParentheses(String s) { + //1.定义需要维护的状态 + //1.1 最长有效字符长度 + int max = 0; + //1.2当前字符为终点的到上一个无效字符之间的最大有效字符长度 + int currMax = 0; + //1.3左括号的个数 + int leftCount = 0; + char[] chars = s.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '(') { + leftCount++; + } else { + if (leftCount == 0) { + currMax = 0; + } else { + currMax += 2; + leftCount--; + max = Math.max(max, currMax); + } + } + } + /* for (int i = 1; i < chars.length; i++) { + if (chars[i] == ')' && chars[i - 1] == '(') { + currMax += 2; + max = Math.max(max, currMax); + } else if (chars[i] == '(') { + continue; + } else { + currMax = 0; + } + }*/ + + return max; + } +} diff --git a/Week 05/id_371/Leetcode_363_371.java b/Week 05/id_371/Leetcode_363_371.java new file mode 100644 index 000000000..e0018f201 --- /dev/null +++ b/Week 05/id_371/Leetcode_363_371.java @@ -0,0 +1,52 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-01 15:13 + **/ + +public class Leetcode_363_371 { + + /** + * 防解1:暴力法 + * + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/comments/ + */ + public int maxSumSubmatrix(int[][] matrix, int k) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + + //1.从左上角起点(0,0)到当前点(row,col)的矩阵面积 + int[][] sum = new int[rows + 1][cols + 1]; + int res = Integer.MIN_VALUE;//k < 0 ,res是负值,所以初始化为Integer.MIN_VALUE + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + sum[i][j] = matrix[i - 1][j - 1] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]; + //2.每个矩阵内的子矩阵面积 + for (int l = 1; l <= i; l++) { + for (int m = 1; m <= j; m++) { + //子矩阵面积(画图比较好理解) + int subMatrixSum = sum[i][j] + sum[l - 1][m - 1] - sum[i][m - 1] - sum[l - 1][j]; + if (subMatrixSum <= k) { + res = Math.max(subMatrixSum, res); + } + } + } + + } + } + return res; + } + + /** + * 防解2:mergesort + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/discuss/83595/JAVA-117ms-beat-99.81-merge-sort + */ + public int maxSumSubmatrix1(int[][] matrix, int k) { + + return 0; + } +} diff --git a/Week 05/id_371/Leetcode_371_410.java b/Week 05/id_371/Leetcode_371_410.java new file mode 100644 index 000000000..cfa899820 --- /dev/null +++ b/Week 05/id_371/Leetcode_371_410.java @@ -0,0 +1,53 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-02 08:52 + **/ + +public class Leetcode_371_410 { + + public static void main(String[] args) { + + int[] nums = {7, 2, 5, 10, 8}; + int m = 2; + int res = splitArray(nums, 2); + System.out.println("res = " + res); + } + /** + * 防解1:二分查找 + * @author Shaobo.Qian + * @date 2019/12/2 + * @link https://leetcode-cn.com/problems/split-array-largest-sum/solution/er-fen-cha-zhao-by-coder233-2/ + * @anki 如何转换成二分查找问题的 + */ + public static int splitArray(int[] nums, int m) { + //1.确定数组和最小值和数组和最大值的范围 + long l = 0, h = 0; //h可能超出int最大值,用 long + for (int num : nums) { + h += num; + l = Math.max(l, num); + } + + while (l < h) { + //2.mid,寻找最合适数组和 + long mid = l + ((h - l) >> 1); + long temp = 0; + //cnt,被划分的子数组个数 + int cnt = 1;//初始值必须为1(因为在没有划分的时候是一整个数组) + for (int num : nums) { + temp += num; + if (temp > mid) { + ++cnt; + temp = num; + } + } + //cnt >m,说明选择的 mid 小了 + if (cnt > m) l = mid + 1; + //cnt <=m,说明选择的 mid 大了1 + else h = mid; + } + return (int) l; + } + +} diff --git a/Week 05/id_371/Leetcode_403_371.java b/Week 05/id_371/Leetcode_403_371.java new file mode 100644 index 000000000..5b8ef634c --- /dev/null +++ b/Week 05/id_371/Leetcode_403_371.java @@ -0,0 +1,81 @@ +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-01 17:54 + **/ + +public class Leetcode_403_371 { + public static void main(String[] args) { +// int[] stones = {0, 1, 2, 3, 4, 8, 9, 11}; + int[] stones = {0, 1, 3, 5, 6, 8, 12, 17}; + boolean can = canCross(stones); + System.out.println("can = " + can); + } + + /** + * 防解2:dfs + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode.com/problems/frog-jump/discuss/88804/JAVA-DFS-17ms-beat-99.28-so-far + */ + public static boolean canCross2(int[] stones) { + return false; + } + /** + * 防解1:循环+map + * + * @author Shaobo.Qian + * @date 2019/12/1 + * @link https://leetcode.com/problems/frog-jump/discuss/88824/Very-easy-to-understand-JAVA-solution-with-explanations + */ + public static boolean canCross1(int[] stones) { + if (stones.length == 0) return true; + //记录在每一个节点可以走的所有可能得的数 + Map> map = new HashMap<>(); + map.put(0, new HashSet()); + map.get(0).add(1); + int len = stones.length; + for (int i = 1; i < len; i++) { + map.put(stones[i], new HashSet<>()); + } + for (int i = 0; i < len; i++) { + int stone = stones[i]; + HashSet set = map.get(stone); + + for (Integer step : set) { + int reach = stone + step;//从当前 stone 位置走 step可以达到的位置 + if (reach == stones[len - 1]) return true; + HashSet nextSet = map.get(reach); + if (nextSet != null) {//说明能到达的位置有石头 + nextSet.add(step); + if(step-1>0) nextSet.add(step - 1); + nextSet.add(step + 1); + } + } + } + return false; + } + + /** + * 原解(未通过,没有看清题意) + * + * @author Shaobo.Qian + * @date 2019/12/1 + */ + public static boolean canCross(int[] stones) { + + //确定的上一部跳跃的单位 + int k = 1; + for (int i = 2; i < stones.length; i++) { + if (Math.abs(stones[i] - stones[i - 1] - k) > 1) return false; + k = stones[i] - stones[i - 1]; + } + + return true; + } +} diff --git a/Week 05/id_371/Leetcode_53_371.java b/Week 05/id_371/Leetcode_53_371.java new file mode 100644 index 000000000..5ad388dc0 --- /dev/null +++ b/Week 05/id_371/Leetcode_53_371.java @@ -0,0 +1,52 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-12 18:19 + **/ + +public class Leetcode_53_371 { + + public static void main(String[] args) { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};//4,-1,2,1 ==>6 + int ans = maxSubArray2(nums); + System.out.println("ans = " + ans); + } + + /** + * 仿解2:dp(更清楚的解释了dp的结构) + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode-cn.com/problems/maximum-subarray/solution/xiang-xi-jie-du-dong-tai-gui-hua-de-shi-xian-yi-li/ + */ + public static int maxSubArray2(int[] nums) { + int maxEndHere = nums[0]; + int maxSoFar = nums[0]; + for (int i = 1; i < nums.length; i++) { + //最佳子结构 + maxEndHere = Math.max(nums[i], maxEndHere + nums[i]); + //状态转移方程 + maxSoFar = Math.max(maxEndHere, maxSoFar); + } + return maxSoFar; + } + /** + * 仿解1:动态规划 + * @author Shaobo.Qian + * @date 2019/11/12 + * @link https://leetcode-cn.com/problems/maximum-subarray/solution/hua-jie-suan-fa-53-zui-da-zi-xu-he-by-guanpengchn/ + */ + public static int maxSubArray1(int[] nums) { + int ans = 0;//结果 + int sumed = 0;//当前最大子序列和 + for (int i = 0; i < nums.length; i++) { + if (sumed > 0) { // sumed>0对结果有增益,保留 + sumed += nums[i]; + } else { + sumed = nums[i]; //sumed<0对结果无增益,舍弃 + } + } + ans = Math.max(ans, sumed); + return ans; + } +} diff --git a/Week 05/id_371/Leetcode_64_371.java b/Week 05/id_371/Leetcode_64_371.java new file mode 100644 index 000000000..26629ed12 --- /dev/null +++ b/Week 05/id_371/Leetcode_64_371.java @@ -0,0 +1,34 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-17 22:46 + **/ + +public class Leetcode_64_371 { + public static void main(String[] args) { + + } + + /** + * 仿解1:dp-->自顶向下(循环+记忆化存储) + * + * @author Shaobo.Qian + * @date 2019/11/17 + * @link https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ + * @anki 1.dp 方程如何推导 2.如何降维度 + */ + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j == 0) continue; + else if (i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if (j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[m - 1][n - 1]; + } +} diff --git a/Week 05/id_371/Leetcode_714_371.java b/Week 05/id_371/Leetcode_714_371.java new file mode 100644 index 000000000..dc1afae7e --- /dev/null +++ b/Week 05/id_371/Leetcode_714_371.java @@ -0,0 +1,29 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-22 07:43 + **/ + +public class Leetcode_714_371 { + public static void main(String[] args) { + int[] prices = {1, 3, 2, 8, 4, 9}; + int fee = 2; + int res = maxProfit(prices, fee); + System.out.println("res = " + res); + } + + public static int maxProfit(int[] prices, int fee) { + //dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+price) + //dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-price-fee) + int dp_i_0 = 0; + int dp_i_1 = Integer.MIN_VALUE; + for (int i = 0; i < prices.length; i++) { + int temp = dp_i_0; + dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]); + dp_i_1 = Math.max(dp_i_1, temp - prices[i] - fee); + } + + return dp_i_0; + } +} diff --git a/Week 05/id_371/Leetcode_91_371.java b/Week 05/id_371/Leetcode_91_371.java new file mode 100644 index 000000000..c9f7a83aa --- /dev/null +++ b/Week 05/id_371/Leetcode_91_371.java @@ -0,0 +1,66 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-22 08:07 + **/ + +public class Leetcode_91_371 {//"01" ==>0 ("01"无法编码) + + /** + * 仿解1:dp-->自底向上(爬楼梯问题,每次可以爬1步也可以爬2步) + * + * @author Shaobo.Qian + * @date 2019/11/30 + * @link https://leetcode-cn.com/problems/decode-ways/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-3/ + */ + public int numDecodings(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; + if (s.charAt(len - 1) != '0') { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if(s.charAt(i) == '0') continue; + int ans1 = dp[i + 1]; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + int ans2 = 0; + if (ten + one <= 26) { + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + } + return dp[0]; + } + + /** + * 仿解2:优化空间 + * @author Shaobo.Qian + * @date 2019/11/30 + */ + public int numDecodings1(String s) { + int len = s.length(); + int end = 1;//初始化 + int cur = 0; + if(s.charAt(len-1) != '0') cur = 1; + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + end = cur; //end 前移(记录前面一层的解个数) + cur = 0; + continue; + } + int ans1 = cur; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = (s.charAt(i + 1) - '0'); + if (ten + one <= 26) ans2 = end; + end = cur;//end 前移(记录前面一层的解个数) + cur = ans1 + ans2; + + } + return cur; + } + +} diff --git a/Week 05/id_381/leetcode-32.py b/Week 05/id_381/leetcode-32.py new file mode 100644 index 000000000..9fda79b85 --- /dev/null +++ b/Week 05/id_381/leetcode-32.py @@ -0,0 +1,46 @@ +# leetcode 32 最长有效括号 + +# 第一种用栈 +class Solution: + def longestValidParentheses(self, s: str) -> int: + if not s: + return 0 + max_num = 0 + stack = [-1] # 哨兵,很重要 + for i in range(len(s)): + if s[i] == '(': + # 压入栈中去 + stack.append(i) + else: + # 先不管其他,先pop一个出去 + stack.pop() + # 如果pop后还有,那就表明')',是有'('匹配的,也就是上一步pop出来的是一个'(' + # 如果pop后stack=[],那就表明,没有'('匹配,也就是上衣步pop出来的是前面的哨兵,比如最开始压入的-1 + if stack: + # 能匹配上,那么最大长度就是当前的下表i-stack最后的一个值 + max_num = max(max_num, i-stack[-1]) + else: + # 不能匹配上,那么就从当前位置开始再重新计算 + stack.append(i) + return max_num + +# 第二种 动态规划 + +class Solution: + def longestValidParentheses(self, s: str) -> int: + max_num = 0 + dp = [0]*len(s) + for i in range(1, len(s)): + # 只需要判断为')' + if s[i] == ')': + # 分两种情况,两个子问题 + if s[i-1] == '(': + dp[i] = dp[i-2] + 2 if i > 1 else 2 + elif s[i-1] == ')': + j = i - dp[i-1] - 1 + # 需要判断是否>0 + if j >= 0: + if s[j] == '(': + dp[i] = dp[j-1] + dp[i-1] + 2 + max_num = max(dp[i], max_num) + return max_num diff --git a/Week 05/id_381/leetcode-64.py b/Week 05/id_381/leetcode-64.py new file mode 100644 index 000000000..8525c8bf9 --- /dev/null +++ b/Week 05/id_381/leetcode-64.py @@ -0,0 +1,19 @@ + +# leetcode 64 最小路径和 + +# 通过逆推得到最小路径 + +class Solution: + def minPathSum(self, grid) -> int: + x, y = len(grid)-1, len(grid[0])-1 + for i in range(x, -1, -1): + for j in range(y, -1, -1): + if i == x and j == y: + pass + elif i == x and j < y: + grid[i][j] = grid[i][j] + grid[i][j+1] + elif i < x and j == y: + grid[i][j] = grid[i][j] + grid[i+1][j] + else: + grid[i][j] = grid[i][j] + min(grid[i+1][j], grid[i][j+1]) + return grid[0][0] diff --git a/Week 05/id_386/LeetCode_647_386.java b/Week 05/id_386/LeetCode_647_386.java new file mode 100644 index 000000000..c0b07f532 --- /dev/null +++ b/Week 05/id_386/LeetCode_647_386.java @@ -0,0 +1,33 @@ +class Solution { + public int countSubstrings(String s) { + char[] arrays = s.toCharArray(); + int count = 0; + for (int i=0; i=0 && i+j < arrays.length) { + int left = arrays[i-j]; + int right = arrays[i+j]; + if (left == right) { + count++; + j++; + } else { + break; + } + } + + j = 0; + + while(i-j >=0 && i+1+j < arrays.length) { + int left = arrays[i-j]; + int right = arrays[i+1 + j]; + if (left == right) { + count++; + j++; + } else { + break; + } + } + } + return count; + } +} diff --git a/Week 05/id_386/LeetCode_91_386.java b/Week 05/id_386/LeetCode_91_386.java new file mode 100644 index 000000000..b7e67c6e7 --- /dev/null +++ b/Week 05/id_386/LeetCode_91_386.java @@ -0,0 +1,27 @@ +class Solution { + public int numDecodings(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; //将递归法的结束条件初始化为 1 + //最后一个数字不等于 0 就初始化为 1 + if (s.charAt(len - 1) != '0') { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + //当前数字时 0 ,直接跳过,0 不代表任何字母 + if (s.charAt(i) == '0') { + continue; + } + int ans1 = dp[i + 1]; + //判断两个字母组成的数字是否小于等于 26 + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + } + return dp[0]; + } +} diff --git a/Week 05/id_396/LeetCode_221_396.swift b/Week 05/id_396/LeetCode_221_396.swift new file mode 100644 index 000000000..28010ac0d --- /dev/null +++ b/Week 05/id_396/LeetCode_221_396.swift @@ -0,0 +1,33 @@ +// +// LeetCode_221_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit + +class Solution { + func maximalSquare(_ matrix: [[Character]]) -> Int { + // 求最大正方形,可以转为求最大正方形的边长 a[i][j] = min(a[i-1][j], a[i][j-1]) + // 状态 a[i][j] + // dp dp[i][j] = mix(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + // + if matrix.count == 0 { + return 0 + } + + var lenghts: [[Int]] = Array(repeating: Array(repeating: 0, count: matrix.last!.count+1), count: matrix.count+1) + var maxLenght = 0; + for i in 1...matrix.count { + let row = matrix[i-1] + for j in 1...row.count { + if matrix[i-1][j-1] == "1" { + lenghts[i][j] = min(min(lenghts[i-1][j], lenghts[i][j-1]), lenghts[i-1][j-1]) + 1 + maxLenght = maxLenght < lenghts[i][j] ? lenghts[i][j] : maxLenght + } + } + } + return maxLenght * maxLenght + } +} diff --git a/Week 05/id_396/LeetCode_64_396.swift b/Week 05/id_396/LeetCode_64_396.swift new file mode 100644 index 000000000..17e937264 --- /dev/null +++ b/Week 05/id_396/LeetCode_64_396.swift @@ -0,0 +1,36 @@ +// +// LeetCode_64_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit + +class Solution { + func minPathSum(_ grid: [[Int]]) -> Int { + if grid.count == 0 { + return 0 + } + // 找最的重复子问题 min[0,0] = min(min[0,1], min[1,0])。 + // 定义状态数组 a[i][j] + // DP方程 min[i][j] = mi(min[i][j-1], min[i-1][j]) + grid[i][j] + + var pathSum: [[Int]] = Array(repeating: Array(repeating: 0, count: grid.last!.count), count: grid.count) + for i in 0.. int: + if not matrix: return 0 + row = len(matrix) + col = len(matrix[0]) + dp = [[0] * (col + 1) for _ in range(row + 1)] + res = 0 + for i in range(1, row + 1): + for j in range(1, col + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i-1][j - 1], dp[i - 1][j], dp[i][j - 1] + 1) + res = max(res, dp[i][j] ** 2) + return res diff --git a/Week 05/id_406/Leetcode_32_406.py b/Week 05/id_406/Leetcode_32_406.py new file mode 100644 index 000000000..207dc7833 --- /dev/null +++ b/Week 05/id_406/Leetcode_32_406.py @@ -0,0 +1,16 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + if not s: + return 0 + res = 0 + stack = [-1] + for i in range(len(s)): + if s[i] == "(": + stack.append(i) + else: + stack.pop() + if not stack: + stack.append(i) + else: + res = max(res,i - stack[-1]) + return res diff --git a/Week 05/id_406/Leetcode_647_406.py b/Week 05/id_406/Leetcode_647_406.py new file mode 100644 index 000000000..700cb3a5b --- /dev/null +++ b/Week 05/id_406/Leetcode_647_406.py @@ -0,0 +1,26 @@ +class Solution: + def countSubstrings(self, s: str) -> int: + counts, count = [], 1 + for i in range(len(s)-1): + if s[i] == s[i+1]: + count += 1 + else: + counts.append((s[i], count)) + count = 1 + counts.append((s[-1], count)) + res = 0 + for i in range(len(counts)): + res += counts[i][1]*(counts[i][1]+1)//2 + j = 1 + while i-j >= 0 and i+j < len(counts): + left, right = counts[i-j], counts[i+j] + if left[0] == right[0]: + if left[1] != right[1]: + res += min(left[1], right[1]) + break + else: + res += left[1] + j += 1 + else: + break + return res diff --git a/Week 05/id_406/NOTE.md b/Week 05/id_406/NOTE.md index a6321d6e2..af708dd78 100644 --- a/Week 05/id_406/NOTE.md +++ b/Week 05/id_406/NOTE.md @@ -1,4 +1,64 @@ # NOTE +关键点 +动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构) +共性:找到重复子问题 +差异性:最优子结构、中途可以淘汰次优解 + + +状态转移方程(DP方程) +opt[i,j]=opt[i+1,j] + opt[i,j+1] +完整逻辑: +if a[i,j] = '空地': +opt[i,j] = opt[i + 1,j] + opt[i, j + 1] +else: +opt[i,j] = 0 + + + + +动态规划关键点 +1、最优子结构opt[n] = best_of(opt[n-1], opt[n-2], ...) +2、储存中间状态:opt[i] +3、递推公式(美其名曰:状态转移方程或者DP方程) +fib:opt[i] = opt[n-1] + opt[n-2] +二维路径:opt[i,j] = opt[i+1][j] + opt[i][j+1](且判断a[i,j]是否空地) + +动态规划小结 +1、打破自己的思维惯性,形成机器思维 +2、理解复杂逻辑的关键 +3、也是职业进阶的要点要领 + + + +DP分治 +a、重复性(分治) +b、定义状态数组 +c、DP方程 + +解题步骤: +1、暴力:n^2 +2、DP: +a、分治(子问题)max_sum(i) = Max(max_sum(i-1), 0) + a[i] +b、状态数组定义:r[i] +c、DP方程:f[i] = Max[f[i-1], 0] + a[i] + + + + + + + + + + + + + + + + + + diff --git a/Week 05/id_416/LeetCode_1143_416 b/Week 05/id_416/LeetCode_1143_416 new file mode 100644 index 000000000..3fc93e047 --- /dev/null +++ b/Week 05/id_416/LeetCode_1143_416 @@ -0,0 +1,51 @@ +/** + 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。 + + 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 + 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 + + 若这两个字符串没有公共子序列,则返回 0。 + +   + + 示例 1: + + 输入:text1 = "abcde", text2 = "ace" + 输出:3 + 解释:最长公共子序列是 "ace",它的长度为 3。 + 示例 2: + + 输入:text1 = "abc", text2 = "abc" + 输出:3 + 解释:最长公共子序列是 "abc",它的长度为 3。 + 示例 3: + + 输入:text1 = "abc", text2 = "def" + 输出:0 + 解释:两个字符串没有公共子序列,返回 0。 +   + + 提示: + + 1 <= text1.length <= 1000 + 1 <= text2.length <= 1000 + 输入的字符串只含有小写英文字符。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/longest-common-subsequence + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + public int longestCommonSubsequence(String text1, String text2) { + int n1 = text1.length(); + int n2 = text2.length(); + int[][] dp = new int[n1 + 1][n2 + 1]; + for(int i = 1;i<=n1;i++) { + for(int j = 1;j<=n2;j++) { + if(text1.charAt(i - 1) == text2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + 1; + else dp[i][j] = Math.max(dp[i][j - 1],dp[i - 1][j]); + } + } + return dp[n1][n2]; + } +} \ No newline at end of file diff --git a/Week 05/id_416/LeetCode_120_416 b/Week 05/id_416/LeetCode_120_416 new file mode 100644 index 000000000..3d690fa6f --- /dev/null +++ b/Week 05/id_416/LeetCode_120_416 @@ -0,0 +1,46 @@ +/** + 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + + 例如,给定三角形: + + [ + [2], + [3,4], + [6,5,7], + [4,1,8,3] + ] + 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + + 说明: + + 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/triangle + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + /** + * 解题思路 + * 1.寻找重复子问题subproblems problem[i][j] = Math.min(subproblem[j+1][j] + subproblem[i+1][j+1]) + * 2.寻找中间状态opt[i] + * 3.dp方程式,递归公式 f[i][j] = f[i+1][j] + */ + + int row = 0; + //自顶向下,递归 + public int minimumTotal(List> triangle) { + row = triangle.size(); + return helper(0,0,triangle); + } + public int helper(int i, int j,List> triangle) { + //terminator + if(level >= row - 1) { + return triangle.get(i).get(j); + } + //current logic,drill down + int left = helper(i + 1,j,triangle); + int right = helper(i + 1,j + 1,triangle); + return Math.min(left,right) + triangle.get(i).get(j); + } +} \ No newline at end of file diff --git a/Week 05/id_416/LeetCode_32_416 b/Week 05/id_416/LeetCode_32_416 new file mode 100644 index 000000000..bb4f82e1a --- /dev/null +++ b/Week 05/id_416/LeetCode_32_416 @@ -0,0 +1,36 @@ +/** + 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + + 示例 1: + + 输入: "(()" + 输出: 2 + 解释: 最长有效括号子串为 "()" + 示例 2: + + 输入: ")()())" + 输出: 4 + 解释: 最长有效括号子串为 "()()" + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/longest-valid-parentheses + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + public int longestValidParentheses(String s) { + if (s == null || s.length() == 0) return 0; + int[] dp = new int[s.length()]; + int res = 0; + for (int i = 0; i < s.length(); i++) { + if (i > 0 && s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i - 2 >= 0 ? dp[i - 2] + 2 : 2); + } else if (s.charAt(i - 1) == ')' && i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0); + } + } + res = Math.max(res, dp[i]); + } + return res; + } +} \ No newline at end of file diff --git a/Week 05/id_416/LeetCode_53_416 b/Week 05/id_416/LeetCode_53_416 new file mode 100644 index 000000000..a036a8245 --- /dev/null +++ b/Week 05/id_416/LeetCode_53_416 @@ -0,0 +1,31 @@ +/** + 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + + 示例: + + 输入: [-2,1,-3,4,-1,2,1,-5,4], + 输出: 6 + 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 + 进阶: + + 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/maximum-subarray + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + public int maxSubArray(int[] nums) { + int ans = nums[0]; + int sum = 0; + for(int i = 0;i 0) { + sum += nums[i]; + }else { + sum = nums[i]; + } + ans = Math.max(sum,ans); + } + return ans; + } +} \ No newline at end of file diff --git a/Week 05/id_416/LeetCode_62_416 b/Week 05/id_416/LeetCode_62_416 new file mode 100644 index 000000000..ad84190f6 --- /dev/null +++ b/Week 05/id_416/LeetCode_62_416 @@ -0,0 +1,70 @@ +/** + * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + * + * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + * + * 问总共有多少条不同的路径? + * + * + * + * 例如,上图是一个7 x 3 的网格。有多少可能的路径? + * + * 说明:m 和 n 的值均不超过 100。 + * + * 示例 1: + * + * 输入: m = 3, n = 2 + * 输出: 3 + * 解释: + * 从左上角开始,总共有 3 条路径可以到达右下角。 + * 1. 向右 -> 向右 -> 向下 + * 2. 向右 -> 向下 -> 向右 + * 3. 向下 -> 向右 -> 向右 + * 示例 2: + * + * 输入: m = 7, n = 3 + * 输出: 28 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/unique-paths + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + + //递归 + 优化搜索 + public int uniquePaths(int m, int n) { + int[][] nums = new int[m][n]; + return circle(m - 1,n - 1,nums); + } + + public int circle(int m,int n,int[][] nums){ + if(m == 0 || n == 0) return 1; + if( nums[m][n] == 0 ){ + nums[m][n] = circle(m - 1,n ,nums) + circle(m,n - 1,nums); + } + return nums[m][n]; + } + //动态规划 + public int uniquePaths(int m,int n){ + int[][] map = new int[m][n]; + for(int i = 0;i < m;i++) map[i][0] = 1; + for(int i = 0;i < n;i++) map[0][j] = 1; + for(int i = 1;i < m;i++){ + for(j = 1;j < n;j++){ + map[i][j] = map[i - 1][j] + map[i][j - 1]; + } + } + return map[m - 1][n - 1]; + } + //动态规划,极简版本 + public int uniquePaths(int m,int n){ + int[] dep = new int[n]; + dep[0] = 1; + for(int i = 0;i 向右 -> 向下 -> 向下 + * 2. 向下 -> 向下 -> 向右 -> 向右 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/unique-paths-ii + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + + //动态规划 + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int w = obstacleGrid[0].length; + int[] dep = new int[w]; + dep[0] = 1; + for(int [] row : obstacleGrid){ + for(int j = 0;j 0){ + dep[j] += dep[j - 1]; + } + } + } + return dep[w - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_416/LeetCode_64_416 b/Week 05/id_416/LeetCode_64_416 new file mode 100644 index 000000000..e7edff549 --- /dev/null +++ b/Week 05/id_416/LeetCode_64_416 @@ -0,0 +1,40 @@ +/** + 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + + 说明:每次只能向下或者向右移动一步。 + + 示例: + + 输入: + [ +   [1,3,1], + [1,5,1], + [4,2,1] + ] + 输出: 7 + 解释: 因为路径 1→3→1→1→1 的总和最小。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/minimum-path-sum + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LeetCode_62_416 { + public int minPathSum(int[][] grid) { + //自顶向下递归 + //1.重复子问题 F(i,j) = Math.min()F(i-1,j),F(i,j-1)); + //2.中间状态转移数组 F(i,j) 二维的 + //3.dp方程 F(i,j) = Math.min()F(i-1,j),F(i,j-1)); + int row = grid.length; + int col = grid[0].length; + int[][] dp = new int[row][col];//中间状态转移数组 + for(int i = 0;i < row;i++) { + for(int j = 0;j < col;j++) { + if(i == 0 && j==0) dp[i][j] = grid[i][j]; + if(i != 0 && j != 0) dp[i][j] = Math.min(dp[i - 1][j],dp[i][j - 1]) + grid[i][j]; + if(i == 0 && j != 0) dp[i][j] = dp[i][j - 1] + grid[i][j]; + if(i != 0 && j == 0) dp[i][j] = dp[i - 1][j] + grid[i][j]; + } + } + return dp[row - 1][col - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_431/LeetCode_1143_431.java b/Week 05/id_431/LeetCode_1143_431.java new file mode 100644 index 000000000..9cffa26f3 --- /dev/null +++ b/Week 05/id_431/LeetCode_1143_431.java @@ -0,0 +1,27 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/11 + */ +public class LongestCommonSubsequence { + public int longestCommonSubsequence(String text1, String text2) { + char[] text1Array = text1.toCharArray(); + char[] text2Array = text2.toCharArray(); + int m = text1Array.length; + int n = text2Array.length; + int[][] array = new int[m][n]; + // init + array[0][0] = text1Array[0] == text2Array[0] ? 1 : 0; + for (int i = 1; i < m; i++) array[i][0] = Math.max(array[i - 1][0], text1Array[i] == text2Array[0] ? 1 : 0); + for (int i = 1; i < n; i++) array[0][i] = Math.max(array[0][i - 1], text2Array[i] == text1Array[0] ? 1 : 0); + // dp + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + array[i][j] = Math.max(array[i - 1][j], array[i][j - 1]); + if (text1Array[i] == text2Array[j]) array[i][j] = Math.max(array[i - 1][j - 1] + 1, array[i][j]); + } + } + return array[m - 1][n - 1]; + } +} diff --git a/Week 05/id_431/LeetCode_120_431.java b/Week 05/id_431/LeetCode_120_431.java new file mode 100644 index 000000000..ce9046f55 --- /dev/null +++ b/Week 05/id_431/LeetCode_120_431.java @@ -0,0 +1,24 @@ +package medium; + +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/11 + */ +public class Triangle { + public int minimumTotal(List> triangle) { + int[] paths = new int[triangle.size()]; + if (paths.length == 1) return triangle.get(0).get(0); + //init + List list = triangle.get(triangle.size() - 1); + for (int i = 0; i < list.size(); i++) paths[i] = list.get(i); + for (int i = paths.length - 2; i >= 0; i--) { + List array = triangle.get(i); + for (int j = 0; j < array.size(); j++) { + paths[j] = Math.min(paths[j], paths[j + 1]) + triangle.get(i).get(j); + } + } + return paths[0]; + } +} diff --git a/Week 05/id_431/LeetCode_121_431.java b/Week 05/id_431/LeetCode_121_431.java new file mode 100644 index 000000000..ea6effdb2 --- /dev/null +++ b/Week 05/id_431/LeetCode_121_431.java @@ -0,0 +1,18 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/13 + */ +public class BestTimeToBuyAndSellStock { + public int maxProfit(int[] prices) { + int max = 0; + int fir = Integer.MAX_VALUE; + for (int i = 0; i < prices.length; i++) { + int tmp = prices[i] - fir; + max = Math.max(tmp, max); + fir = tmp > 0 ? fir : prices[i]; + } + return max; + } +} diff --git a/Week 05/id_431/LeetCode_123_431.java b/Week 05/id_431/LeetCode_123_431.java new file mode 100644 index 000000000..640b3845e --- /dev/null +++ b/Week 05/id_431/LeetCode_123_431.java @@ -0,0 +1,46 @@ +package hard; + +/** + * @author 潘磊明 + * @date 2019/11/13 + */ +public class BestTimetoBuyandSellStockIII { +// public int maxProfit(int[] prices) { +// if (prices.length == 0) return 0; +// /** +// * 状态方程,1维是天数,2维是买卖次数,3维是买卖状态 0买入1卖出 +// */ +// int[][][] dp = new int[prices.length][2][2]; +// dp[0][0][0] = -prices[0]; +// dp[0][0][1] = 0; +// dp[0][1][0] = Integer.MIN_VALUE; +// dp[0][1][1] = Integer.MIN_VALUE; +// for (int i = 1; i < prices.length; i++) { +// dp[i][0][0] = Math.max(dp[i - 1][0][0], -prices[i]); +// dp[i][0][1] = Math.max(dp[i - 1][0][0] + prices[i], dp[i - 1][0][1]); +// dp[i][1][0] = Math.max(dp[i - 1][0][1] - prices[i], dp[i - 1][1][0]); +// dp[i][1][1] = Math.max(dp[i - 1][1][0] + prices[i], dp[i - 1][1][1]); +// } +// return Math.max(dp[prices.length - 1][0][1], dp[prices.length - 1][1][1]); +// } + + /** + * 简化代码 + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices.length == 0) return 0; + int dp_i_0_0 = -prices[0]; + int dp_i_0_1 = 0; + int dp_i_1_0 = Integer.MIN_VALUE; + int dp_i_1_1 = Integer.MIN_VALUE; + for (int i = 1; i < prices.length; i++) { + dp_i_1_1 = Math.max(dp_i_1_1, dp_i_1_0 + prices[i]); + dp_i_1_0 = Math.max(dp_i_1_0, dp_i_0_1 - prices[i]); + dp_i_0_1 = Math.max(dp_i_0_1, dp_i_0_0 + prices[i]); + dp_i_0_0 = Math.max(dp_i_0_0, -prices[i]); + } + return Math.max(dp_i_0_1, dp_i_1_1); + } +} diff --git a/Week 05/id_431/LeetCode_152_431.java b/Week 05/id_431/LeetCode_152_431.java new file mode 100644 index 000000000..223761cbf --- /dev/null +++ b/Week 05/id_431/LeetCode_152_431.java @@ -0,0 +1,26 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/12 + */ +public class MaximumProductSubarray { + public int maxProduct(int[] nums) { + int max = nums[0]; + int[] minNums = new int[nums.length]; + int[] maxNums = new int[nums.length]; + minNums[0] = nums[0]; + maxNums[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + if (nums[i] < 0) { + minNums[i] = Math.min(nums[i] * maxNums[i - 1], nums[i]); + maxNums[i] = Math.max(nums[i] * minNums[i - 1], nums[i]); + }else { + minNums[i] = Math.min(nums[i] * minNums[i - 1], nums[i]); + maxNums[i] = Math.max(nums[i] * maxNums[i - 1], nums[i]); + } + max = Math.max(max, maxNums[i]); + } + return max; + } +} diff --git a/Week 05/id_431/LeetCode_188_431.java b/Week 05/id_431/LeetCode_188_431.java new file mode 100644 index 000000000..633348201 --- /dev/null +++ b/Week 05/id_431/LeetCode_188_431.java @@ -0,0 +1,71 @@ +package hard; + +/** + * @author 潘磊明 + * @date 2019/11/14 + */ +public class BestTimeToBuyAndSellStockIV { + /** + * 状态方程 一维天数,二维次数,三维买入卖出 + * @param k + * @param prices + * @return + */ +// public int maxProfit(int k, int[] prices) { +// if (prices.length == 0 || prices.length == 1 || k == 0) return 0; +// if (k > prices.length / 2) return _maxProfit(prices); +// int[][][] dp = new int[prices.length][k][2]; +// // init +// for (int i = 0; i < k; i++) { +// dp[0][i][0] = -prices[0]; +// dp[0][i][1] = 0; +// } +// for (int i = 1; i < prices.length; i++) { +// for (int j = k - 1; j>=0; j--) { +// if (j == 0) { +// dp[i][0][0] = Math.max(dp[i - 1][0][0], -prices[i]); +// dp[i][0][1] = Math.max(dp[i - 1][0][1], dp[i - 1][0][0] + prices[i]); +// }else { +// dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j - 1][1] - prices[i]); +// dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j][0] + prices[i]); +// } +// } +// } +// return dp[prices.length - 1][k - 1][1]; +// } + + public int maxProfit(int k, int[] prices) { + if (prices.length == 0 || prices.length == 1 || k == 0) return 0; + if (k > prices.length / 2) return _maxProfit(prices); + int[][] dp = new int[k][2]; + for (int i = 0; i < k; i++) { + dp[i][0] = -prices[0]; + dp[i][1] = 0; + } + int tmp;//记录前一天卖出的最大值 + for (int i = 1; i < prices.length; i++) { + for (int j = 0; j < k; j++) { + if (j == 0) { + dp[j][1] = Math.max(dp[j][1], dp[j][0] + prices[i]); + dp[j][0] = Math.max(dp[j][0], -prices[i]); + continue; + } + tmp = dp[j - 1][1]; + dp[j][1] = Math.max(dp[j][1], dp[j][0] + prices[i]); + dp[j][0] = Math.max(dp[j][0], tmp - prices[i]); + } + } + return dp[k - 1][1]; + } + + private int _maxProfit(int[] prices) { + int dp_0_0 = -prices[0]; + int dp_0_1 = 0; + for (int i = 1; i < prices.length; i++) { + int tmp = dp_0_1; + dp_0_1 = Math.max(dp_0_1, dp_0_0 + prices[i]); + dp_0_0 = Math.max(dp_0_0, tmp - prices[i]); + } + return dp_0_1; + } +} diff --git a/Week 05/id_431/LeetCode_198_431.java b/Week 05/id_431/LeetCode_198_431.java new file mode 100644 index 000000000..24783a073 --- /dev/null +++ b/Week 05/id_431/LeetCode_198_431.java @@ -0,0 +1,21 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/12 + */ +public class HouseRobber { + public int rob(int[] nums) { + if (nums.length == 0) return 0; + //状态变量 1为偷 0为不偷 + int[][] dp = new int[nums.length][2]; + dp[0][0] = 0; + dp[0][1] = nums[0]; + //dp方程 + for (int i = 1; i < nums.length; i++) { + dp[i][0] = Math.max(dp[i - 1][1], dp[i - 1][0]); + dp[i][1] = dp[i - 1][0] + nums[i]; + } + return Math.max(dp[nums.length - 1][1], dp[nums.length - 1][0]); + } +} diff --git a/Week 05/id_431/LeetCode_213_431.java b/Week 05/id_431/LeetCode_213_431.java new file mode 100644 index 000000000..27973518e --- /dev/null +++ b/Week 05/id_431/LeetCode_213_431.java @@ -0,0 +1,26 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/13 + */ +public class HouseRobberII { + public int rob(int[] nums) { + if (nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + int max = 0, fir = 0, sec = 0; + for (int i = 0; i < nums.length - 1; i++) { + max = Math.max(sec, fir + nums[i]); + fir = sec; + sec = max; + } + int max1 = 0; + fir = 0; sec = 0; + for (int i = 1; i < nums.length; i++) { + max1 = Math.max(sec, fir + nums[i]); + fir = sec; + sec = max1; + } + return Math.max(max, max1); + } +} diff --git a/Week 05/id_431/LeetCode_221_431.java b/Week 05/id_431/LeetCode_221_431.java new file mode 100644 index 000000000..b6c9b580d --- /dev/null +++ b/Week 05/id_431/LeetCode_221_431.java @@ -0,0 +1,24 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/19 + */ +public class MaximalSquare { + public int maximalSquare(char[][] matrix) { + if (matrix.length == 0) return 0; + int x = matrix.length; + int y = matrix[0].length; + int max = 0; + int[][] dp = new int[x + 1][y + 1]; + for (int i = 1; i <= x; i++) { + for (int j = 1; j <= y; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1; + max = Math.max(dp[i][j], max); + } + } + } + return max * max; + } +} diff --git a/Week 05/id_431/LeetCode_309_431.java b/Week 05/id_431/LeetCode_309_431.java new file mode 100644 index 000000000..e3b048d79 --- /dev/null +++ b/Week 05/id_431/LeetCode_309_431.java @@ -0,0 +1,48 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/14 + */ +public class BestTimeToBuyAndSellStockWithCooldown { + /** + * 状态定义: 1维代表天数,2维代表买入,卖出 + * @param prices + * @return + */ +// public int maxProfit(int[] prices) { +// if (prices.length == 0 || prices.length == 1) return 0; +// int[][] dp = new int[prices.length][2]; +// //After you sell your stock, you cannot buy stock on next day +// dp[0][0] = -prices[0]; +// dp[0][1] = 0; +// dp[1][0] = Math.max(dp[0][0], -prices[1]); +// dp[1][1] = Math.max(dp[0][1], dp[0][0] + prices[1]); +// for (int i = 2; i < prices.length; i++) { +// dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][1] - prices[i]); +// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]); +// } +// return dp[prices.length - 1][1]; +// } + + /** + * 简化代码 + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices.length == 0 || prices.length == 1) return 0; + int dp_0_0 = -prices[0]; + int dp_0_1 = 0; + int dp_1_0 = Math.max(dp_0_0, -prices[1]); + int dp_1_1 = Math.max(dp_0_1, dp_0_0 + prices[1]); + for (int i = 2; i < prices.length; i++) { + int tmp2 = dp_0_1; + dp_0_0 = dp_1_0; + dp_0_1 = dp_1_1; + dp_1_0 = Math.max(dp_0_0, tmp2 - prices[i]); + dp_1_1 = Math.max(dp_1_1, dp_0_0 + prices[i]); + } + return dp_1_1; + } +} diff --git a/Week 05/id_431/LeetCode_322_431.java b/Week 05/id_431/LeetCode_322_431.java new file mode 100644 index 000000000..af40ec01f --- /dev/null +++ b/Week 05/id_431/LeetCode_322_431.java @@ -0,0 +1,30 @@ +package medium; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/12 + */ +public class CoinChange { + /** + * 使用递归方程 + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int j = coins.length - 1; j >= 0; j--) { + if (coins[j] <= i) + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } +} diff --git a/Week 05/id_431/LeetCode_32_431.java b/Week 05/id_431/LeetCode_32_431.java new file mode 100644 index 000000000..50f126684 --- /dev/null +++ b/Week 05/id_431/LeetCode_32_431.java @@ -0,0 +1,68 @@ +package hard; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * @author 潘磊明 + * @date 2019/11/15 + */ +public class LongestValidParentheses { + +// public int longestValidParentheses(String s) { +// if (s.length() <= 1) return 0; +// /** +// * 状态方程,存储当前有效括号的最大距离 +// */ +// int[] dp = new int[s.length()]; +// char[] array = s.toCharArray(); +// int max = 0; +// dp[0] = 0; +// for (int i = 1; i < array.length; i++) { +// if (array[i] == ')') { +// if (array[i - 1] == '(') { +// dp[i] = i >= 2 ? dp[i] = dp[i - 2] + 2 : 2; +// }else { +// if (i - dp[i - 1] - 1 >= 0 +// && array[i - dp[i - 1] - 1] == '(') { +// //还需判断前面的有效括号能不能组合在一起,例如()(()) +// dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 > 0 ? dp[i - dp[i - 1] - 2] : 0); +// } +// } +// max = Math.max(max, dp[i]); +// } +// } +// return max; +// } + + /** + * 使用栈 + * @param s + * @return + */ + public int longestValidParentheses(String s) { + Deque deque = new LinkedList<>(); + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + if (arr[i] == ')' && !deque.isEmpty() && arr[deque.getFirst()] == '(') { + deque.removeFirst(); + } else { + deque.addFirst(i); + } + } + if (deque.isEmpty()) return s.length(); + int a = s.length() - 1, max = 0; + while (!deque.isEmpty()) { + int tmp = deque.removeFirst(); + max = Math.max(a - tmp, max); + a = tmp - 1; + } + max = Math.max(a, max); + return max; + } + + public static void main(String[] args) { + LongestValidParentheses l = new LongestValidParentheses(); + l.longestValidParentheses("(()"); + } +} diff --git a/Week 05/id_431/LeetCode_62_431.java b/Week 05/id_431/LeetCode_62_431.java new file mode 100644 index 000000000..4659aec14 --- /dev/null +++ b/Week 05/id_431/LeetCode_62_431.java @@ -0,0 +1,39 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/11 + */ +public class UniquePaths { +// public int uniquePaths(int m, int n) { +// int[][] paths = new int[m][n]; +// // init path +// for (int i = 0; i < m; i++) paths[i][0] = 1; +// for (int i = 0; i < n; i++) paths[0][i] = 1; +// // 动态规划方程 +// for (int i = 1; i < m; i++) { +// for (int j = 1; j < n; j++) { +// paths[i][j] = paths[i - 1][j] + paths[i][j - 1]; +// } +// } +// return paths[m - 1][n - 1]; +// } + + /** + * 使用一维数组 + * @param m + * @param n + * @return + */ + public int uniquePaths(int m, int n) { + int[] paths = new int[m]; + // init path + for (int i = 0; i < m; i++) paths[i] = 1; + for (int i = 1; i < n; i++) { + for (int j = 1; j < m; j++) { + paths[j] = paths[j] + paths[j - 1]; + } + } + return paths[m - 1]; + } +} diff --git a/Week 05/id_431/LeetCode_63_431.java b/Week 05/id_431/LeetCode_63_431.java new file mode 100644 index 000000000..ee6e020cd --- /dev/null +++ b/Week 05/id_431/LeetCode_63_431.java @@ -0,0 +1,28 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/11 + */ +public class UniquePathsII { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int m = obstacleGrid[0].length; + int n = obstacleGrid.length; + int[] paths = new int[m]; + // init path + for (int i = 0; i < m; i++) { + if (obstacleGrid[0][i] == 1) paths[i] = 0; + else if (i == 0) paths[i] = 1; + else paths[i] = Math.min(paths[i - 1], 1); + } + // DP程序 + for (int i = 1; i < n; i++) { + for (int j = 0; j < m; j++) { + if (obstacleGrid[i][j] == 1) paths[j] = 0; + else if (j == 0) paths[j] = Math.min(paths[j], 1); + else paths[j] = paths[j] + paths[j - 1]; + } + } + return paths[m - 1]; + } +} diff --git a/Week 05/id_431/LeetCode_64_431.java b/Week 05/id_431/LeetCode_64_431.java new file mode 100644 index 000000000..3c4037df7 --- /dev/null +++ b/Week 05/id_431/LeetCode_64_431.java @@ -0,0 +1,28 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/15 + */ +public class MinimumPathSum { + + public int minPathSum(int[][] grid) { + int row = grid.length; + int col = grid[0].length; + int[] dp = new int[col]; + + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (i == 0 && j ==0) dp[0] = grid[0][0]; + else if (i == 0) { + dp[j] = dp[j - 1] + grid[i][j]; + } else if (j == 0) { + dp[0] = dp[0] + grid[i][j]; + } else { + dp[j] = Math.min(dp[j - 1] + grid[i][j], dp[j] + grid[i][j]); + } + } + } + return dp[col - 1]; + } +} diff --git a/Week 05/id_431/LeetCode_714_431.java b/Week 05/id_431/LeetCode_714_431.java new file mode 100644 index 000000000..80fcfdcc4 --- /dev/null +++ b/Week 05/id_431/LeetCode_714_431.java @@ -0,0 +1,20 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/14 + */ +public class BestTimeToBuyAndSellStockWithTransactionFee { + + public int maxProfit(int[] prices, int fee) { + if (prices.length == 0 || prices.length == 1) return 0; + int dp_0_0 = -prices[0]; + int dp_0_1 = -fee; + for (int i = 1; i < prices.length; i++) { + int tmp = dp_0_1; + dp_0_1 = Math.max(dp_0_1, dp_0_0 + prices[i] - fee); + dp_0_0 = Math.max(dp_0_0, tmp - prices[i]); + } + return dp_0_1; + } +} diff --git a/Week 05/id_431/LeetCode_72_431.java b/Week 05/id_431/LeetCode_72_431.java new file mode 100644 index 000000000..b81bb6aa7 --- /dev/null +++ b/Week 05/id_431/LeetCode_72_431.java @@ -0,0 +1,40 @@ +package hard; + +/** + * @author 潘磊明 + * @date 2019/11/15 + */ +public class EditDistance { + public int minDistance(String word1, String word2) { + if (word1.length() == 0) return word2.length(); + if (word2.length() == 0) return word1.length(); + char[] w1 = word1.toCharArray(); + char[] w2 = word2.toCharArray(); + int[][] dp = new int[w1.length][w2.length]; + //init + if (w1[0] == w2[0]) dp[0][0] = 0; + else dp[0][0] = 1; + for (int i = 1; i < w1.length; i++) { + if (w1[i] == w2[0]) dp[i][0] = i; + else dp[i][0] = dp[i - 1][0] < i ? i : i + 1; + } + for (int j = 1; j < w2.length; j++) { + if (w2[j] == w1[0]) dp[0][j] = j; + else dp[0][j] = dp[0][j - 1] < j ? j : j + 1; + } + for (int i = 1; i < w1.length; i++) { + for (int j = 1; j < w2.length; j++) { + if (w1[i] == w2[j]) dp[i][j] = dp[i - 1][j - 1]; + else dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1; + } + } + return dp[w1.length - 1][w2.length - 1]; + } + + public static void main(String[] args) { + String s1 = "intention"; + String s2 = "execution"; + EditDistance e = new EditDistance(); + e.minDistance(s1, s2); + } +} diff --git a/Week 05/id_431/LeetCode_91_431.java b/Week 05/id_431/LeetCode_91_431.java new file mode 100644 index 000000000..fe520c42d --- /dev/null +++ b/Week 05/id_431/LeetCode_91_431.java @@ -0,0 +1,38 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/18 + */ +public class DecodeWays { + public int numDecodings(String s) { + if (s.startsWith("0")) return 0; + if (s.length() == 1) return 1; + int[] array = new int[s.length()]; + for(int i = 0; i < s.length(); i++) { + array[i] = Integer.valueOf(s.substring(i, i + 1)); + } + int[] dp = new int[array.length]; + dp[0] = 1; + + for (int i = 1; i < array.length; i++) { + if (dp[i - 1] == 0) dp[i] = 0; + else if (array[i] == 0) { + if(array[i - 1] == 1 || array[i - 1] == 2) { + if (i != 1) dp[i] = dp[i - 2]; + else dp[i] = 1; + } + else dp[i] = 0; + } + else { + int tmp = array[i - 1] * 10 + array[i]; + if (tmp > 10 && tmp < 27) { + if (i == 1) dp[i] = 2; + else dp[i] = dp[i - 1] + dp[i - 2]; + } + else dp[i] = dp[i - 1]; + } + } + return dp[array.length - 1]; + } +} diff --git a/Week 05/id_431/NOTE.md b/Week 05/id_431/NOTE.md index a6321d6e2..ce47538de 100644 --- a/Week 05/id_431/NOTE.md +++ b/Week 05/id_431/NOTE.md @@ -1,4 +1,31 @@ # NOTE - +# 目录 +* 刷题时间表 + + + +# 第五周刷题时间表 + +题目名称|难易度|第一遍时间|第二遍时间|第三遍时间|第四遍时间|第五遍时间|地址 +:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-: +Unique Paths |Medium|2019-11-11||||| https://leetcode.com/problems/unique-paths/ +Unique Paths II|Medium|2019-11-11|||||https://leetcode.com/problems/unique-paths-ii/ +Triangle|Medium|2019-11-11|||||https://leetcode.com/problems/triangle/ +Maximum Subarray|Easy|2019-11-12|||||https://leetcode.com/problems/maximum-subarray/ +Maximum Product Subarray|Medium|2019-11-12|||||https://leetcode.com/problems/maximum-product-subarray/ +Coin Change|Medium|2019-11-12|||||https://leetcode.com/problems/coin-change/description/ +House Robber|Easy|2019-11-12|||||https://leetcode.com/problems/house-robber/ +House Robber II|Mediu|2019-11-13|||||https://leetcode.com/problems/house-robber-ii/ +Best Time to Buy and Sell Stock|Easy|2019-11-13|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ +Best Time to Buy and Sell Stock III|Hard|2019-11-14|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ +Best Time to Buy and Sell Stock with Cooldown|Medium|2019-11-14|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ +Best Time to Buy and Sell Stock IV|Hard|2019-11-14|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ +Best Time to Buy and Sell Stock with Transaction Fee|Medium|2019-11-15|||||https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ +Longest Valid Parentheses|Hard|2019-11-15|||||https://leetcode.com/problems/longest-valid-parentheses/ +Minimum Path Sum|Medium|2019-11-15|||||https://leetcode.com/problems/minimum-path-sum/ +Edit Distance|Hard|2019-11-18|||||https://leetcode.com/problems/edit-distance/ +Decode Ways|Medium|201911-19|||||https://leetcode.com/problems/decode-ways/ +Maximal Square|Medium|2019-11-19|||||https://leetcode.com/problems/maximal-square/ +Max Sum of Rectangle No Larger Than K|Hard||||||https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/ \ No newline at end of file diff --git a/Week 05/id_436/Leetcode_32_436.java b/Week 05/id_436/Leetcode_32_436.java new file mode 100644 index 000000000..cbc579405 --- /dev/null +++ b/Week 05/id_436/Leetcode_32_436.java @@ -0,0 +1,24 @@ +class Solution { + public int longestValidParentheses(String s) { + int result = 0; int start = 0; int n = s.length(); + Stack stack = new Stack(); + + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') + stack.push(i); + else if (s.charAt(i) == ')') { + if (stack.isEmpty()) { + start = i + 1; + } + else { + stack.pop(); + if (stack.isEmpty()) + result = Math.max(result,i - start + 1); + else + result = Math.max(result, i - (stack.peek() + 1) + 1); + } + } + } + return result; + } +} diff --git a/Week 05/id_436/Leetcode_72_436.java b/Week 05/id_436/Leetcode_72_436.java new file mode 100644 index 000000000..a42aa503a --- /dev/null +++ b/Week 05/id_436/Leetcode_72_436.java @@ -0,0 +1,26 @@ +public class Solution { + public int minDistance(String word1, String word2) { + int n = word1.length(); + int m = word2.length(); + + int[][] dp = new int[n+1][m+1]; + for (int i = 0; i < m + 1; i++) { + dp[0][i] = i; + } + for (int j = 0; i < n + 1; j++) { + dp[i][0] = i; + } + + + for (int i = 1; i < n + 1; i++) { + for (int j=1; j < m + 1; j++) { + if(word1.charAt(i-1) == word2.charAt(j-1)) { + dp[i][j] = dp[i-1][j-1]; + } else { + dp[i][j] = 1 + Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1])); + } + } + } + return dp[n][m]; + } +} diff --git a/Week 05/id_441/NOTE.md b/Week 05/id_441/NOTE.md index a6321d6e2..ff2921706 100644 --- a/Week 05/id_441/NOTE.md +++ b/Week 05/id_441/NOTE.md @@ -1,4 +1,32 @@ -# NOTE +# 第五周动态规划 - +## 相关的类似问题 +分治,回溯,递归,动态规划这些本质上没有很大的区别,五毒神掌不能少。 +记住所有的代码模板。 + +1. 终止条件 +2. 处理当前层逻辑 +3. 下探 +4. 恢复当前层状态 + +## 注意点 + +1. 不要人肉递归 +2. 找到最近最简单方法,(计算机的特性)拆解重复问题 +3. 数学归纳法思维实现 + +## 动态规划 + +解决的问题就是递归问题和分治问题。不过是动态规划是有最优子结构的。 +可以理解为就是分治+最优子结构。 + +### 关键点 + +1. 动态规划和递归或者分治没有本质区别 +2. 共性是找重复度的子问题 +3. 差异性是最优子结构,中途可以淘汰次优解 + opt[n] = bestof(opt[n-1]+opt[n-2]) + 递推公式: + opt(i) = opt(i-1)+opt(i-2) + opt(i,j)= opt(i+1, j)+opt(i, j+1) diff --git a/Week 05/id_441/fibonacci.js b/Week 05/id_441/fibonacci.js new file mode 100644 index 000000000..411076f65 --- /dev/null +++ b/Week 05/id_441/fibonacci.js @@ -0,0 +1,62 @@ +// 斐波那契代码 +function fib (n, memo) { + if( n < 0) { + return 0 + }else if(n === 1) { + return 1 + }else if(memo[n] === 0){ + memo[n] = fib(n-1) + fib(n-2) + } + return memo[n] +} +function fib (n, memo) { + if(n<=1) { + return n; + } + if(!memo[n]){ + memo[n] = fib(n-1)+fib(n-2) + } + return memo[n] +} +function fib (n){ + let a = [0,1] + console.log() + for(let i =2; i st; + +​ for (int i = 0; i < n; i++) { + +​ if (s[i] == '(') st.push(i); + +​ else { + +​ if (!st.empty()) { + +​ if (s[st.top()] == '(') st.pop(); + +​ else st.push(i); + +​ } + +​ else st.push(i); + +​ } + +​ } + +​ if (st.empty()) longest = n; + +​ else { + +​ int a = n, b = 0; + +​ while (!st.empty()) { + +​ b = st.top(); st.pop(); + +​ longest = max(longest, a-b-1); + +​ a = b; + +​ } + +​ longest = max(longest, a); + +​ } + +​ return longest; + + } + +}; \ No newline at end of file diff --git a/Week 05/id_446/LeetCode_64_446.cpp b/Week 05/id_446/LeetCode_64_446.cpp new file mode 100644 index 000000000..31969ac18 --- /dev/null +++ b/Week 05/id_446/LeetCode_64_446.cpp @@ -0,0 +1,31 @@ +class Solution { + +public: + + int minPathSum(vector>& grid) { + +​ int m = grid.size(); + +​ int n = grid[0].size(); + +​ vector cur(m, grid[0][0]); + +​ for (int i = 1; i < m; i++) + +​ cur[i] = cur[i - 1] + grid[i][0]; + +​ for (int j = 1; j < n; j++) { + +​ cur[0] += grid[0][j]; + +​ for (int i = 1; i < m; i++) + +​ cur[i] = min(cur[i - 1], cur[i]) + grid[i][j]; + +​ } + +​ return cur[m - 1]; + + } + +}; \ No newline at end of file diff --git a/Week 05/id_451/LeetCode_213_451.go b/Week 05/id_451/LeetCode_213_451.go new file mode 100644 index 000000000..d4bf39d38 --- /dev/null +++ b/Week 05/id_451/LeetCode_213_451.go @@ -0,0 +1,44 @@ +func max(a, b int) int { + if a > b { + return a + } + return b +} +func _rob(nums []int) int { + l := len(nums) + if l == 0 { + return 0 + } + if l == 1 { + return nums[0] + } + if l == 2 { + return max(nums[1], nums[0]) + } + dp := make(map[int]int) + dp[0] = nums[0] + dp[1] = max(nums[1], nums[0]) + for i, n := range nums { + if i == 0 || i == 1 { + continue + } + + dp[i] = max(dp[i-2]+n, dp[i-1]) + } + return dp[l-1] +} +func rob(nums []int) int { + l := len(nums) + if l == 0 { + return 0 + } + if l == 1 { + return nums[0] + } + if l == 2 { + return max(nums[1], nums[0]) + } + a := _rob(nums[1:]) + b := _rob(nums[:l-1]) + return max(a, b) +} diff --git a/Week 05/id_451/LeetCode_221_451.go b/Week 05/id_451/LeetCode_221_451.go new file mode 100644 index 000000000..bac46f802 --- /dev/null +++ b/Week 05/id_451/LeetCode_221_451.go @@ -0,0 +1,35 @@ +func min(a, b int) int { + if a > b { + return b + } + return a +} +func max(a, b int) int { + if a > b { + return a + } + return b +} +func maximalSquare(grid [][]byte) int { + if len(grid) == 0 { + return 0 + } + res := 0 + for j := 0; j < len(grid); j++ { + row := grid[j] + for i := 0; i < len(row); i++ { + row[i] = row[i] - 48 + if i-1 < 0 || j-1 < 0 { + res = max(res, int(row[i])) + continue + } + if grid[j][i] == 1 { + grid[j][i] = byte(min(int(grid[j-1][i-1]), min(int(grid[j-1][i]), int(grid[j][i-1]))) + 1) + res = max(res, int(grid[j][i])) + } + + //println(`?`, j, i, row[i]) + } + } + return res * res +} diff --git a/Week 05/id_451/LeetCode_32_451.go b/Week 05/id_451/LeetCode_32_451.go new file mode 100644 index 000000000..44bb33f63 --- /dev/null +++ b/Week 05/id_451/LeetCode_32_451.go @@ -0,0 +1,34 @@ + +func max(a, b int) int { + if a > b { + return a + } + return b +} +func longestValidParentheses(s string) int { + + dp := make([]int, len(s)) + res := 0 + for i, a := range s { + if i == 0 { + continue + } + if a == ')' && s[i-1] == '(' { + if i-2 < 0 { + dp[i] = 2 + } else { + dp[i] = dp[i-2] + 2 + } + } + if a == ')' && s[i-1] == ')' { + if i-1-dp[i-1] >= 0 && s[i-1-dp[i-1]] == '(' { + dp[i] = dp[i-1] + 2 + if i-1-dp[i-1]-1 >= 0 { + dp[i] += dp[i-1-dp[i-1]-1] + } + } + } + res = max(res, dp[i]) + } + return res +} diff --git a/Week 05/id_451/LeetCode_64_451.go b/Week 05/id_451/LeetCode_64_451.go new file mode 100644 index 000000000..24b80c594 --- /dev/null +++ b/Week 05/id_451/LeetCode_64_451.go @@ -0,0 +1,30 @@ +func min(a, b int) int { + if a > b { + return b + } + return a +} +func minPathSum(grid [][]int) int { + if len(grid) == 0 { + return 0 + } + + for j := 0; j < len(grid); j++ { + row := grid[j] + for i := 0; i < len(row); i++ { + if i-1 < 0 && j-1 < 0 { + continue + } + if j-1 < 0 { + row[i] = row[i] + row[i-1] + continue + } + if i-1 < 0 { + row[i] = row[i] + grid[j-1][i] + continue + } + row[i] = row[i] + min(row[i-1], grid[j-1][i]) + } + } + return grid[len(grid)-1][len(grid[len(grid)-1])-1] +} diff --git a/Week 05/id_466/LeetCode_32_466.java b/Week 05/id_466/LeetCode_32_466.java new file mode 100644 index 000000000..65de9572b --- /dev/null +++ b/Week 05/id_466/LeetCode_32_466.java @@ -0,0 +1,77 @@ +//给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 +// +// 示例 1: +// +// 输入: "(()" +//输出: 2 +//解释: 最长有效括号子串为 "()" +// +// +// 示例 2: +// +// 输入: ")()())" +//输出: 4 +//解释: 最长有效括号子串为 "()()" +// +// Related Topics 字符串 动态规划 +package com.aseara.leetcode.editor.cn.a32; + +import org.junit.jupiter.api.Test; + +import java.util.LinkedList; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 32.最长有效括号
+ * Date: 2019/11/14
+ * + * @author qiujingde + */ +class LongestValidParentheses { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(2, solution.longestValidParentheses("(()")); + assertEquals(4, solution.longestValidParentheses(")()())")); + assertEquals(2, solution.longestValidParentheses("()(()")); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int longestValidParentheses(String s) { + if (s == null || s.length() < 2) { + return 0; + } + + // 检查判断某个位置是否合法 + int[] memo = new int[s.length() + 1]; + char[] chars = s.toCharArray(); + LinkedList stack = new LinkedList<>(); + + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (c == '(') { + stack.push(i); + } else if (!stack.isEmpty()) { + memo[stack.pop()] = 1; + memo[i] = 1; + } + } + + int max = 0; + for (int i = 1; i < memo.length; i++) { + if (memo[i] == 0) { + max = Math.max(max, memo[i - 1]); + } else { + memo[i] = memo[i - 1] + 1; + } + } + return max; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_466/LeetCode_64_466.java b/Week 05/id_466/LeetCode_64_466.java new file mode 100644 index 000000000..f2d0c2149 --- /dev/null +++ b/Week 05/id_466/LeetCode_64_466.java @@ -0,0 +1,69 @@ +//给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 +// +// 说明:每次只能向下或者向右移动一步。 +// +// 示例: +// +// 输入: +//[ +//  [1,3,1], +// [1,5,1], +// [4,2,1] +//] +//输出: 7 +//解释: 因为路径 1→3→1→1→1 的总和最小。 +// +// Related Topics 数组 动态规划 +package com.aseara.leetcode.editor.cn.a64; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 64.最小路径和
+ * Date: 2019/11/14
+ * + * @author qiujingde + */ +class MinimumPathSum { + private Solution solution = new Solution(); + + @Test + void test1() { + int[][] grid = { + {1,3,1}, + {1,5,1}, + {4,2,1} + }; + assertEquals(7, solution.minPathSum(grid)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int m = grid.length; + int n = grid[0].length; + int[] memo = new int[n + 1]; + Arrays.fill(memo, Integer.MAX_VALUE); + memo[n - 1] = 0; + + for (int i = m - 1; i >= 0; i--) { + for (int j = n - 1; j >= 0; j--) { + memo[j] = Math.min(memo[j], memo[j + 1]) + grid[i][j]; + } + } + + return memo[0]; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_466/LeetCode_72_466.java b/Week 05/id_466/LeetCode_72_466.java new file mode 100644 index 000000000..b98681095 --- /dev/null +++ b/Week 05/id_466/LeetCode_72_466.java @@ -0,0 +1,94 @@ +//给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 +// +// 你可以对一个单词进行如下三种操作: +// +// +// 插入一个字符 +// 删除一个字符 +// 替换一个字符 +// +// +// 示例 1: +// +// 输入: word1 = "horse", word2 = "ros" +//输出: 3 +//解释: +//horse -> rorse (将 'h' 替换为 'r') +//rorse -> rose (删除 'r') +//rose -> ros (删除 'e') +// +// +// 示例 2: +// +// 输入: word1 = "intention", word2 = "execution" +//输出: 5 +//解释: +//intention -> inention (删除 't') +//inention -> enention (将 'i' 替换为 'e') +//enention -> exention (将 'n' 替换为 'x') +//exention -> exection (将 'n' 替换为 'c') +//exection -> execution (插入 'u') +// +// Related Topics 字符串 动态规划 +package com.aseara.leetcode.editor.cn.a72; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 72.编辑距离
+ * Date: 2019/11/14
+ * + * @author qiujingde + */ +class EditDistance { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(3, solution.minDistance("horse", "ros")); + assertEquals(5, solution.minDistance("intention", "execution")); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int minDistance(String word1, String word2) { + if (word1 == null || word1.length() == 0) { + return word2 == null ? 0 : word2.length(); + } + if (word2 == null || word2.length() == 0) { + return word1.length(); + } + + int m = word1.length(); + int n = word2.length(); + + char[] chars1 = word1.toCharArray(); + char[] chars2 = word2.toCharArray(); + + int[] pre = new int[n + 1]; + int[] cur = new int[n + 1]; + + for (int i = 1; i < pre.length; i++) { + pre[i] = i; + } + + for (int i = 0; i < m; i++) { + cur[0] = i + 1; + for (int j = 0; j < n; j++) { + int up = pre[j + 1] + 1; + int left = cur[j] + 1; + int upLeft = pre[j] + (chars1[i] == chars2[j] ? 0 : 1); + cur[j + 1] = Math.min(up, Math.min(left, upLeft)); + } + System.arraycopy(cur, 0, pre, 0, n + 1); + } + + return cur[n]; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_466/LeetCode_91_466.java b/Week 05/id_466/LeetCode_91_466.java new file mode 100644 index 000000000..a12563df6 --- /dev/null +++ b/Week 05/id_466/LeetCode_91_466.java @@ -0,0 +1,77 @@ +//一条包含字母 A-Z 的消息通过以下方式进行了编码: +// +// 'A' -> 1 +//'B' -> 2 +//... +//'Z' -> 26 +// +// +// 给定一个只包含数字的非空字符串,请计算解码方法的总数。 +// +// 示例 1: +// +// 输入: "12" +//输出: 2 +//解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 +// +// +// 示例 2: +// +// 输入: "226" +//输出: 3 +//解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +// +// Related Topics 字符串 动态规划 +package com.aseara.leetcode.editor.cn.a91; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 91.解码方法
+ * Date: 2019/11/15
+ * + * @author qiujingde + */ +class DecodeWays { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(2, solution.numDecodings("12")); + assertEquals(3, solution.numDecodings("226")); + assertEquals(1, solution.numDecodings("110")); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + char[] chars = s.toCharArray(); + int[] memo = new int[chars.length + 2]; + memo[chars.length] = 1; + + int before = 0; + for (int i = chars.length - 1; i >= 0; i--) { + int curNum = chars[i] - '0'; + if (curNum == 0) { + memo[i] = 0; + } else if (curNum == 1 || (curNum == 2 && before < 7)) { + memo[i] = memo[i + 1] + memo[i + 2]; + } else { + memo[i] = memo[i + 1]; + } + before = curNum; + + } + + return memo[0]; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 05/id_471/LeetCode_121_471.java b/Week 05/id_471/LeetCode_121_471.java new file mode 100644 index 000000000..5a4717102 --- /dev/null +++ b/Week 05/id_471/LeetCode_121_471.java @@ -0,0 +1,13 @@ +class Solution { + //遍历数组,然后保存最小值,根据最小值和最大值的差来求利润,最后返回最大利润 + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE, result = 0; + + for (int i = 0; i < prices.length; i++) { + minPrice = Math.min(minPrice, prices[i]); + result = Math.max(result, prices[i] - minPrice); + } + + return result; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_122_471.java b/Week 05/id_471/LeetCode_122_471.java new file mode 100644 index 000000000..a3a2af878 --- /dev/null +++ b/Week 05/id_471/LeetCode_122_471.java @@ -0,0 +1,20 @@ +class Solution { + /* + 动态规划法 + 考虑买和卖两个状态 + 定义重复子问题:在第 i 天的买卖情况可以由前一天的买卖状态来决定,然后择优决定买或者卖掉 + 动态规划方程:sale[i] = Math.max(sale[i - 1], buy[i-1] + prices[i]) + buy[i] = Math.max(buy[i-1], sale[i-1] + prices[i]) + */ + + public int maxProfit(int[] prices) { + int sale = 0, buy = Integer.MIN_VALUE; + + for (int i = 0; i < prices.length; i++) { + buy = Math.max(buy, sale - prices[i]); + sale = Math.max(sale, buy + prices[i]); + } + + return sale; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_123_471.java b/Week 05/id_471/LeetCode_123_471.java new file mode 100644 index 000000000..00226a51b --- /dev/null +++ b/Week 05/id_471/LeetCode_123_471.java @@ -0,0 +1,25 @@ +class Solution { + public int maxProfit(int[] prices) { + if (prices.length < 2) { + return 0; + } + int buy = -prices[0]; + int sales[] = new int[prices.length]; + buy = -prices[0]; + sales[0] = 0; + for (int i = 1; i < prices.length; i++) { + sales[i] = Math.max(sales[i - 1], buy + prices[i]); + buy = Math.max(buy, -prices[i]); + } + + int maxProfit = sales[sales.length-1]; + int maxPrice = prices[prices.length - 1]; + + for (int i = prices.length - 2; i >= 1; i--) { + maxProfit = Math.max(maxProfit, maxPrice - prices[i] + sales[i-1]); + maxPrice = Math.max(maxPrice, prices[i]); + } + + return maxProfit; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_152_471.java b/Week 05/id_471/LeetCode_152_471.java new file mode 100644 index 000000000..c4d230ee2 --- /dev/null +++ b/Week 05/id_471/LeetCode_152_471.java @@ -0,0 +1,16 @@ +class Solution { + public int maxProduct(int[] nums) { + int min = nums[0]; + int max = nums[0]; + int result = nums[0]; + + for (int i = 1; i < nums.length; i++) { + int tempMin = min; + min = Math.min(nums[i], Math.min(max * nums[i], min * nums[i])); + max = Math.max(nums[i], Math.max(max * nums[i], tempMin * nums[i])); + result = Math.max(max, result); + } + + return result; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_198_471.java b/Week 05/id_471/LeetCode_198_471.java new file mode 100644 index 000000000..5982e680a --- /dev/null +++ b/Week 05/id_471/LeetCode_198_471.java @@ -0,0 +1,14 @@ +class Solution { + public int rob(int[] nums) { + + int preMax = 0, curMax = 0; + + for (int i = 0; i < nums.length; i++) { + int temp = curMax; + curMax = Integer.max(curMax, preMax + nums[i]); + preMax = temp; + } + + return curMax; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_213_471.java b/Week 05/id_471/LeetCode_213_471.java new file mode 100644 index 000000000..3583bbdd5 --- /dev/null +++ b/Week 05/id_471/LeetCode_213_471.java @@ -0,0 +1,20 @@ +class Solution { + public int rob(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + return Math.max(robber(nums, 0, nums.length - 2), robber(nums, 1, nums.length - 1)); + } + + public int robber(int[] nums, int start, int end) { + int preMax = 0, curMax = 0; + + for (int i = start; i <= end; i++) { + int temp = curMax; + curMax = Math.max(preMax + nums[i], curMax); + preMax = temp; + } + + return curMax; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_309_471.java b/Week 05/id_471/LeetCode_309_471.java new file mode 100644 index 000000000..bae82f181 --- /dev/null +++ b/Week 05/id_471/LeetCode_309_471.java @@ -0,0 +1,20 @@ +class Solution { + //sale[i] = Math.max(sale[i-1], buy[i-1] + prices[i]); + //buy[i] = Math.max(buy[i-1], sale[i-2] - prices[i]); + public int maxProfit(int[] prices) { + if (prices.length < 2) { + return 0; + } + + int sales = 0, buy = -prices[0], preSales = 0; + + for (int i = 1; i < prices.length; i++) { + int temp = sales; + sales = Math.max(sales, buy + prices[i]); + buy = Math.max(buy, preSales - prices[i]); + preSales = temp; + } + + return sales; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_322_471.java b/Week 05/id_471/LeetCode_322_471.java new file mode 100644 index 000000000..03d27baac --- /dev/null +++ b/Week 05/id_471/LeetCode_322_471.java @@ -0,0 +1,18 @@ +class Solution { + public int coinChange(int[] coins, int amount) { + int dp[] = new int[amount + 1]; + + Arrays.fill(dp, Integer.MAX_VALUE); + dp[0] = 0; + + for (int i = 0; i < coins.length; i++) { + for (int j = coins[i]; j <= amount; j++) { + if (dp[j - coins[i]] != Integer.MAX_VALUE) { + dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1); + } + } + } + + return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount]; + } +} \ No newline at end of file diff --git a/Week 05/id_471/LeetCode_53_471.java b/Week 05/id_471/LeetCode_53_471.java new file mode 100644 index 000000000..d25a67d9d --- /dev/null +++ b/Week 05/id_471/LeetCode_53_471.java @@ -0,0 +1,12 @@ +class Solution { + public int maxSubArray(int[] nums) { + int maxResult = nums[0]; + int curMax = maxResult; + for (int i = 1; i < nums.length; i++) { + curMax = Math.max(curMax + nums[i], nums[i]); + maxResult = Math.max(maxResult, curMax); + } + + return maxResult; + } +} \ No newline at end of file diff --git a/Week 05/id_476/LeetCode_32_476.java b/Week 05/id_476/LeetCode_32_476.java new file mode 100644 index 000000000..97ffc565a --- /dev/null +++ b/Week 05/id_476/LeetCode_32_476.java @@ -0,0 +1,44 @@ +public class LeetCode_32_LongestValidParentheses { + public static void main(String[] args) { + Solution solution = new LeetCode_32_LongestValidParentheses().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int longestValidParentheses(String s) { + + // a. 子问题 + // 有效的字符串总是以')'结尾 + // i 处的最长有效字符串 + // 如果 s[i] = '(',dp[i] = 0; + // 如果 s[i] = ')' + // 如果 s[i - 1] = '(',刚好与之匹配,dp[i] = dp[i - 2] + 2 + // 如果 s[i - 1] = ')', + // 如果 s[i - dp[i - 1] - 1] = '(' + // dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2; + // 如果 s[i - dp[i - 1] - 1] = ')' + // dp[i] = 0; + // b. 状态数组 + // DP数组记录每个位置的最长有效字符串长度 + // c. DP 方程 + if (s == null || s.length() < 2) return 0; + char[] chs = s.toCharArray(); + int[] dp = new int[chs.length]; + int max = 0; + for (int i = 1; i < chs.length; i++) { + if (chs[i] == ')') { + if (chs[i - 1] == '(') { + dp[i] = (i - 2 >= 0 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] - 1 >= 0 && chs[i - dp[i - 1] - 1] == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1] - 2 >= 0) ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + max = Math.max(max, dp[i]); + } + } + return max; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 05/id_476/LeetCode_72_476.java b/Week 05/id_476/LeetCode_72_476.java new file mode 100644 index 000000000..a723ce7ee --- /dev/null +++ b/Week 05/id_476/LeetCode_72_476.java @@ -0,0 +1,47 @@ +public class LeetCode_72_EditDistance { + public static void main(String[] args) { + Solution solution = new LeetCode_72_EditDistance().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int minDistance(String word1, String word2) { + + // 乍一看到这个题,条件反射的想到找最长子字符串,在此基础上进行增删改 + // 实际上,并不能这样解。举个例子,"abc"、"cde",最长子字符串为"c", + // 如果在此基础上操作,则需要先删除"a"、"b",再插入"d"、"e",操作次数为 4。 + // 但是直接全部替换,操作次数只有 3。 + + // a. 子问题 + // i, j 处的最少操作次数 + // word1[i] == word2[j] + // dp[i][j] = dp[i - 1][j - 1] + // word1[i] != word2[j] + // dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 + // b. 状态数组定义 + // c. DP 方程 + int m = word1.length(); + int n = word2.length(); + int[][] dp = new int[m + 1][n + 1]; + for (int i = 0; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 0; j <= n; j++) { + dp[0][j] = j; + } + for (int i = 1; i < m + 1; i++) { + for (int j = 1; j < n + 1; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; + } + } + } + return dp[m][n]; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 05/id_491/LeetCode_32_491.java b/Week 05/id_491/LeetCode_32_491.java new file mode 100644 index 000000000..8cf86299e --- /dev/null +++ b/Week 05/id_491/LeetCode_32_491.java @@ -0,0 +1,54 @@ +class Solution { + public int longestValidParentheses(String s) { + Stack stack = new Stack<>(); + int result = 0; + int tempResult = 0; + int tempEnd = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push('('); + } else { + if (!stack.isEmpty()) { + stack.pop(); + tempResult += 2; + } else { + if (tempResult > result) { + result = tempResult; + } + tempResult = 0; + tempEnd = i + 1; + } + } + } + + if(!stack.isEmpty()) { + tempResult = 0; + stack.clear(); + for (int i = s.length() - 1; i >= tempEnd; i--) { + if (s.charAt(i) == ')') { + stack.push(')'); + } else { + if (!stack.isEmpty()) { + stack.pop(); + tempResult += 2; + } else { + if (tempResult > result) { + result = tempResult; + } + tempResult = 0; + } + } + } + + if (tempResult > result) { + result = tempResult; + } + } else { + if (tempResult > result) { + result = tempResult; + } + } + + return result; + } +} diff --git a/Week 05/id_491/LeetCode_64_491.java b/Week 05/id_491/LeetCode_64_491.java new file mode 100644 index 000000000..ecd844e83 --- /dev/null +++ b/Week 05/id_491/LeetCode_64_491.java @@ -0,0 +1,18 @@ +class Solution { + public int minPathSum(int[][] grid) { + int row = grid.length; + int column = grid[0].length; + int[][] memo = new int[row + 1][column + 1]; + for(int i = row - 1; i >= 0; i--) { + for(int j = column - 1; j >= 0; j--) { + if(i == row - 1 || j == column - 1) { + memo[i][j] = memo[i + 1][j] + memo[i][j + 1] + grid[i][j]; + } else { + memo[i][j] = Math.min(memo[i + 1][j], memo[i][j + 1]) + grid[i][j]; + } + } + } + + return memo[0][0]; + } +} diff --git a/Week 05/id_501/week05/LeetCode_32_501.java b/Week 05/id_501/week05/LeetCode_32_501.java new file mode 100644 index 000000000..fe2405a97 --- /dev/null +++ b/Week 05/id_501/week05/LeetCode_32_501.java @@ -0,0 +1,69 @@ +package homework.week05; + +import java.util.Stack; + +/** + * 32. 最长有效括号 + * https://leetcode-cn.com/problems/longest-valid-parentheses/ + * @author sintang + * @date 2019-11-17 + */ +public class LeetCode_32_501 { + /** + * 暴力法使用栈处理 + * @param s + * @return + */ + public int longestValidParentheses(String s) { + int maxLength = 0; + for(int i = 0;i < s.length();i++){ + for(int j = i + 2;j <= s.length(); j+=2){ + if(isValid(s.substring(i,j))){ + maxLength = Math.max(maxLength,j - i); + } + } + } + return maxLength; + } + public boolean isValid(String s){ + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + if(s.charAt(i) == '('){ + stack.push('('); + }else if(!stack.empty() && stack.peek() == '('){ + stack.pop(); + }else{ + return false; + } + } + return stack.empty(); + } + + /** + * 动态规划 + * @param s + * @return + */ + public int longestValidParentheses2(String s){ + int maxlength = 0; + int[] dp =new int[s.length()]; + for (int i = 1; i < s.length() ; i++) { + if(s.charAt(i) == ')'){ + if(s.charAt(i - 1) == '('){ + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + }else if(i - dp[i - 1] > 0 && s.charAt(i - dp[i-1] - 1) == '('){ + dp[i] = dp[i - 1] + ((i - dp[i - 1])>=2 ? dp[i - dp[i -1] -2] :0) +2; + } + maxlength = Math.max(maxlength,dp[i]); + } + } + return maxlength; + } + + + public static void main(String[] args) { + LeetCode_32_501 leetcode = new LeetCode_32_501(); + System.out.println(leetcode.longestValidParentheses("()(()")); + System.out.println(leetcode.longestValidParentheses2("()(()")); + } +} diff --git a/Week 05/id_501/week05/LeetCode_647_501.java b/Week 05/id_501/week05/LeetCode_647_501.java new file mode 100644 index 000000000..fdc1550e4 --- /dev/null +++ b/Week 05/id_501/week05/LeetCode_647_501.java @@ -0,0 +1,31 @@ +package homework.week05; + +/** + * 647. 回文子串 + * https://leetcode-cn.com/problems/palindromic-substrings/ + * @author sintang + * @date 2019-11-17 + */ +public class LeetCode_647_501 { + + public int countSubstrings(String s) { + int result = 0; + boolean[][] dp = new boolean[s.length()][s.length()]; + for (int i = s.length() - 1; i >= 0 ; i--) { + for(int j = i;j < s.length() ; j ++){ + if(i == j){ + dp[i][j] = true; + }else{ + dp[i][j] = s.charAt(i) == s.charAt(j) && (j <= i + 1 || dp[i +1][j - 1]); + } + if(dp[i][j]){ + result ++; + } + } + } + return result; + } + public static void main(String[] args) { + + } +} diff --git a/Week 05/id_501/week05/LeetCode_64_501.java b/Week 05/id_501/week05/LeetCode_64_501.java new file mode 100644 index 000000000..f4bb0981b --- /dev/null +++ b/Week 05/id_501/week05/LeetCode_64_501.java @@ -0,0 +1,44 @@ +package homework.week05; + +/** + * 64. 最小路径和 + * https://leetcode-cn.com/problems/minimum-path-sum/ + * @author sintang + * @date 2019-11-17 + */ +public class LeetCode_64_501 { + + public int minPathSum(int[][] grid) { + // dp 元素表示数值和 + for (int i = 0; i < grid.length ; i++) { + for(int j = 0; j = 0; i--) { + if (s.charAt(i) == '0') { + dp[i] = 0; + continue; + } + if (Integer.valueOf(s.substring(i,i + 2)) <= 26) { + dp[i] = dp[i + 1] + dp[i + 2]; + } else { + dp[i] = dp[i + 1]; + } + } + return dp[0]; + } + + public static void main(String[] args) { + LeetCode_91_501 leetCode = new LeetCode_91_501(); + System.out.println(leetCode.numDecodings("12")); + } +} diff --git a/Week 05/id_506/LeetCode_32_506.java b/Week 05/id_506/LeetCode_32_506.java new file mode 100644 index 000000000..56e067d6b --- /dev/null +++ b/Week 05/id_506/LeetCode_32_506.java @@ -0,0 +1,32 @@ +class Solution { + public int longestValidParentheses(String s) { + int max = 0; + int dp[] = new int[s.length()]; + + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + + if (i >= 2){ + dp[i] = dp[i - 2] + 2; + }else { + dp[i] = 2; + } + + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + + if (i - dp[i - 1] >= 2){ + + dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2; + }else { + dp[i] = dp[i - 1] + 2; + } + + } + max = Math.max(max, dp[i]); + } + } + return max; + + } +} \ No newline at end of file diff --git a/Week 05/id_506/LeetCode_64_506.java b/Week 05/id_506/LeetCode_64_506.java new file mode 100644 index 000000000..dc16d61e4 --- /dev/null +++ b/Week 05/id_506/LeetCode_64_506.java @@ -0,0 +1,34 @@ +class Solution { + public int minPathSum(int[][] grid) { + + int[][] dp = new int[grid.length][grid[0].length]; + + dp[0][0] = grid[0][0]; + + for (int i = 0; i < grid.length; i++){ + + for (int j = 0; j < grid[0].length; j++){ + + if (i == 0 && j == 0){ + dp[i][j] = grid[0][0]; + }else if (i == 0 && j != 0){ + + dp[i][j] = dp[i][j-1] + grid[i][j]; + + }else if (j == 0 & i != 0){ + + dp[i][j] = dp[i-1][j] + grid[i][j]; + + }else { + dp[i][j] = grid[i][j] + Math.min(dp[i-1][j], dp[i][j-1]); + } + + } + } + + return dp[grid.length-1][grid[0].length-1]; + + + + } +} \ No newline at end of file diff --git a/Week 05/id_511/LeetCode_211_511.java b/Week 05/id_511/LeetCode_211_511.java new file mode 100644 index 000000000..4e00bb6bb --- /dev/null +++ b/Week 05/id_511/LeetCode_211_511.java @@ -0,0 +1,26 @@ +package id_511; + +/** + * @version 1.0 + * @Description: 最大正方形 + * @author: bingyu + * @date: 2019/11/17 23:03 + */ +public class LeetCode_211_511 { + + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } + +} diff --git a/Week 05/id_511/LeetCode_621_511.java b/Week 05/id_511/LeetCode_621_511.java new file mode 100644 index 000000000..79b54988c --- /dev/null +++ b/Week 05/id_511/LeetCode_621_511.java @@ -0,0 +1,45 @@ +package id_511; + +import java.util.Arrays; +import java.util.List; + +/** + * @version 1.0 + * @Description: 任务调度器s + * @author: bingyu + * @date: 2019/11/17 22:58 + */ +public class LeetCode_621_511 { + + /** + * 解题思路: + * 1、将任务按类型分组,正好A-Z用一个int[26]保存任务类型个数 + * 2、对数组进行排序,优先排列个数(count)最大的任务, + * 如题得到的时间至少为 retCount =(count-1)* (n+1) + 1 ==> A->X->X->A->X->X->A(X为其他任务或者待命) + * 3、再排序下一个任务,如果下一个任务B个数和最大任务数一致, + * 则retCount++ ==> A->B->X->A->B->X->A->B + * 4、如果空位都插满之后还有任务,那就随便在这些间隔里面插入就可以,因为间隔长度肯定会大于n,在这种情况下就是任务的总数是最小所需时间 + */ + public int leastInterval(char[] tasks, int n) { + if (tasks.length <= 1 || n < 1) return tasks.length; + //步骤1 + int[] counts = new int[26]; + for (int i = 0; i < tasks.length; i++) { + counts[tasks[i] - 'A']++; + } + //步骤2 + Arrays.sort(counts); + int maxCount = counts[25]; + int retCount = (maxCount - 1) * (n + 1) + 1; + int i = 24; + //步骤3 + while (i >= 0 && counts[i] == maxCount) { + retCount++; + i--; + } + //步骤4 + return Math.max(retCount, tasks.length); + } + + +} diff --git a/Week 05/id_511/NOTE.md b/Week 05/id_511/NOTE.md index a6321d6e2..1e3889a69 100644 --- a/Week 05/id_511/NOTE.md +++ b/Week 05/id_511/NOTE.md @@ -1,4 +1,10 @@ -# NOTE - - - +DP其实和递归、分治、回溯、贪心异曲同工 +处理DP步骤 +a. 分解成子问题 +b. 设置状态数组 +c. 编写DP方程 +只有多练了,多理解了。 +总结: 目前大多数知识还需要靠时间不断的练习去消化,绝不是那么快就能掌握的,需要工作之余多抽时间不断去训练才行。 + + + diff --git a/Week 05/id_516/LeetCode_32_516.java b/Week 05/id_516/LeetCode_32_516.java new file mode 100644 index 000000000..78771a7f8 --- /dev/null +++ b/Week 05/id_516/LeetCode_32_516.java @@ -0,0 +1,42 @@ +package com.hjj.leetcode.nov17; + +import java.util.Stack; + +public class LeetCode32 { + public int longestValidParentheses(String s) { + Stack stack = new Stack<>(); + int max = 0; + int left = -1; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + if (stack.isEmpty()) left = i; + else { + stack.pop(); + if (stack.isEmpty()) max = Math.max(max, i - left); + else max = Math.max(max, i - stack.peek()); + } + } + } + return max; + + } + + + public int longestValidParentheses2(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} diff --git a/Week 05/id_516/LeetCode_64_516.java b/Week 05/id_516/LeetCode_64_516.java new file mode 100644 index 000000000..365530f1c --- /dev/null +++ b/Week 05/id_516/LeetCode_64_516.java @@ -0,0 +1,20 @@ +package com.hjj.leetcode.nov17; + +public class LeetCode64 { + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } +} diff --git a/Week 05/id_516/NOTE.md b/Week 05/id_516/NOTE.md index a6321d6e2..1b79f18cd 100644 --- a/Week 05/id_516/NOTE.md +++ b/Week 05/id_516/NOTE.md @@ -1,4 +1,130 @@ -# NOTE +## 笔记 +> 分治回溯+ 递归 +动态规划 +> +> 分治: 变成子问题 +> +> 本质没有非常大的区别 都是 寻找重复性 +> +> 动态规划 +> +> 2. "Simplifying a complicated problem by breaking it down into simpler sub-problems" (in a recursive manner) 把指数级变成了 多项式级别 +> +> 3. Divide & Conquer + Optimal substructure +> +> 动态规划和递归或分治没有根本上的区别(关键在有无最优的子结构) +> +> 共性:找到重复子问题 +> +> 差异性:最优子结构、中途可以淘汰次优解 + + + +### 模板 + +#### 递归代码模板 + +```java +public void recur(int level,int param) { + // terminator + if (level > MAX_LEVEL) { + return ; + } + // process current logic + process(level,param); + + // drill down + recur(level + 1,newParam); + + // restore current status +} +``` + + + +#### 分治 + +```python +def divide_conquer(problem,param1,param2,...): + # problem terminator 终 + if problem is None: + print_result + return + # prepare data 治 + data = prepare_data(problem) + sub_problems = split_problem(problem,data) + + # conquer subproblems 分 + sub_result1 = self.divide_conquer(sub_problems[0],param1,param2,...) + sub_result2 = self.divide_conquer(sub_problems[1],param1,param2,...) + ... + # process and generate the final result 合并 + result = process_result(sub_result1,sub_result2,...) + + # revert the current level status 复原 + +``` + + + +#### 动态规划模板 + +```java +// 待总结 for 循环 +``` + + + +### 动态规划 + +1. 分治(找子问题) +2. 状态数组定义 +3. 写DP方程 + +> 1. 分治(找子问题)max_sum(i) = Max(max_sum(i - 1),0) + a[i] +> 2. 状态数组定义: f[i] +> 3. DP方程 f[i] = Max(f[i - 1],0) + a[i] + + + +fib (实际上并非动态规划) + +> 1. 分治找子问题 f(n) = f(n - 1) + f(n - 2) +> 2. 状态数组定义 f[i] +> 3. DP 方程 f[i] = f[i - 1] + f[i - 2] + + + +Count the paths + +> 1. 分治找子问题 count(i,j) = count(i+1,j) + count(i,j+1) +> 2. 状态数组定义 ```counts[i][j]``` +> 3. + + + +coin change dp + +> 1.分治(子问题) + + + + + +打家劫舍 + +> 1. 分治(子问题) max_sum(i) = max_sum(i - 2) + a[i] +> +> 2. 状态数组定义 f[i] +> 3. dp方程 f[i] = f[i - 2] + a[i] + + + + + +### 总结 + + +这周出差比较忙,所以学习这块并没有非常用心。 \ No newline at end of file diff --git "a/Week 05/id_521/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.js" "b/Week 05/id_521/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.js" new file mode 100644 index 000000000..6b93015cd --- /dev/null +++ "b/Week 05/id_521/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.js" @@ -0,0 +1,17 @@ +var longestValidParentheses = function(s) { + var max = 0; + var n = s.length; + var dp = new Array(n).fill(0); + for(var i = 1;i < n;i++){ + if(s[i] == ')'){ + if(s[i-1] == '('){ + dp[i] = ( i >= 2 ? dp[i-2] : 0) + 2; + } + else if(i - dp[i-1] > 0 && s[i - dp[i-1] - 1] == '('){ + dp[i] = dp[i-1] + ( (i - dp[i-1] >= 2) ? dp[i - dp[i-1] - 2] : 0 ) + 2; + } + max = Math.max(max,dp[i]); + } + } + return max; +}; \ No newline at end of file diff --git "a/Week 05/id_521/72.\347\274\226\350\276\221\350\267\235\347\246\273.js" "b/Week 05/id_521/72.\347\274\226\350\276\221\350\267\235\347\246\273.js" new file mode 100644 index 000000000..ca068c2ea --- /dev/null +++ "b/Week 05/id_521/72.\347\274\226\350\276\221\350\267\235\347\246\273.js" @@ -0,0 +1,21 @@ +var minDistance = function (word1, word2) { + let D = []; + for (let i = 0; i <= word1.length; i++) { + if (D[i] === undefined) { + D[i] = []; + } + for (let j = 0; j <= word2.length; j++) { + if (i === 0) { + D[i][j] = j; + + } else if (j === 0) { + D[i][j] = i; + } else if (word1[i - 1] === word2[j - 1]) { + D[i][j] = D[i-1][j-1]; + } else { + D[i][j] = Math.min(D[i - 1][j] + 1, D[i][j - 1] + 1, D[i-1][j - 1] + 1); + } + } + } + return D[word1.length][word2.length] +}; \ No newline at end of file diff --git "a/Week 05/id_521/\347\254\224\350\256\260.txt" "b/Week 05/id_521/\347\254\224\350\256\260.txt" new file mode 100644 index 000000000..7ab959ca3 --- /dev/null +++ "b/Week 05/id_521/\347\254\224\350\256\260.txt" @@ -0,0 +1,8 @@ + 1. DPʵͷΡݡ̰ͬ + 2. DP + a. ֽ + b. ״̬ + c. дDP +3. ֻжˣˡ + +ܽ᣺ Ѷ̫ˣ ϰ˵ִֻֽܴգ֮ϸϸƷˣʵû̫ʱ䡣 \ No newline at end of file diff --git a/Week 05/id_526/LeetCode_72_526 b/Week 05/id_526/LeetCode_72_526 new file mode 100644 index 000000000..2d54606ad --- /dev/null +++ b/Week 05/id_526/LeetCode_72_526 @@ -0,0 +1,36 @@ +class Solution { + public int minDistance(String word1, String word2) { + int n = word1.length(); + int m = word2.length(); + + // if one of the strings is empty + if (n * m == 0) + return n + m; + + // array to store the convertion history + int [][] d = new int[n + 1][m + 1]; + + // init boundaries + for (int i = 0; i < n + 1; i++) { + d[i][0] = i; + } + for (int j = 0; j < m + 1; j++) { + d[0][j] = j; + } + + // DP compute + for (int i = 1; i < n + 1; i++) { + for (int j = 1; j < m + 1; j++) { + int left = d[i - 1][j] + 1; + int down = d[i][j - 1] + 1; + int left_down = d[i - 1][j - 1]; + if (word1.charAt(i - 1) != word2.charAt(j - 1)) + left_down += 1; + d[i][j] = Math.min(left, Math.min(down, left_down)); + + } + } + return d[n][m]; + + } +} \ No newline at end of file diff --git a/Week 05/id_526/LeetCode_76_526 b/Week 05/id_526/LeetCode_76_526 new file mode 100644 index 000000000..adeaebb30 --- /dev/null +++ b/Week 05/id_526/LeetCode_76_526 @@ -0,0 +1,29 @@ +class Solution { + public String minWindow(String s, String t) { + int[] map = new int[128]; + for(char c : t.toCharArray()) { + ++map[c]; + } + int start = 0, end = 0, counter = t.length(); + int[] ans = {-1, 0, 0}; + while (end < s.length()) { + if (map[s.charAt(end)]-- > 0){ + --counter; + } + end++; + while (counter == 0) { + if (ans[0] == -1 || ans[0] > end - start) { + ans[0] = end - start; + ans[1] = start; + ans[2] = end; + } + if (++map[s.charAt(start)] > 0){ + ++counter; + } + start++; + } + + } + return ans[0] == -1 ? "" : s.substring(ans[1], ans[2]); + } +} \ No newline at end of file diff --git a/Week 05/id_531/leetCode_221_531.go b/Week 05/id_531/leetCode_221_531.go new file mode 100644 index 000000000..8cb77f4cb --- /dev/null +++ b/Week 05/id_531/leetCode_221_531.go @@ -0,0 +1,32 @@ +package id_531 + +func maximalSquare(matrix [][]byte) int { + rows := len(matrix) + var cols int + if rows > 0 { + cols = len(matrix[0]) + } + dp := make([][]int, rows+1) + for i := 0; i <= rows; i++ { + dp[i] = make([]int, cols+1) + } + var maxSquare int + for i := 1; i <= rows; i++ { + for j := 1; j <= cols; j++ { + if matrix[i-1][j-1] == '1' { + dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1 + if maxSquare < dp[i][j] { + maxSquare = dp[i][j] + } + } + } + } + return maxSquare * maxSquare +} + +//func min(i, j int) int { +// if i < j { +// return i +// } +// return j +//} diff --git a/Week 05/id_531/leetCode_64_531.go b/Week 05/id_531/leetCode_64_531.go new file mode 100644 index 000000000..c16bf6db8 --- /dev/null +++ b/Week 05/id_531/leetCode_64_531.go @@ -0,0 +1,44 @@ +package id_531 + +// 暴力 +func MinPathSumBrust(grid [][]int) int { + // 1. 终止条件 + // 2. 当成逻辑 + // 3. 下层逻辑 + // 4. 恢复状态 + return 0 +} + +// DP +// a. 分治(重复子问题):pb(m,n)=min(sub(m,n+1),sub(m+1,n))+grid(m,n) +// b. 定义状态空间: grid[m][n]: 左上角到m行n 列中数字和 +// c. DP 方程 f[m][n]=min +func minPathSum(grid [][]int) int { + m := len(grid) + n := len(grid[0]) + dp := make([][]int, m) + for i := 0; i < m; i++ { + dp[i] = make([]int, n) + } + for i := m - 1; i >= 0; i-- { + for j := n - 1; j >= 0; j-- { + if i == m-1 && j != n-1 { + dp[i][j] = grid[i][j] + dp[i][j+1] + } else if j == n-1 && i != m-1 { + dp[i][j] = grid[i][j] + dp[i+1][j] + } else if i != m-1 && j != n-1 { + dp[i][j] = grid[i][j] + min(dp[i+1][j], dp[i][j+1]) + } else { + dp[i][j] = grid[i][j] + } + } + } + return dp[0][0] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/Week 05/id_536/leetcode_1143_536.cpp b/Week 05/id_536/leetcode_1143_536.cpp new file mode 100644 index 000000000..0cc99e53b --- /dev/null +++ b/Week 05/id_536/leetcode_1143_536.cpp @@ -0,0 +1,46 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1DP + ʱ临ӶO(len1*len2) + ******/ + int dp(string text1, string text2) + { + int len1 = text1.size(); + int len2 = text2.size(); + int ans[len1+1][len2+1]; + memset(ans,0,sizeof(ans)); + for(int i=1;i<=len1;++i) + { + for(int j=1;j<=len2;++j) + { + if(text1[i-1] == text2[j-1]) + ans[i][j] = ans[i-1][j-1] + 1; + else + ans[i][j] = max(ans[i-1][j],ans[i][j-1]); + } + } + return ans[len1][len2]; + } + + int longestCommonSubsequence(string text1, string text2) { + int res; + res = dp(text1,text2); + return res; + } +}; + +int main() +{ + Solution s; + string text1 = "bsbininm"; + string text2 = "jmjkbkjkv"; + int res = s.longestCommonSubsequence(text1,text2); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_120_536.cpp b/Week 05/id_536/leetcode_120_536.cpp new file mode 100644 index 000000000..fd3bae195 --- /dev/null +++ b/Week 05/id_536/leetcode_120_536.cpp @@ -0,0 +1,103 @@ +#include +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1DP + ʱ临ӶO(n*n) + *******/ + int dp(vector>& triangle) + { + int n = triangle.size();// + if(n == 0) + return 0; + if(n == 1) + return triangle[0][0]; + + //Աͳһ߼ + int ans[n+1][n+1]; + for(int i=0;i<=n;++i) + for(int j=0;j<=n;++j) + ans[i][j] = INT_MAX; + ans[0][0] = 0; + ans[0][1] = 0; + + int temp = INT_MAX; + for(int i = 1; i <= n ; ++i) + { + for(int j = 1; j <= triangle[i-1].size(); ++j) + { + //ͼʾԶ¿ݽṹֻ··· + ans[i][j] = min(ans[i-1][j-1],ans[i-1][j]) + triangle[i-1][j-1]; + if(i == n && ans[i][j] < temp)//һнСļΪ + temp = ans[i][j]; + } + } + return temp; + } + + /****** + ⷨ2DP + ʱ临ӶO(n*n) + *******/ + int dp2(vector>& triangle) + { + int n = triangle.size();// + if(n == 0) + return 0; + if(n == 1) + return triangle[0][0]; + int ans[n][n]; + //vector> ans(n,vector(n)); + ans[0][0] = triangle[0][0]; + + int temp = INT_MAX; + for(int i = 1; i < n ; ++i) + { + for(int j = 0; j < triangle[i].size(); ++j) + { + if(j == 0)//1 + ans[i][j] = ans[i-1][j] + triangle[i][j]; + else if(j == triangle[i].size() - 1)//ÿһ + ans[i][j] = ans[i-1][j-1] + triangle[i][j]; + else + ans[i][j] = min(ans[i-1][j-1],ans[i-1][j]) + triangle[i][j]; + + if(i == n-1 && ans[i][j] < temp)//һнСļΪ + temp = ans[i][j]; + } + } + return temp; + } + + int minimumTotal(vector>& triangle) { + int res; + //res = dp(triangle);//ⷨ1 + res = dp2(triangle);//ⷨ2 + return res; + } +}; + +int main() +{ + Solution s; + vector> triangle{{2},{3,4},{6,5,7},{4,1,8,3}};//԰Ԥ11 + /********ⷨ1ans[n+1][n+1]ֵ仯· + 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 + ---------- ---------- ---------- ---------- + 0|0 0 m m m 0|0 0 m m m 0|0 0 m m m 0|0 0 m m m + 1|m m m m m 1|m 2 m m m 1|m 2 m m m 1|m 2 m m m + 2|m m m m m -> 2|m m m m m -> 2|m 5 6 m m -> 2|m 5 6 m m + 3|m m m m m 3|m m m m m 3|m m m m m 3|m 11 10 13 m + 4|m m m m m 4|m m m m m 4|m m m m m 4|m 15 11 18 16 -> res = 11 + *********/ + //vector> triangle{{-1},{-2,-3}};//԰Ԥ-4 + //vector> triangle{{-1},{3,2},{-3,1,-1}};//԰Ԥ-1 + int res = s.minimumTotal(triangle); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_121_536.cpp b/Week 05/id_536/leetcode_121_536.cpp new file mode 100644 index 000000000..62646278f --- /dev/null +++ b/Week 05/id_536/leetcode_121_536.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +using namespace std; + +/*DP,leetcod_121 + ʱ临ӶO(n) + ռ临ӶO(n) +*/ +class Solution { +public: + int maxProfit(vector& prices) { + //terminator + int n = prices.size(); + if(n == 0) return 0; + + //initial + int dp[n][2]; + //memset(dp,0,sizeof(dp)); + dp[0][0] = 0; //ʼһdz״̬ + dp[0][1] = -prices[0];//ʼһ״̬ + + //process + for(int i=1;i prices{7,1,5,3,6,4};//Ԥڽ5 + //vector prices{7,6,4,3,1};//Ԥڽ0 + int res = s.maxProfit(prices); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_123_536.cpp b/Week 05/id_536/leetcode_123_536.cpp new file mode 100644 index 000000000..e4477cbf7 --- /dev/null +++ b/Week 05/id_536/leetcode_123_536.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +using namespace std; + +/*̬滮˼· + 0ǰ᣺Ե뵱 + ʱ临ӶȣO(n*k),nΪ,kΪ״ + ռ临ӶȣO(n*k),ԼΪO(1) + 1DP״̬壺 + dp[i][j][0]ʾi졢jʽסйƱ + dp[i][j][1]ʾi졢jʽסйƱ + ע0 <= i < prices.size();0 < j <= k; + 漴Ϊdp[prices.size()-1][k][0] + ע1죬kʽףҹƱȫ + 2DP״̬̣ + dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1] + prices[i]); + Ϣ + dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j-1][0] - prices[i]); + Ϣ + 3ʼ + dp[0][j][0] = 0; + dp[0][j][1] = -prices[0]; +*/ +class Solution { +public: + int maxProfit(vector& prices) { + //terminator + int n = prices.size(); + if(n == 0) return 0; + + //initial + const int k = 2; //ཻ2 + int dp[n][k+1][2]; //k+1Ϊ˷ֹ״̬±j-1<0쳣 + memset(dp,0,sizeof(dp)); + for(int i=1;i<=k;++i)//ʼһ״̬ + dp[0][i][1] = -prices[0]; + + //process + for(int i=1;i prices{3,3,5,0,0,3,1,4}; + vector prices{1,2,3,4,5}; + int res = s.maxProfit(prices); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_152_536.cpp b/Week 05/id_536/leetcode_152_536.cpp new file mode 100644 index 000000000..5a1c75d05 --- /dev/null +++ b/Week 05/id_536/leetcode_152_536.cpp @@ -0,0 +1,110 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1:DP + ʱ临ӶO(n) + ռ临ӶO(1) + *****/ + int helper1(vector& nums) { + int n = nums.size(); + if(n == 1) + return nums[0]; + + int curMax = 1; + int curMin = 1; + int res = INT_MIN; + + for(int i=0;i& nums) { + int n = nums.size(); + if(n == 1) + return nums[0]; + + int curMax = 1; + int curMin = 1; + int res = INT_MIN; + + for(int i=0;i& nums) { + int n = nums.size(); + if(n == 1) + return nums[0]; + + int dpMax[n]; + int dpMin[n]; + dpMax[0] = nums[0]; + dpMin[0] = nums[0]; + int res = nums[0]; + + for(int i=1;i& nums) { + int res; + //res = helper1(nums); + //res = helper2(nums); + res = helper3(nums); + return res; + } +}; + +int main() +{ + Solution s; + vector nums{2,3,-2,4};//԰Ԥڽ6 + //vector nums{-2,0,-1};//԰Ԥڽ0 + int res = s.maxProduct(nums); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_198_536.cpp b/Week 05/id_536/leetcode_198_536.cpp new file mode 100644 index 000000000..67b427f80 --- /dev/null +++ b/Week 05/id_536/leetcode_198_536.cpp @@ -0,0 +1,50 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1DP + dp[i]ʾǰiٵ + dp[i] = max( dp[i-2] + nums[i], i + dp[i-1]) i + ʱ临ӶO(n) + ռ临ӶO(n) + ******/ + int helper1(vector& nums) + { + + int n = nums.size(); + if(n == 0) + return 0; + if(n == 1) + return nums[0]; + + vector dp(n,0); + dp[0] = nums[0]; + dp[1] = max(nums[0],nums[1]); + + for(int i = 2; i < n; ++i) + dp[i] = max(dp[i-2] + nums[i], dp[i-1]); + + return dp[n-1]; + } + + int rob(vector& nums) { + int res; + res = helper1(nums); + return res; + } +}; + +int main() +{ + Solution s; + //vector nums{2,1,1,2};//Ԥڽ4 + vector nums{2, 5, 17, 3, 9, 28, 19, 29, 5, 7, 31};//Ԥڽ107 + int res = s.rob(nums); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_213_536.cpp b/Week 05/id_536/leetcode_213_536.cpp new file mode 100644 index 000000000..cb084ca95 --- /dev/null +++ b/Week 05/id_536/leetcode_213_536.cpp @@ -0,0 +1,56 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1DP + leetcode198⣬2 + 1ٵ1ң dp1[i],1& nums) { + int n = nums.size(); + if(n == 0) return 0; + if(n == 1) return nums[0]; + if(n == 2) return max(nums[0],nums[1]); + + vector dp1(n,0);//1 + vector dp2(n,0);//1 + + dp1[0] = 0; + dp2[0] = nums[0]; + dp1[1] = nums[1]; + dp2[1] = max(nums[0],nums[1]); + + for(int i = 2; i < n ; ++i) + { + dp1[i] = max(dp1[i-2] + nums[i],dp1[i-1]);//ٵ1 + if(i < n-1) + dp2[i] = max(dp2[i-2] + nums[i],dp2[i-1]);//1 + } + + return dp1[n-1] > dp2[n-2]? dp1[n-1] : dp2[n-2]; + } + + int rob(vector& nums) { + int res; + res = helper1(nums); + return res; + } +}; + +int main() +{ + Solution s; + vector nums{1,2,3,1};//Ԥڽ4 + //vector nums{2,3,2};//Ԥڽ3 + int res = s.rob(nums); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_322_536.cpp b/Week 05/id_536/leetcode_322_536.cpp new file mode 100644 index 000000000..952c2bd66 --- /dev/null +++ b/Week 05/id_536/leetcode_322_536.cpp @@ -0,0 +1,110 @@ +#include +#include +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1:ݹ + ʱ临ӶO(n) + ռ临ӶO() + *****/ + int helper1(vector& coins, int amount) { + //terminator + if(amount == 0) + return 1; + + //process + + //drill + + //combine + + } + + /***** + ⷨ2:DP + dp̣f(n) = { 0 ; n=0 + 1 + min{f(n-Ci)}; n>0 + ע:nΪCiΪӲֵiΪֵ + ʱ临ӶO(n*amount),nΪӲ + ռ临ӶO(amount) + *****/ + int helper2(vector& coins, int amount) { + vector dp(amount+1,amount+1); + dp[0] = 0; + for(int i = 1; i <= amount; ++i) + { + for(int j = 0; j < coins.size(); ++j) + { + if(coins[j] <= i) + dp[i] = min(dp[i-coins[j]] + 1,dp[i]); + } + } + return dp[amount] == amount +1 ? -1 : dp[amount]; + } + + /***** + ⷨ3:BFS + ֦ + ?ʱ临ӶO(2^n-T),nΪ㼶ȥ֦ĸʱT + *****/ + int helper3(vector& coins, int amount) { + queue q; //洢ʣamount + set visited; //ѷʹڼ֦ + q.push(amount); + int res = 0; //Ҹ + while(!q.empty()) + { + ++res; + int width = q.size(); + while(width--) + { + int curAmount = q.front(); + q.pop(); + for(int i=0;i& coins, int amount) { + int res; + int n = coins.size(); + if(n == 0) //ӲҸ0 + return -1; + if(amount == 0) //0 + return 0; + + //ݹ鿪ʼ + //res = helper1(coins,amount); + //ݹ + res = helper2(coins,amount);//BFS + //res = helper3(coins,amount);//BFS + + return res; + } +}; + +int main() +{ + Solution s; + vector coins{1,2,5}; + int amount = 100; + int res = s.coinChange(coins,amount); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_53_536.cpp b/Week 05/id_536/leetcode_53_536.cpp new file mode 100644 index 000000000..e90479f2e --- /dev/null +++ b/Week 05/id_536/leetcode_53_536.cpp @@ -0,0 +1,73 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1DP + ʱ临ӶO(n) + ռ临ӶO(n) + ******/ + int helper1(vector& nums) + { + int n = nums.size(); + if(n == 0) + return 0; + if(n == 1) + return nums[0]; + + int dp[n]; + dp[0] = nums[0]; + + int res = nums[0]; + for(int i=1;i& nums) + { + int n = nums.size(); + if(n == 0) + return 0; + if(n == 1) + return nums[0]; + + int cur; + int pre = nums[0]; + int res = nums[0]; + for(int i=1;i& nums) { + int res; + //res = helper1(nums);//DP + res = helper2(nums);//DP2 + return res; + } +}; + +int main() +{ + Solution s; + vector nums{-2,1,-3,4,-1,2,1,-5,4};//԰Ԥڽ6 + int res = s.maxSubArray(nums); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_536/leetcode_62_536.cpp b/Week 05/id_536/leetcode_62_536.cpp new file mode 100644 index 000000000..c641e55b2 --- /dev/null +++ b/Week 05/id_536/leetcode_62_536.cpp @@ -0,0 +1,74 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /****** + ⷨ1ݹ飬ʱ + ʱ临ӶȣO(2^n) + *******/ + int helper(int x,int y,int m,int n,int &res) + { + //terminator + if(x == 0 || y == 0) + return 1; + + //process,recurse + res = helper(x-1,y,m,n,res) + helper(x,y-1,m,n,res); + + return res; + } + + int recurse(int m,int n) + { + if(m<=0 || n<=0) + return 0; + if(m==1 || n==1) + return 1; + int res = 0; + helper(m-1,n-1,m,n,res); + return res; + } + + /****** + ⷨ2DP + ʱ临ӶO(m*n) + *******/ + int dp(int m,int n) + { + int dp[m][n]; + //memset(dp,0,sizeof(dp)); + for(int i=0;i +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1DP + ʱ临ӶO(n) + *****/ + int dp(int n) + { + if(n == 0 || n == 1) + return n; + int ans[n+1] = {0}; + ans[1] = 1; + ans[2] = 2; + for(int i=3;i<=n;++i) + ans[i] = ans[i-1] + ans[i-2]; + return ans[n]; + } + + /***** + ⷨ2ݹ飬мݴ + ʱ临ӶO(n) + *****/ + int recurse(int n,vector& ans) + { + //terminator + if(n == 1) + return 1; + if(n == 2) + return 2; + + //process,drill + if(ans[n] == 0) + ans[n] = recurse(n-1,ans)+recurse(n-2,ans); + + return ans[n]; + + } + + int climbStairs(int n) { + int res; + //res = dp(n);//̬滮 + //ݹ鿪ʼ + vector ans(n+1,0); + res = recurse(n,ans); + //ݹ + return res; + } +}; + +int main() +{ + Solution s; + int n = 5; + int res = s.climbStairs(n); + cout << res << endl; + return 0; +} diff --git a/Week 05/id_546/LeetCode_221_546.cs b/Week 05/id_546/LeetCode_221_546.cs new file mode 100644 index 000000000..468ad4f5c --- /dev/null +++ b/Week 05/id_546/LeetCode_221_546.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 221. 最大正方形 + /// + public class MaximalSquare + { + public int MaximalSquare1(char[][] matrix) + { + if (matrix.Length == 0) return 0; + int m = matrix.Length, n = matrix[0].Length, result = 0; + int[,] b = new int[m + 1,n + 1]; + for (int i = 1; i <= m; i++) + { + for (int j = 1; j <= n; j++) + { + if (matrix[i - 1][j - 1] == '1') + { + b[i,j] = Math.Min(Math.Min(b[i,j - 1], b[i - 1,j - 1]), b[i - 1,j]) + 1; + result = Math.Max(b[i,j], result); + } + } + } + return result * result; + } + } +} diff --git a/Week 05/id_546/LeetCode_32_546.cs b/Week 05/id_546/LeetCode_32_546.cs new file mode 100644 index 000000000..d3ad493e1 --- /dev/null +++ b/Week 05/id_546/LeetCode_32_546.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hard +{ + /// + /// 32. 最长有效括号 + /// + public class LongestValidParentheses + { + public int LongestValidParentheses1(string s) + { + Stack stack = new Stack(); + int max = 0; + int left = -1; + for (int j = 0; j < s.Length; j++) + { + if (s[j] == '(') + { + stack.Push(j); + } + else + { + if (!stack.Any()) + { + left = j; + } + else + { + stack.Pop(); + if (!stack.Any()) + { + max = Math.Max(max, j - left); + } + else max = Math.Max(max, j - stack.Peek()); + } + } + } + return max; + } + } +} diff --git a/Week 05/id_546/LeetCode_64_546.cs b/Week 05/id_546/LeetCode_64_546.cs new file mode 100644 index 000000000..e6565fba3 --- /dev/null +++ b/Week 05/id_546/LeetCode_64_546.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 64. 最小路径和 + /// + public class MinimumPathSum + { + public int MinPathSum(int[][] grid) + { + int m = grid.Length; + int n = grid[0].Length; + for (int i = 1; i < n; i++) + { + grid[0][i] += grid[0][i - 1]; + } + for (int i = 1; i < m; i++) + { + grid[i][0] += grid[i - 1][0]; + for (int j = 1; j < n; j++) + { + grid[i][j] += Math.Min(grid[i][j - 1], grid[i - 1][j]); + } + } + return grid[m - 1][n - 1]; + } + + + public int MinPathSum2(int[][] grid) + { + int m = grid.Length, n = grid[0].Length; + + int[][] minSum = new int[m][]; + + for(int i=0;i 0) minSum[i][j] = minSum[i][j - 1] + grid[i][j]; + else if (j == 0 && i > 0) minSum[i][j] = minSum[i - 1][j] + grid[i][j]; + else if (i > 0 && j > 0) minSum[i][j] = Math.Min(minSum[i][j - 1], minSum[i - 1][j]) + grid[i][j]; + } + } + return minSum[m - 1][n - 1]; + } + + + public int MinPathSum3(int[][] grid) + { + int m = grid.Length, n = grid[0].Length; + + int[,] minSum = new int[m,n]; + minSum[0,0] = grid[0][0]; + for (int i = 0; i < m; i++) + { + + + for (int j = 0; j < n; j++) + { + if (i == 0 && j > 0) minSum[i,j] = minSum[i,j - 1] + grid[i][j]; + else if (j == 0 && i > 0) minSum[i,j] = minSum[i - 1,j] + grid[i][j]; + else if (i > 0 && j > 0) minSum[i,j] = Math.Min(minSum[i,j - 1], minSum[i - 1,j]) + grid[i][j]; + } + } + return minSum[m - 1,n - 1]; + } + } +} diff --git a/Week 05/id_546/LeetCode_72_546.cs b/Week 05/id_546/LeetCode_72_546.cs new file mode 100644 index 000000000..b94f217a7 --- /dev/null +++ b/Week 05/id_546/LeetCode_72_546.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hard +{ + /// + /// 72. 编辑距离 + /// + public class EditDistance + { + public int MinDistance(string word1, string word2) + { + int m = word1.Length; + int n = word2.Length; + + int[,] cost = new int[m + 1,n + 1]; + for (int i = 0; i <= m; i++) + cost[i,0] = i; + for (int i = 1; i <= n; i++) + cost[0,i] = i; + + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + if (word1[i] == word2[j]) + cost[i + 1,j + 1] = cost[i,j]; + else + { + int a = cost[i,j]; + int b = cost[i,j + 1]; + int c = cost[i + 1,j]; + cost[i + 1,j + 1] = a < b ? (a < c ? a : c) : (b < c ? b : c); + cost[i + 1,j + 1]++; + } + } + } + return cost[m,n]; + } + } +} diff --git a/Week 05/id_546/LeetCode_91_546.cs b/Week 05/id_546/LeetCode_91_546.cs new file mode 100644 index 000000000..9012828cb --- /dev/null +++ b/Week 05/id_546/LeetCode_91_546.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 91. 解码方法 + /// + public class DecodeWays + { + public int NumDecodings(string s) + { + if (s == null || s.Length == 0) + { + return 0; + } + int n = s.Length; + int[] dp = new int[n]; + dp[0] = s[0] != '0' ? 1 : 0; + + for (int i = 1; i < n; i++) + { + int first = int.Parse( s.Substring(i, 1)); + int second = int.Parse(s.Substring(i - 1,2)); + if (first >= 1 && first <= 9) + { + dp[i] += dp[i - 1]; + } + if (second >= 10 && second <= 26) + { + dp[i] += i >= 2 ? dp[i - 2] : 1; + } + } + return dp[n - 1]; + } + + + public int numDecodings2(String s) + { + int n = s.Length; + if (n == 0) return 0; + + int[] memo = new int[n + 1]; + memo[n] = 1; + memo[n - 1] = s[n - 1] != '0' ? 1 : 0; + + for (int i = n - 2; i >= 0; i--) + if (s[i] == '0') continue; + else memo[i] = (int.Parse(s.Substring(i, 2)) <= 26) ? memo[i + 1] + memo[i + 2] : memo[i + 1]; + + return memo[0]; + } + } +} diff --git a/Week 05/id_551/LeetCode_32_551.py b/Week 05/id_551/LeetCode_32_551.py new file mode 100644 index 000000000..7ada5c475 --- /dev/null +++ b/Week 05/id_551/LeetCode_32_551.py @@ -0,0 +1,15 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + n = len(s) + if n == 0: return 0 + dp = [0] * n + res = 0 + for i in range(n): + if i>0 and s[i] == ")": + if s[i - 1] == "(": + dp[i] = dp[i - 2] + 2 + elif s[i - 1] == ")" and i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == "(": + dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2] + if dp[i] > res: + res = dp[i] + return res diff --git a/Week 05/id_551/LeetCode_64_551.swift b/Week 05/id_551/LeetCode_64_551.swift new file mode 100644 index 000000000..2d3165756 --- /dev/null +++ b/Week 05/id_551/LeetCode_64_551.swift @@ -0,0 +1,23 @@ +class Solution { + func minPathSum(_ grid: [[Int]]) -> Int { + let width = grid.count + let height = grid[0].count + var dp = [[Int]](repeating: [Int](repeating: 0, count: height), count: width) + for i in 0.. 0 + let jMark = j > 0 + if iMark && jMark { + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] + } else if iMark { + dp[i][j] = dp[i - 1][j] + grid[i][j] + } else if jMark { + dp[i][j] = dp[i][j - 1] + grid[i][j] + } else { + dp[i][j] = grid[i][j] + } + } + } + return (dp.last?.last)! + } +} diff --git a/Week 05/id_556/LeetCode_198_556.java b/Week 05/id_556/LeetCode_198_556.java new file mode 100644 index 000000000..f173436c3 --- /dev/null +++ b/Week 05/id_556/LeetCode_198_556.java @@ -0,0 +1,29 @@ +public class Robber198 { + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 1}; + System.out.println(rob(nums)); + } + + public static int rob(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int n = nums.length; + if (n == 1) { + return nums[0]; + } + + int[][] a = new int[n][2]; + + a[0][0] = 0; + a[0][1] = nums[0]; + + for (int i = 1; i < n; ++i) { + a[i][0] = Math.max(a[i - 1][0], a[i - 1][1]); + a[i][1] = a[i - 1][0] + nums[i]; + } + + return Math.max(a[n - 1][0], a[n - 1][1]); + } +} diff --git a/Week 05/id_556/LeetCode_32_556.java b/Week 05/id_556/LeetCode_32_556.java new file mode 100644 index 000000000..6c49c51e3 --- /dev/null +++ b/Week 05/id_556/LeetCode_32_556.java @@ -0,0 +1,114 @@ +import java.util.Stack; + +public class Brackets32 { + public static void main(String[] args) { + Brackets32 brackets32 = new Brackets32(); + System.out.println(brackets32.longestValidParentheses("(")); + System.out.println(brackets32.longestValidParentheses2("")); + System.out.println(brackets32.longestValidParentheses2("(")); + } + + // 1. brutal force (O(n^2)) + public int longestValidParentheses(String s) { + int max = 0; + for (int i = 0; i < s.length(); ++i) { + for (int j = i + 2; j <= s.length(); j += 2) { + if (isValid(s.substring(i, j))) { + max = Math.max(max, j - i); + } + } + } + return max; + } + + private boolean isValid(String s) { + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '(') { + stack.push('('); + } else if (!stack.isEmpty() && stack.peek() == '(') { + // s.charAt(i) ==')' + stack.pop(); + } else { + return false; + } + } + return stack.isEmpty(); + } + + // 2. DP (O(n)) + public int longestValidParentheses2(String s) { + int max = 0; + if (s == null || s.length() == 0) { + return 0; + } + int n = s.length(); + int[] dp = new int[n]; + for (int i = 1; i < n; i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] >= 1) { + if (s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + } + max = Math.max(max, dp[i]); + } + } + return max; + } + + // 3. Stack (O(n)但由于出入栈操作导致比DP慢) + public int longestValidParentheses3(String s) { + int max = 0; + Stack stack = new Stack<>(); + stack.push(-1); + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + max = Math.max(max, i - stack.peek()); + } + } + } + return max; + } + + // 4. Scan + public int longestValidParentheses4(String s) { + int l = 0, r = 0, max = 0; + // scan left to right + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '(') { + l++; + } else { + r++; + } + if (l == r) { + max = Math.max(max, l + r); + } else if (r > l) { + l = r = 0; + } + } + l = r = 0; + // scan right to left + for (int i = s.length() - 1; i >= 0; --i) { + if (s.charAt(i) == '(') { + l++; + } else { + r++; + } + if (l == r) { + max = Math.max(max, l + r); + } else if (l > r) { + l = r = 0; + } + } + return max; + } +} \ No newline at end of file diff --git a/Week 05/id_556/LeetCode_72_556.java b/Week 05/id_556/LeetCode_72_556.java new file mode 100644 index 000000000..d2d3a1b10 --- /dev/null +++ b/Week 05/id_556/LeetCode_72_556.java @@ -0,0 +1,133 @@ +import java.util.ArrayList; +import java.util.List; + +public class EditDistance72 { + public static void main(String[] args) { + EditDistance72 editDistance72 = new EditDistance72(); +// System.out.println(editDistance72.minDistance("horse", "ros")); + System.out.println(editDistance72.minDistance2("intention", "execution")); + // !!! ArrayIndexOutOfBoundsException to be resolve +// editDistance72.minSequence("intention", "execution").forEach(System.out::println); + editDistance72.minSequence("horse", "ros").forEach(System.out::println); + } + + // 1. recursive brutal force (top-down) + public int minDistance(String word1, String word2) { + return dp(word1.length() - 1, word2.length() - 1, word1, word2); + } + + private int dp(int i, int j, String word1, String word2) { + if (i == -1) { + return j + 1; + } + if (j == -1) { + return i + 1; + } + if (word1.charAt(i) == word2.charAt(j)) { + return dp(i - 1, j - 1, word1, word2); + } else { + int insert = dp(i, j - 1, word1, word2) + 1; + int delete = dp(i - 1, j, word1, word2) + 1; + int replace = dp(i - 1, j - 1, word1, word2) + 1; + return Math.min(insert, Math.min(delete, replace)); + } + } + + // 2. memoization (bottom up) + public int minDistance2(String word1, String word2) { + int m = word1.length(), n = word2.length(); + int[][] dp = new int[m + 1][n + 1]; + + // only one char, to delete + for (int i = 0; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 0; j <= n; j++) { + dp[0][j] = j; + } + + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1; + } + } + } + return dp[m][n]; + } + + // 3. get the edit sequence + class Node { + int distance; + int operation; // 0: skip 1: insert 2:delete 3: replace + + Node(int distance, int operation) { + this.distance = distance; + this.operation = operation; + } + } + + public List minSequence(String word1, String word2) { + int m = word1.length(), n = word2.length(); + List> nodes = new ArrayList<>(); + for (int i = 0; i <= m; i++) { + nodes.add(new ArrayList(n + 1)); + } + + for (int i = 0; i <= m; i++) { + Node node = new Node(i, 2); + nodes.get(i).add(0, node); + } + for (int j = 0; j <= n; j++) { + Node node = new Node(j, 2); + nodes.get(0).add(j, node); + } + + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + int t = nodes.get(i - 1).get(j - 1).distance; + Node node = new Node(t, 0); + nodes.get(i).add(j, node); + } else { + int insert = nodes.get(i).get(j - 1).distance + 1; + int delete = nodes.get(i - 1).get(j).distance + 1; + int replace = nodes.get(i - 1).get(j - 1).distance + 1; + int min = Math.min(insert, Math.min(delete, replace)); + int oper = 0; + if (min == insert) { + oper = 1; + } else if (min == delete) { + oper = 2; + } else if (min == replace) { + oper = 3; + } + Node node = new Node(min, oper); + nodes.get(i).add(j, node); + } + } + } + + // print the operations + List operations = new ArrayList<>(); + Node lastNode = nodes.get(m).get(n); + for (int i = m; i > 0; ) { + for (int j = n; j > 0; ) { + int operation = lastNode.operation; + if (operation > 0) { + operations.add(operation); + } + if (operation == 1) { + lastNode = nodes.get(i).get(j--); + } else if (operation == 2) { + lastNode = nodes.get(i--).get(j); + } else if (operation == 0 || operation == 3) { + lastNode = nodes.get(i--).get(j--); + } + } + } + return operations; + } +} diff --git a/Week 05/id_556/NOTE.md b/Week 05/id_556/NOTE.md index a6321d6e2..2ba628ccc 100644 --- a/Week 05/id_556/NOTE.md +++ b/Week 05/id_556/NOTE.md @@ -2,3 +2,185 @@ +#### Dynamic Programming + +DP=分治+最优子结构 + +一般用于求解:最优解,最大值,最少方式... + +DP本质是动态递推,和分治或递归没有本质区别 + +- 共性:找重复子问题 + +- 差异:缓存(储存中间状态)、淘汰次优 + +- 指数-->多项式(n^2或n) + +> 形成机器思维,计算机处理问题的本质是重复性,是理解复杂问题的关键,放弃人肉递归事事亲为的思维习惯,而要化繁为简! + +#### 实例: +##### 1. 一维DP +fibonacci:自顶向下记忆化搜索(Memoization) + +```java +int fib(int n, int[] memo) { + // terminator + if(n<=1){ + return n; + } + if(memo[n] == 0){ + memno[n]= fib(n-1) + fib(n-2) + } +} +``` + +fibonacci:自底向上循环(动态规划(DP)) +```java +int fib(int n, int[] a){ + a[0] = 0; + a[1] = 1; + for(int i=2;i<=n;+r+i){ + a[i] = a[i-1] + a[i-2]; + } + return a[n]; +} +``` + +优化:只需要保存最近的两个结果(a[i-1]和a[i-2])即可 + +```java +int fib(int n){ + int one = 0, two = 1; + int res = -1; + if (n <= 1) { + res = n; + } + for (int i = 2; i <= n; ++i) { + res = one + two; + one = two; + two = res; + } + return res; +} +``` + + +> 更好的做法基本是自顶向上进行递推 + +多维递推,存在取舍最优子结构,放弃人肉递归,使用数学归纳法思维 + +##### 2. 二维简单DP:路径计数(62/63) + +递推(状态转移方程/DP方程):opt[i, j] = opt[i-1, j] + opt[i, j-1] + + +优化:只需要保存一行的结果 + +##### 3. 字符串进行变化DP:最长公共子序列(1143) + +暴力:枚举1的每一个子序列,看是否也是2的子序列O(2^n) + +重复性: + +先看特殊/边界情况(corner case),再数学归纳一般情况: +1. S1="", S2="" +2. S1="", S2=任意 +3. S1="A",S2=任意 +4. S1="...A",S2="...A" --> 子问题:S1="...", S2="..." + 1 +5. S1="...A", S2="...B" --> 子问题:Max(LCS(S1="...", S2="...B"), LCS(S1="...A", S2="...")) + +使用二维数组,保存两个字符串变化中间状态的结果 + +DP公式: +``` +if s1[-1] != s2[-1]: + LCS(s1, s2) = max(LCS(s1-1, s2), LCS(s1, s2-1)) +if s1[-1] == s2[-1]: + LCS(s1, s2) = LCS(s1-1, s2-1) + 1 +return LCS[s1.length, s2.length] +``` + 5 steps to DP: + + 1. define repetitive subproblems (divide) + + 2. guess part of solution + + 3. merge subproblem solutions + + 4. build DP table bottom-up (OR recurse & memorize) + + 5. solve the original problem + +习题: + +##### 4. ClimbingStairs思考: + 1. 假设可以1、2、3步 + 2. 假设相邻两步不能相同 + +##### 5. Triangle(120): +> 相当于路径计数中二维数组砍掉一半的三角形 + +(1) 重复性子问题:solve(i, j) = min(solve(i+1, j) + solve(i+1, j+1)) + a[i, j] + +(2) 递推公式:f[i, j] = min(f(i+1, j) + f(i+1, j+1)) + a[i, j] + +思考:记忆化递归写法 + +##### 6. 子序列的最大和(53)/积 + +> 平时就养成在纸上/电脑上/白板上将自己的思考过程写出来的习惯,面试时按照平时的习惯就不虚了! + +(1) brutal force + +(2) DP: 子问题:当前元素自身最大(即之前最大和为0),或加上以前最大和后最大(要么不用之前的,要么用) + +solve(i) = max(solve(i-1), 0) + a[i] + +f[i] = max(f[i-1], 0) + a[i] + +结果:max(f) + +优化:为负就抛弃 +nums[i] = nums[i] + max(0, nums[i-1]) +return max(nums) + +> 思考:乘积最大 + +##### 7. Coin Change (322) + +暴力:转化为状态树,递归(O(2^n) + +BFS: 广度优先遍历状态树,找最短达到0的路径长度 + +DP: f(n) = min(f(n-k)), for k in [1,2,5]) + 1 + +##### 8. House Robber (198) +(1) 子问题 +(2) 状态定义 +(3) DP方程 + +使用二维数组,保存第i个房子是否偷 + +a[i][0/1]: 0表示当前第i个房子不偷 + +a[i][0] = max(a[i-1][0], a[i-1][1]) + +a[i][1] = a[i-1][0] + nums[i] + +结果:a[n-1] + + +一位数组: + +a[i]:表示nums[i]必偷的最大值 + +a[i] = max(a[i-1] + 0, a[i-2] + nums[i]) + +甚至不需要开数组,只需三个变量即可 + +> 面试中状态定义比较重要,竞赛中递归方程会比较难 + +##### 9. 股票买卖(121) +... + +##### 10. Edit Distance \ No newline at end of file diff --git a/Week 05/id_566/leetcode_621_566.php b/Week 05/id_566/leetcode_621_566.php new file mode 100644 index 000000000..4c42ff355 --- /dev/null +++ b/Week 05/id_566/leetcode_621_566.php @@ -0,0 +1,38 @@ +$v){ + if(isset($count[$v])) + $count[$v]++; + else + $count[$v]=1; + } + + arsort($count); + $max=array_shift($count); + $sum=1; + foreach($count as $a) + if($a==$max) + $sum++; + + $res = ($max-1)*($n+1)+$sum; + + return $res>$total?$res:$total; + } +} +?> \ No newline at end of file diff --git a/Week 05/id_566/leetcode_64_566.php b/Week 05/id_566/leetcode_64_566.php new file mode 100644 index 000000000..9c64e3689 --- /dev/null +++ b/Week 05/id_566/leetcode_64_566.php @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/Week 05/id_571/leetcode_69_571.js b/Week 05/id_571/leetcode_69_571.js new file mode 100644 index 000000000..8ee7ebbd3 --- /dev/null +++ b/Week 05/id_571/leetcode_69_571.js @@ -0,0 +1,18 @@ +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function(m, n) { + let arr = Array.from(Array(m), () => Array(n).fill(1)); + + for (let i = m - 2; i >= 0; i--) { + for (let j = n - 2; j >= 0; j--) { + arr[i][j] = arr[i + 1][j] + arr[i][j + 1]; + } + } + + return arr[0][0]; +}; + +uniquePaths(3, 2); diff --git a/Week 05/id_576/Fibonacci.java b/Week 05/id_576/Fibonacci.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_1143_576.java b/Week 05/id_576/LeetCode_1143_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_120_576.java b/Week 05/id_576/LeetCode_120_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_198_576.java b/Week 05/id_576/LeetCode_198_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_322_576.java b/Week 05/id_576/LeetCode_322_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_32_576.java b/Week 05/id_576/LeetCode_32_576.java new file mode 100644 index 000000000..d1da83594 --- /dev/null +++ b/Week 05/id_576/LeetCode_32_576.java @@ -0,0 +1,23 @@ +/** + * LeetCode_32_576 + */ +public class LeetCode_32_576 { + + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + //右括号前边是左括号 + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + //右括号前边是右括号,并且除去前边的合法序列的前边是左括号 + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} \ No newline at end of file diff --git a/Week 05/id_576/LeetCode_63_576.java b/Week 05/id_576/LeetCode_63_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/LeetCode_64_576.java b/Week 05/id_576/LeetCode_64_576.java new file mode 100644 index 000000000..3d54f99ec --- /dev/null +++ b/Week 05/id_576/LeetCode_64_576.java @@ -0,0 +1,17 @@ +/** + * LeetCode_64_576 + */ +public class LeetCode_64_576 { + + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_576/Leetcode_62_576.java b/Week 05/id_576/Leetcode_62_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_576/TemplateOfRecursion.java b/Week 05/id_576/TemplateOfRecursion.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 05/id_586/32-longest-valid-parentheses.cc b/Week 05/id_586/32-longest-valid-parentheses.cc new file mode 100644 index 000000000..1bf8a6331 --- /dev/null +++ b/Week 05/id_586/32-longest-valid-parentheses.cc @@ -0,0 +1,43 @@ +/* +定义一个 dp\text{dp}dp 数组,其中第 i 个元素表示以下标为 iii 的字符结尾的最长有效子字符串的长度。我们将 dp\text{dp}dp 数组全部初始化为 0 + +And the DP idea is : + +If s[i] is '(', set longest[i] to 0,because any string end with '(' cannot be a valid one. + +Else if s[i] is ')' + + If s[i-1] is '(', longest[i] = longest[i-2] + 2 + + Else if s[i-1] is ')' and s[i-longest[i-1]-1] == '(', longest[i] = longest[i-1] + 2 + longest[i-longest[i-1]-2] + +For example, input "()(())", at i = 5, longest array is [0,2,0,0,2,0], longest[5] = longest[4] + 2 + longest[1] = 6. + +*/ + +class Solution { +public: + int longestValidParentheses(string s) { + int res = 0; + + vector longest(s.size()+1, 0); + for(int i = 1; i < s.size(); ++i) { + // if(s[i] == ')') { + // if(s[i-1] == '(') { + // longest[i] = (i-2) >= 0 ? (longest[i-2] + 2) : 2; + // res = max(longest[i], res); + // } else { // if s[i-1] == ')', combine the previous length. + // if(i-longest[i-1]-1 >= 0 && s[i-longest[i-1]-1] == '('){ + // longest[i] = longest[i-1] + 2 + ((i-longest[i-1]-2 >= 0)?longest[i-longest[i-1]-2]:0); + // res = max(longest[i], res); + // } + // } + // } + if(s[i] == ')' && i - longest[i] && s[i - longest[i] - 1] == '(') { + longest[i + 1] = longest[i] + longest[i - longest[i] - 1] + 2; + } + res = max(res, longest[i + 1]); + } + return res; + } +}; \ No newline at end of file diff --git a/Week 05/id_586/64-minimum-path-sum.cc b/Week 05/id_586/64-minimum-path-sum.cc new file mode 100644 index 000000000..be825a1c5 --- /dev/null +++ b/Week 05/id_586/64-minimum-path-sum.cc @@ -0,0 +1,62 @@ +// This is a typical DP problem. Suppose the minimum path sum of arriving at point (i, j) is S[i][j], then the state equation is S[i][j] = min(S[i - 1][j], S[i][j - 1]) + grid[i][j]. + +// Well, some boundary conditions need to be handled. The boundary conditions happen on the topmost row (S[i - 1][j] does not exist) and the leftmost column (S[i][j - 1] does not exist). Suppose grid is like [1, 1, 1, 1], then the minimum sum to arrive at each point is simply an accumulation of previous points and the result is [1, 2, 3, 4]. + +// Now we can write down the following (unoptimized) code. + +class Solution { +public: + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + vector > sum(m, vector(n, grid[0][0])); + for (int i = 1; i < m; i++) + sum[i][0] = sum[i - 1][0] + grid[i][0]; + for (int j = 1; j < n; j++) + sum[0][j] = sum[0][j - 1] + grid[0][j]; + for (int i = 1; i < m; i++) + for (int j = 1; j < n; j++) + sum[i][j] = min(sum[i - 1][j], sum[i][j - 1]) + grid[i][j]; + return sum[m - 1][n - 1]; + } +}; + +// As can be seen, each time when we update sum[i][j], we only need sum[i - 1][j] (at the current column) and sum[i][j - 1] (at the left column). So we need not maintain the full m*n matrix. Maintaining two columns is enough and now we have the following code. + +class Solution { +public: + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + vector pre(m, grid[0][0]); + vector cur(m, 0); + for (int i = 1; i < m; i++) + pre[i] = pre[i - 1] + grid[i][0]; + for (int j = 1; j < n; j++) { + cur[0] = pre[0] + grid[0][j]; + for (int i = 1; i < m; i++) + cur[i] = min(cur[i - 1], pre[i]) + grid[i][j]; + swap(pre, cur); + } + return pre[m - 1]; + } +}; + +// Further inspecting the above code, it can be seen that maintaining pre is for recovering pre[i], which is simply cur[i] before its update. So it is enough to use only one vector. Now the space is further optimized and the code also gets shorter. + +class Solution { +public: + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + vector cur(m, grid[0][0]); + for (int i = 1; i < m; i++) + cur[i] = cur[i - 1] + grid[i][0]; + for (int j = 1; j < n; j++) { + cur[0] += grid[0][j]; + for (int i = 1; i < m; i++) + cur[i] = min(cur[i - 1], cur[i]) + grid[i][j]; + } + return cur[m - 1]; + } +}; \ No newline at end of file diff --git a/Week 05/id_586/72-edit-distance.cc b/Week 05/id_586/72-edit-distance.cc new file mode 100644 index 000000000..347e67188 --- /dev/null +++ b/Week 05/id_586/72-edit-distance.cc @@ -0,0 +1,94 @@ +/* +To apply DP, we define the state dp[i][j] to be the minimum number of operations to convert word1[0..i) to word2[0..j). + +For the base case, that is, to convert a string to an empty string, the mininum number of operations (deletions) is just the length of the string. So we have dp[i][0] = i and dp[0][j] = j. + +For the general case to convert word1[0..i) to word2[0..j), we break this problem down into sub-problems. Suppose we have already known how to convert word1[0..i - 1) to word2[0..j - 1) (dp[i - 1][j - 1]), if word1[i - 1] == word2[j - 1], then no more operation is needed and dp[i][j] = dp[i - 1][j - 1]. + +If word1[i - 1] != word2[j - 1], we need to consider three cases. + + Replace word1[i - 1] by word2[j - 1] (dp[i][j] = dp[i - 1][j - 1] + 1); + If word1[0..i - 1) = word2[0..j) then delete word1[i - 1] (dp[i][j] = dp[i - 1][j] + 1); + If word1[0..i) + word2[j - 1] = word2[0..j) then insert word2[j - 1] to word1[0..i) (dp[i][j] = dp[i][j - 1] + 1). + +So when word1[i - 1] != word2[j - 1], dp[i][j] will just be the minimum of the above three cases. +*/ + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 1; j <= n; j++) { + dp[0][j] = j; + } + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (word1[i - 1] == word2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1; + } + } + } + return dp[m][n]; + } +}; + +/* +Note that each time when we update dp[i][j], we only need dp[i - 1][j - 1], dp[i][j - 1] and dp[i - 1][j]. We may optimize the space of the code to use only two vectors. +*/ + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(); + vector pre(n + 1, 0), cur(n + 1, 0); + for (int j = 1; j <= n; j++) { + pre[j] = j; + } + for (int i = 1; i <= m; i++) { + cur[0] = i; + for (int j = 1; j <= n; j++) { + if (word1[i - 1] == word2[j - 1]) { + cur[j] = pre[j - 1]; + } else { + cur[j] = min(pre[j - 1], min(cur[j - 1], pre[j])) + 1; + } + } + fill(pre.begin(), pre.end(), 0); + swap(pre, cur); + } + return pre[n]; + } +}; + +/* Or even just one vector. */ + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(), pre; + vector cur(n + 1, 0); + for (int j = 1; j <= n; j++) { + cur[j] = j; + } + for (int i = 1; i <= m; i++) { + pre = cur[0]; + cur[0] = i; + for (int j = 1; j <= n; j++) { + int temp = cur[j]; + if (word1[i - 1] == word2[j - 1]) { + cur[j] = pre; + } else { + cur[j] = min(pre, min(cur[j - 1], cur[j])) + 1; + } + pre = temp; + } + } + return cur[n]; + } +}; \ No newline at end of file diff --git a/Week 05/id_586/NOTE.md b/Week 05/id_586/NOTE.md index a6321d6e2..08d522954 100644 --- a/Week 05/id_586/NOTE.md +++ b/Week 05/id_586/NOTE.md @@ -1,4 +1,174 @@ -# NOTE +# 动态规划 - +动态规划和 递归/分治没有根本的区别(关键是看有没有最优子结构) + +共性: 找到重复的子问题 +差异性: 最优子结构,中途可以淘汰次优解 + +1. 可以用数组缓存中间值 + +## Fibonacci数列 + +```c +/* O(2^n) 指数级 分治 */ +int fib(int n) { + if (n <= 0) return 0; + else if (n == 1) return 1; + else return fib(n - 1) + fib(n - 2); +} + +/* 加缓存: 记忆化搜索 + * O(n) + */ +int memo[1024] = {0}; +int fib(int n) { + if (n <= 1) return n; + + if (memo[n] == 0) + memon[n] = fib(n - 1) + fib(n - 2); + + return memon[n]; +} + +/* 自底向上递推 -- 数学归纳法 + * f(n) = f(n - 1) + f(n - 2) + */ +int fib(int n) { + if (n <= 1) return n; + a[0] = 0, a[1] = 1; + for (int i = 2; i <= n; i++) { + a[i] = a[i - 1] + a[i - 2]; + } + return a[n]; +} +``` + +## 62 路径计数 + +取舍最优子结构? + +```cpp + +int countPaths( frid, int row, int col) { + +} + +``` + +## 不同路径题目 + +```cpp + + +``` + +## 不同路径 2 题目 + +## 最长公共子序列题目 + +## MIT 动态规划课程最短路径算法 + + +DP + +- 重复性(分治) problem(i, j) = min(sub(i + 1, j), sub(i + 1, j + 1) + a[i, j]) +- 定义状态数组 f(i, j) +- DP 方程 f(i, j = ) = min(f(i + 1, j), f(i + 1, j + 1) + a[i, j]) + + +```cpp +// triangle : https://leetcode-cn.com/problems/triangle/description/ +class Solution { +public: + int minimumTotal(vector>& triangle) { + vector dp(triangle.back()); + + for (int layer = triangle.size() - 2; layer >=0 ; --layer) { + for (int j = 0; j <= layer; ++j) + dp[j] = min(dp[j], dp[j + 1]) + triangle[layer][j]; + } + + return dp[0]; + } +}; +``` + +```c +// https://leetcode-cn.com/problems/maximum-subarray/ +// 1. 重复性(分治) max_sum(i) = max(max_sum(i - 1), 0) + a[i]; +// 2. 定义状态数组 f(i, j) +// 3. DP 方程 f(i) = max(f(i - 1), 0) + a[i] + + + + +``` + +```c +// https://leetcode-cn.com/problems/coin-change/description/ +// 1. 重复性(分治) max_sum(i) = max(max_sum(i - 1), 0) + a[i]; +// 2. 定义状态数组 f(n) = min(f(n - k) (k in array)) + 1 +// 3. DP 方程 f(i) + + +``` + +```c +// https://leetcode-cn.com/problems/house-robber/ +// 1. 重复性(分治) max_sum(i) = max(max_sum(i - 1), 0) + a[i]; +// 2. 定义状态数组 f(n) = min(f(n - k) (k in array)) + 1 +// 3. DP 方程 f(i) + +// a[i] : 0..i 能偷的最大值 a[n - 1] +// a[i][0,1] 0: 偷, 1:不偷 +``` + + + https://leetcode-cn.com/problems/climbing-stairs/description/ + https://leetcode-cn.com/problems/triangle/description/ + https://leetcode.com/problems/triangle/discuss/38735/Python-easy-to-understand-solutions-(top-down-bottom-up) + https://leetcode-cn.com/problems/maximum-subarray/ + https://leetcode-cn.com/problems/maximum-product-subarray/description/ + https://leetcode-cn.com/problems/coin-change/description/ + +实战题目 + + https://leetcode-cn.com/problems/house-robber/ + https://leetcode-cn.com/problems/house-robber-ii/description/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/#/description + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ + https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + +高级 DP 实战题目 + + https://leetcode-cn.com/problems/perfect-squares/ + https://leetcode-cn.com/problems/edit-distance/ (重点) + https://leetcode-cn.com/problems/jump-game/ + https://leetcode-cn.com/problems/jump-game-ii/ + https://leetcode-cn.com/problems/unique-paths/ + https://leetcode-cn.com/problems/unique-paths-ii/ + https://leetcode-cn.com/problems/unique-paths-iii/ + https://leetcode-cn.com/problems/coin-change/ + https://leetcode-cn.com/problems/coin-change-2/ + +注意:请大家先消化前面的实战题目,高级 DP 的方法和题解会在课程后面解锁。 +课后作业 + + https://leetcode-cn.com/problems/longest-valid-parentheses/ + https://leetcode-cn.com/problems/minimum-path-sum/ + https://leetcode-cn.com/problems/edit-distance/ + https://leetcode-cn.com/problems/decode-ways + https://leetcode-cn.com/problems/maximal-square/ + https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/ + https://leetcode-cn.com/problems/frog-jump/ + https://leetcode-cn.com/problems/split-array-largest-sum + https://leetcode-cn.com/problems/student-attendance-record-ii/ + https://leetcode-cn.com/problems/task-scheduler/ + https://leetcode-cn.com/problems/palindromic-substrings/ + https://leetcode-cn.com/problems/minimum-window-substring/ + https://leetcode-cn.com/problems/burst-balloons/ diff --git a/Week 05/id_586/diff_patch.cpp b/Week 05/id_586/diff_patch.cpp new file mode 100644 index 000000000..5ee314e55 --- /dev/null +++ b/Week 05/id_586/diff_patch.cpp @@ -0,0 +1,15 @@ + +int uniquePath(int m, int n) +{ + vector> dp[m][n]; + + for (int i = 0; i < n; i++) dp[0][i] = 1; + for (int i = 0; i < m; i++) dp[i][0] = 1; + + for (int i = 1; i < m; i++) { + for (int j = 0; j < n; j++) + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + + return dp[m - 1][n - 1]; +} diff --git a/Week 05/id_596/LeetCode_621_596.py b/Week 05/id_596/LeetCode_621_596.py new file mode 100644 index 000000000..d913f39d0 --- /dev/null +++ b/Week 05/id_596/LeetCode_621_596.py @@ -0,0 +1,46 @@ +# 整个任务列表执行的长度取决于执行次数最多的那个任务,次数最多的任务优先安排执行,因此我们将任务按出现次数排序。 +# 假设次数最多的任务A的次数为l,冷却时间为n。那么执行整个任务列表至少需要的时间为 (l - 1) * (n + 1) + 1。 +# 其中l单位时间用来执行A,其余的时间可以用来执行其他任务或者等待。 +# 接下来继续按出现次数顺序处理下一个任务: +# 1. 如果出现次数和最大的一样,则执行时间+1,因为需要在非空闲时间处理 +# 2. 如果出现次数小于最大值,则将空闲时间减去任务数量 +# 3. 如果在空闲时间使用完之前,处理完了所有任务,那么空闲时间就是等待,返回结果 +# 4. 如果空闲时间用完,还有未完成的任务,说明该组任务可以在没有等待的情况下完成任务,那么结果即为任务序列的长度。 +class Solution: + # def leastInterval(self, tasks: List[str], n: int) -> int: + # length = len(tasks) + # if length < 1: + # return length + # # 计算每个任务出现的次数 + + # map.sort() + # maxTaskCount = map[25] + # leastIntervalTime = (maxTaskCount - 1) * (n + 1) + 1 + # i = 24 + # while map[i] > 0 and i > 0: + # if map[i] == maxTaskCount: + # leastIntervalTime += 1 + # i -= 1 + # else: + # break; + # return leastIntervalTime if length <= leastIntervalTime else length + + # 优化算法,不用排序在计算任务数量时就得到最大任务数以及和最大任务数相同的任务数量 + def leastInterval(self, tasks: List[str], n: int) -> int: + ength = len(tasks) + if length <= 1: + return length + + maxTaskLength = 0 + maxTaskCount = 0 + map = [0] * 26 + for task in tasks: + index = ord(task) - ord('A') + map[index] += 1 + if map[index] == maxTaskLength: + maxTaskCount += 1 + if map[index] > maxTaskLength: + maxTaskLength = map[index] + maxTaskCount = 1 + leastIntervalTime = (maxTaskLength - 1) * (n+1) + maxTaskCount + return leastIntervalTime if length <= leastIntervalTime else length \ No newline at end of file diff --git a/Week 05/id_596/LeetCode_64_596.py b/Week 05/id_596/LeetCode_64_596.py new file mode 100644 index 000000000..53189d3ed --- /dev/null +++ b/Week 05/id_596/LeetCode_64_596.py @@ -0,0 +1,13 @@ +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + # 重复性:problem(i, j) = grid[i][j] + min(sub[i+1][j], sub[i][j+1]) + # 状态转移方程:grid[i, j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1]) + + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: continue + elif i == 0: grid[i][j] = grid[i][j] + grid[i][j-1] + elif j == 0: grid[i][j] = grid[i][j] + grid[i-1][j] + else: grid[i][j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1]) + + return grid[-1][-1] \ No newline at end of file diff --git a/Week 05/id_596/NOTE.md b/Week 05/id_596/NOTE.md index a6321d6e2..75cd2ba09 100644 --- a/Week 05/id_596/NOTE.md +++ b/Week 05/id_596/NOTE.md @@ -1,4 +1,20 @@ # NOTE - +## 学习笔记 +动态规划和递归或者分治没有本质上的区别,关键看有无最优子结构。 +他们的共性都是找到重复子问题,差异性在于动态规划存在最优子结构,中途可以淘汰次优解。 +### DP关键点 +1. 最优子结构 opt[n] = best_of(opt[n-1], opt[n-2],…) +2. 储存中间状态:opt[i] +3. 递推公式(美其名曰:状态转移方程或者DP方程) + +常见问题: +Fibonacci: opt[i] = opt[i-1] + opt[i-2] +二维路径问题:opt[i,j] = opt[i+1][j] + opt[i][j+1] + +### 动态规划小结 + +1. 打破自己的思维惯性,形成机器思维 +2. 理解复杂逻辑的关键 +3. 也是职业进阶的要点要领 \ No newline at end of file diff --git a/Week 05/id_601/LeetCode_32_601.java b/Week 05/id_601/LeetCode_32_601.java new file mode 100644 index 000000000..17b1202c5 --- /dev/null +++ b/Week 05/id_601/LeetCode_32_601.java @@ -0,0 +1,18 @@ +public int longestValidParentheses(String s) { + int maxans = 0; + Stack stack = new Stack<>(); + stack.push(-1); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + maxans = Math.max(maxans, i - stack.peek()); + } + } + } + return maxans; + } diff --git a/Week 05/id_601/LeetCode_64_601.java b/Week 05/id_601/LeetCode_64_601.java new file mode 100644 index 000000000..14966866b --- /dev/null +++ b/Week 05/id_601/LeetCode_64_601.java @@ -0,0 +1,16 @@ +public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) { + continue; + }else if(i == 0){ + grid[i][j] = grid[i][j - 1] + grid[i][j]; + }else if(j == 0){ + grid[i][j] = grid[i - 1][j] + grid[i][j]; + }else{ + grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } diff --git "a/Week 05/id_606/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.java" "b/Week 05/id_606/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.java" new file mode 100644 index 000000000..aad006435 --- /dev/null +++ "b/Week 05/id_606/32.\346\234\200\351\225\277\346\234\211\346\225\210\346\213\254\345\217\267.java" @@ -0,0 +1,64 @@ +/* + * @lc app=leetcode.cn id=32 lang=java + * + * [32] 最长有效括号 + * + * https://leetcode-cn.com/problems/longest-valid-parentheses/description/ + * + * algorithms + * Hard (28.38%) + * Likes: 386 + * Dislikes: 0 + * Total Accepted: 27.6K + * Total Submissions: 96.4K + * Testcase Example: '"(()"' + * + * 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + * + * 示例 1: + * + * 输入: "(()" + * 输出: 2 + * 解释: 最长有效括号子串为 "()" + * + * + * 示例 2: + * + * 输入: ")()())" + * 输出: 4 + * 解释: 最长有效括号子串为 "()()" + * + * + */ + +// @lc code=start +class Solution { + public int longestValidParentheses(String s) { + int count = 0; + int max = 0; + for (int i = 0; i < s.length(); i++) { + count = 0; + for (int j = i; j < s.length(); j++) { + if (s.charAt(j) == '(') { + count++; + } else { + count--; + } + // count < 0 说明右括号多了,此时无论后边是什么,一定是非法字符串了,所以可以提前结束循环 + if (count < 0) { + break; + + } + // 当前是合法序列,更新最长长度 + if (count == 0) { + if (j - i + 1 > max) { + max = j - i + 1; + } + } + } + } + return max; + + } +} +// @lc code=end diff --git "a/Week 05/id_606/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/Week 05/id_606/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 000000000..0171614d3 --- /dev/null +++ "b/Week 05/id_606/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,51 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + * + * https://leetcode-cn.com/problems/minimum-path-sum/description/ + * + * algorithms + * Medium (62.54%) + * Likes: 317 + * Dislikes: 0 + * Total Accepted: 42K + * Total Submissions: 66.6K + * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + * [1,3,1], + * ⁠ [1,5,1], + * ⁠ [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j + 1]); + } + } + return grid[0][0]; + + } +} +// @lc code=end diff --git a/Week 05/id_611/LeetCode_198_611.java b/Week 05/id_611/LeetCode_198_611.java new file mode 100644 index 000000000..12592d77a --- /dev/null +++ b/Week 05/id_611/LeetCode_198_611.java @@ -0,0 +1,13 @@ +class Solution { + public int rob(int[] nums) { + int len = nums.length; + if(len == 0) return 0; + int[] dp = new int[len+1]; + dp[0] = 0; + dp[1] = nums[0]; + for(int i = 2; i <= len; ++i){ + dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i-1]); + } + return dp[len]; + } +} \ No newline at end of file diff --git a/Week 05/id_611/LeetCode_213_611.java b/Week 05/id_611/LeetCode_213_611.java new file mode 100644 index 000000000..12592d77a --- /dev/null +++ b/Week 05/id_611/LeetCode_213_611.java @@ -0,0 +1,13 @@ +class Solution { + public int rob(int[] nums) { + int len = nums.length; + if(len == 0) return 0; + int[] dp = new int[len+1]; + dp[0] = 0; + dp[1] = nums[0]; + for(int i = 2; i <= len; ++i){ + dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i-1]); + } + return dp[len]; + } +} \ No newline at end of file diff --git a/Week 05/id_616/LeetCode_221_616.cpp b/Week 05/id_616/LeetCode_221_616.cpp new file mode 100644 index 000000000..2455c71b3 --- /dev/null +++ b/Week 05/id_616/LeetCode_221_616.cpp @@ -0,0 +1,33 @@ +class Solution { +public: + int maximalSquare(vector>& matrix) { + if(matrix.size() == 0 || matrix[0].size() == 0) return 0; + + int rows = matrix.size(); + int cols = matrix[0].size(); + int max_len = 0; + + vector > dp(rows, vector(cols, 0)); + + for(int i = 0; i < rows; ++i){ + dp[i][0] = matrix[i][0] - '0'; + max_len = max(max_len,dp[i][0]); + } + + for(int j = 0; j < cols; ++j){ + dp[0][j] = matrix[0][j] - '0'; + max_len = max(max_len,dp[0][j]); + } + + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + if (matrix[i][j] == '1'){ + dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + max_len = max(max_len, dp[i][j]); + } + } + } + + return max_len * max_len; + } +}; \ No newline at end of file diff --git a/Week 05/id_616/LeetCode_64_616.cpp b/Week 05/id_616/LeetCode_64_616.cpp new file mode 100644 index 000000000..b2d91b4d5 --- /dev/null +++ b/Week 05/id_616/LeetCode_64_616.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + int minPathSum(vector>& grid) { + if(grid.size() == 0) return 0; + if(grid[0].size() == 0) return 0; + vector > min_num(grid.size(), vector(grid[0].size(), 0)); + return minPath(grid,grid.size() - 1, grid[0].size() - 1, min_num); + } + + int minPath(vector>& grid, int m, int n, vector>& min_num){ + if(min_num[m][n] != 0) return min_num[m][n]; + if(m == 0 && n != 0) { + min_num[m][n] = minPath(grid, m, n - 1,min_num) + grid[m][n]; + } else if(m == 0 && n == 0) { + min_num[m][n] = grid[m][n]; + } else if(n == 0) { + min_num[m][n] = minPath(grid, m - 1, n,min_num) + grid[m][n]; + } else{ + min_num[m][n] = min(minPath(grid, m-1,n,min_num),minPath(grid,m,n-1,min_num)) + grid[m][n]; + } + + return min_num[m][n]; + } +}; \ No newline at end of file diff --git a/Week 05/id_616/LeetCode_91_616.cpp b/Week 05/id_616/LeetCode_91_616.cpp new file mode 100644 index 000000000..2ebe76a7c --- /dev/null +++ b/Week 05/id_616/LeetCode_91_616.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int numDecodings(string s) { + if(s[0] == '0') return 0; + if(s.size() == 1) return 1; + int pre = 1; + int cur = 1; + for(int i = 1; i < s.size(); ++i){ + int t = cur; + char tmp = s[i - 1]; + if(s[i] == '0'){ + if(tmp =='1' || tmp == '2') cur = pre; + else return 0; + } else if(tmp == '1' || tmp == '2' && s[i] >= '1' && s[i] <= '6') { + cur += pre; + } + pre = t; + } + return cur; + } +}; \ No newline at end of file diff --git a/Week 05/id_616/NOTE.md b/Week 05/id_616/NOTE.md index a6321d6e2..94e0b3cc7 100644 --- a/Week 05/id_616/NOTE.md +++ b/Week 05/id_616/NOTE.md @@ -1,4 +1,13 @@ -# NOTE +# 学习总结 - +## 动态规划核心 +动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构) +共性: 找到重复子问题 +差异性:最优子结构、中途可以淘汰次优解 + +## 解题步骤 + +1. 分治(找子问题) +2. 状态数组定义 +3. 写DP方程 diff --git a/Week 05/id_631/LeetCode_120_631.go b/Week 05/id_631/LeetCode_120_631.go new file mode 100644 index 000000000..c573db108 --- /dev/null +++ b/Week 05/id_631/LeetCode_120_631.go @@ -0,0 +1,15 @@ +func minimumTotal(triangle [][]int) int { + row := len(triangle) + dp := make([]int, row + 1) + + for i := row - 1; i >= 0; i-- { + for j := 0;j < len(triangle[i]); j++ { + min := dp[j] + if dp[j] > dp[j+1] { + min = dp[j+1] + } + dp[j] = min + triangle[i][j]; + } + } + return dp[0]; +} \ No newline at end of file diff --git a/Week 05/id_631/LeetCode_70_631.go b/Week 05/id_631/LeetCode_70_631.go new file mode 100644 index 000000000..4792726a4 --- /dev/null +++ b/Week 05/id_631/LeetCode_70_631.go @@ -0,0 +1,14 @@ +func climbStairs(n int) int { + if n <= 1 { + return 1; + } + + dp := make([]int, n + 1) + dp[1] = 1; + dp[2] = 2; + //直接遍历向前递推 + for i := 3; i <= n; i++ { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +} \ No newline at end of file diff --git a/Week 05/id_631/NOTE.md b/Week 05/id_631/NOTE.md index a6321d6e2..13b6ebd64 100644 --- a/Week 05/id_631/NOTE.md +++ b/Week 05/id_631/NOTE.md @@ -1,4 +1,40 @@ # NOTE - +动态规划(Dynamic Programming,简称 DP) +步骤: +1.最优子结构 +2.状态定义 +3.dp状态转移公式 +动态规划和递归或分治没有根本上的区别(关键看有无最优的子结构) +共同点:找到重复的子问题 +差异点:最优子结构、中途可以淘汰次优解 + +傻递归或傻分治经常是指数级别的时间复杂度,进行了淘汰次优解,会把时间复杂度降为O(n^2)或者O(n),也就是从指数级把复杂度降到了多项式级别 + +动态规划关键点 +1.最优子结构opt[n] = best of(opt[n-1], opt[n-2], ...) +2.储存中间状态: opt[i] +3.递推公式(状态转移方程或者DP方程) +Fib: opt[n] =opt[n-1] + opt[n-2] +二维路径: opt[i,j] =opt[i+1,j+1] + opt[i,j+1] + +动态规划小结 +1.打破自己的思维惯性,形成机器思维 +2.理解复杂逻辑的关键 +3.也是职业进阶的要点要领 + +MIT DP "五步法" +1、定义子问题, 找重复性 +2、猜(part of solution), 思考递归方程怎么递推的; +3、合并子问题, merge; +4、递归 & 记忆化 or 自底向上解决(建立DP表格) +5、解决原问题 + +递归、分治、动态规划的感触: +1.不要人肉递归、很累,要放手交给下面的人 +2.找到最近最简方法,将其拆解成可重复解决的问题 +3.数学归纳法思维(抵制人肉递归的诱惑) +4.思维习惯一定要改变,要机器思维,在判断自己的工作应该怎么做的时候,大概看一下,好像可以类似这种的认知误区要杜绝。一定要找到自相似的办法,也就是有重复的办法,然后化繁为简,同时逻辑上是简洁的且能够严谨证明的,这才是关键 + +刚开始接触动态规划,还是理解的,后面到了找子串和偷房子的问题的时候有些难懂,还需要多练习,然后培养机器思维习惯 \ No newline at end of file diff --git a/Week 05/id_636/LeetCode_32_636.py b/Week 05/id_636/LeetCode_32_636.py new file mode 100644 index 000000000..e4382e55b --- /dev/null +++ b/Week 05/id_636/LeetCode_32_636.py @@ -0,0 +1,16 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + length = len(s) + if length == 0: + return 0 + dp = [0] * length + res = 0 + for i in range(length): + if i>0 and s[i] == ")": + if s[i - 1] == "(": + dp[i] = dp[i - 2] + 2 + elif s[i - 1] == ")" and i - dp[i - 1] - 1 >= 0 and s[i - dp[i - 1] - 1] == "(": + dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2] + if dp[i] > res: + res = dp[i] + return res diff --git a/Week 05/id_636/LeetCode_403_636.py b/Week 05/id_636/LeetCode_403_636.py new file mode 100644 index 000000000..05dc5e7f4 --- /dev/null +++ b/Week 05/id_636/LeetCode_403_636.py @@ -0,0 +1,17 @@ +class Solution: + def canCross(self, stones: List[int]) -> bool: + if not stones:return False + stones_set = set(stones) + from collections import defaultdict + stones_dict = defaultdict(set) + stones_dict[stones[0]] = {0} + for stone in stones: + for key in stones_dict[stone]: + stoneKey = stone + key + if key + 1 > 0 and (stoneKey + 1) in stones_set: + stones_dict[stoneKey + 1].add(key + 1) + if key > 0 and stoneKey in stones_set: + stones_dict[stoneKey].add(key) + if key - 1 > 0 and (stoneKey - 1) in stones_set: + stones_dict[stoneKey - 1].add(key - 1) + return not(not (stones_dict[stones[-1]])) diff --git a/Week 05/id_636/LeetCode_62_636.py b/Week 05/id_636/LeetCode_62_636.py new file mode 100644 index 000000000..870773357 --- /dev/null +++ b/Week 05/id_636/LeetCode_62_636.py @@ -0,0 +1,17 @@ +class Solution: + def uniquePaths(self, m: int, n: int): + res = [([0] * n) for _ in range(m)] + # for + for i in range(m): + for j in range(n): + if i == 0 or j == 0: + res[i][j] = 1 + continue + res[i][j] = res[i-1][j] + res[i][j-1] + + return res[-1][-1] + +if __name__ == '__main__': + s = Solution() + res = s.uniquePaths(7, 3) + print("res: ", res) \ No newline at end of file diff --git a/Week 05/id_636/LeetCode_63_636.py b/Week 05/id_636/LeetCode_63_636.py new file mode 100644 index 000000000..00808185f --- /dev/null +++ b/Week 05/id_636/LeetCode_63_636.py @@ -0,0 +1,28 @@ + +class Solution: + def uniquePathsWithObstacles(self, obstacleGrid) -> int: + + width = len(obstacleGrid[0]) + res = [0] * width + res[0] = 1 + + # for + for item in obstacleGrid: + for j in range(width): + if item[j] == 1: + res[j] = 0 + elif item[j] == 0: + res[j] = 1 + + return res[-1] + +if __name__ == '__main__': + matrx = [ + [0,0,0,0,1], + [0,1,0,1,0], + [0,0,1,0,0], + [1,0,1,0,0], + ] + + s = Solution() + print("res: ", s.uniquePathsWithObstacles(matrx)) \ No newline at end of file diff --git a/Week 05/id_636/LeetCode_64_636.py b/Week 05/id_636/LeetCode_64_636.py new file mode 100644 index 000000000..095542591 --- /dev/null +++ b/Week 05/id_636/LeetCode_64_636.py @@ -0,0 +1,14 @@ +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + if(not grid): + return 0 + m=len(grid) + n=len(grid[0]) + for i in range(1,n): + grid[0][i]+=grid[0][i-1] + for j in range(1,m): + grid[j][0]+=grid[j-1][0] + for x in range(1,m): + for y in range(1,n): + grid[x][y]+=min(grid[x-1][y],grid[x][y-1]) + return grid[-1][-1] diff --git a/Week 05/id_641/LeetCode_32_641.java b/Week 05/id_641/LeetCode_32_641.java new file mode 100644 index 000000000..300033414 --- /dev/null +++ b/Week 05/id_641/LeetCode_32_641.java @@ -0,0 +1,54 @@ +package vip.ruoyun.week5; + +/** + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + *

+ * 说明:每次只能向下或者向右移动一步。 + *

+ * 示例: + *

+ * 输入: + * [ + *   [1,3,1], + * [1,5,1], + * [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/minimum-path-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_32_641 { + + + //1.递归方法 + public int minPathSum(int[][] grid) { + return recursive(grid, 0, 0); + } + + private int recursive(int[][] grid, int i, int j) { + //边界 + if (i == grid.length || j == grid[0].length) return Integer.MAX_VALUE;//左右边界 + if (i == grid.length - 1 && j == grid[0].length - 1) return grid[i][j];//最后的点 + return grid[i][j] + Math.min(recursive(grid, i + 1, j), recursive(grid, i, j + 1)); + } + + //由下向上 + public int minPathSum2(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) {//计算 y 坐标轴 + grid[i][j] = grid[i][j] + grid[i][j + 1]; + } else if (j == grid[0].length - 1 && i != grid.length - 1) {//计算 x 坐标轴 + grid[i][j] = grid[i][j] + grid[i + 1][j]; + } else if (j != grid[0].length - 1 && i != grid.length - 1) {//计算最短路径 + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j + 1]); + } + } + } + return grid[0][0]; + } + +} diff --git a/Week 05/id_641/LeetCode_64_641.java b/Week 05/id_641/LeetCode_64_641.java new file mode 100644 index 000000000..b9d30d071 --- /dev/null +++ b/Week 05/id_641/LeetCode_64_641.java @@ -0,0 +1,57 @@ +package vip.ruoyun.week5; + +import java.util.Stack; + +public class LeetCode_64_641 { + + + //使用栈来解决问题,2 来进行比对 + private boolean isValid(String s) { + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { //等于( push + stack.push('('); + } else if (!stack.empty() && stack.peek() == '(') {//当等于) ,pop + stack.pop(); + } else { + return false; + } + } + return stack.empty();//如果为空 说明配对成功 + } + + public int longestValidParentheses(String s) { + int maxlen = 0; + for (int i = 0; i < s.length(); i++) { + for (int j = i + 2; j <= s.length(); j += 2) { + if (isValid(s.substring(i, j))) { + maxlen = Math.max(maxlen, j - i); + } + } + } + return maxlen; + } + + + // + public int longestValidParentheses2(String s) { + int maxans = 0; + Stack stack = new Stack<>(); + stack.push(-1); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + maxans = Math.max(maxans, i - stack.peek()); + } + } + } + return maxans; + } +} + + diff --git "a/Week 05/id_646/\345\233\236\346\226\207\345\255\227\344\270\262.md" "b/Week 05/id_646/\345\233\236\346\226\207\345\255\227\344\270\262.md" new file mode 100644 index 000000000..27a30f4f8 --- /dev/null +++ "b/Week 05/id_646/\345\233\236\346\226\207\345\255\227\344\270\262.md" @@ -0,0 +1,23 @@ +```js +var countSubstrings = function (s) { + let dp = Array.from({ length: s.length }, _ => new Array(s.length).fill(0)); + for (let i = s.length - 1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (j == i) dp[i][j] = true; // 只有一个字符时 + if (s[i] == s[j]) { // 两个及两个以上字符时 + if (i + 1 == j) { + dp[i][j] = true; // 如果是两个字符 + } else if (i < s.length - 1 && dp[i + 1][j - 1]) dp[i][j] = true; // 如果更小的回文存在 + } + } + } + let count = 0; + for (let i = s.length - 1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (dp[i][j]) count++; + } + } + return count; +}; + +``` diff --git "a/Week 05/id_646/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.md" "b/Week 05/id_646/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.md" new file mode 100644 index 000000000..f64249dac --- /dev/null +++ "b/Week 05/id_646/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.md" @@ -0,0 +1,30 @@ +```js +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function (grid) { + // 最优子结构 + // 储存中间状态 + // 递推公式 + + let m = grid[0].length; + let n = grid.length; + let res = Array.from(new Array(n), () => new Array(m)); + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (i === 0 && j === 0) { + res[i][j] = grid[i][j]; + } else if (i !== 0 && j === 0) { + res[i][j] = res[i - 1][j] + grid[i][j]; + } else if (j !== 0 && i === 0) { + res[i][j] = res[i][j - 1] + grid[i][j]; + } else if (i !== 0 && j !== 0) { + res[i][j] = Math.min(res[i - 1][j], res[i][j - 1]) + grid[i][j]; + } + } + } + return res[n - 1][m - 1]; +}; +``` +> 本次作业中的两道题都不会做,都是参考别人的答案写的,只能回过来多多练习,先跟上步调,把知识点总结起来,然后后期再花时间练习吧 diff --git a/Week 05/id_651/LeetCode_32_651.cpp b/Week 05/id_651/LeetCode_32_651.cpp new file mode 100644 index 000000000..a53d6ffa2 --- /dev/null +++ b/Week 05/id_651/LeetCode_32_651.cpp @@ -0,0 +1,51 @@ +/* +给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 +示例 1: +输入: "(()" +输出: 2 +解释: 最长有效括号子串为 "()" +示例 2: +输入: ")()())" +输出: 4 +解释: 最长有效括号子串为 "()()" + +思路: + 以')' 作为标准, 判断当前的值是什么 + 如果是'(', 则加上 dp[i-2] 的值 + 如果是')', 则判断下前面是否有一对有效括号(i-dp[i-1] > 0 且 s[i-dp[i-1]-1] == '(') + 记录前一对括号的有效数字+2+前前对括号 + +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + int longestValidParentheses(string s) { + int result = 0; + vector dp(s.size(), 0); + for(int i=1;i< s.size();i++){ + if (s[i] == ')'){ + if (s[i-1] == '('){ + // 判断是否有前一个有效的() + if (i - dp[i] > 2) dp[i] = dp[i-2] + 2; + else dp[i] = 2; + } + else if (i-dp[i-1]>0 && s[i-dp[i-1]-1] == '('){ + // 判断是否有前一个有效的(), 当前值+前一个+上上个 + if (i - dp[i-1] - 2 > 0) dp[i] = dp[i-1] + 2 + dp[i-dp[i-1] -2]; + else dp[i] = dp[i-1] + 2; + } + } + result = max(result, dp[i]); + } + return result; + } +} + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 05/id_651/LeetCode_62_651.cpp b/Week 05/id_651/LeetCode_62_651.cpp new file mode 100644 index 000000000..100d07666 --- /dev/null +++ b/Week 05/id_651/LeetCode_62_651.cpp @@ -0,0 +1,48 @@ +/* +一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + +机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + +问总共有多少条不同的路径? + +思路: + 子问题 -> 计算当前的格子有几种走法, 同上阶梯的问题。 求f(n-2) + f(n-1), + 只是在维度上有所变化, 属于二维以上的范畴 + 1. 解法一: 一维数组的解法, 第一行/列走到当前行/列的尽头的走法只有一种,设置为 [1] * n + 通过当前数组和修改后的数组的值相加, 最后获取到走到终点的走法之和 + + 2. 解法二: 二维数组的解法, 当前格子的走法=左边的走法+上面的走法 + + +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + int uniquePaths1(int m, int n) { + vector result; + result.assign(n,1); + for(int i=1;i> result(m, vector(n, 1)); + for(int i=1;i rorse (将 'h' 替换为 'r') +rorse -> rose (删除 'r') +rose -> ros (删除 'e') + +思路同 最长子序列: + 通过当前判断状态, 更新dp数组的内容 + +*/ +# include +# include +# include +using namespace std; + +class Solution { +public: + int minDistance(string word1, string word2) { + int m=word1.size(), n = word2.size(); + vector> dp(m+1, vector(n+1,0)); + for(int i=1;i<=m;i++) dp[i][0] = i; + for(int j=1;j<=n;j++) dp[0][j] = j; + for(int i=1;i<=m;i++){ + for(int j=1;j<=n;j++){ + if (word1[i-1] == word2[j-1]) + dp[i][j] = dp[i-1][j-1]; + else + dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1])) + 1; + } + } + return dp[m][n]; + } +}; + +int main(){ + Solution sol; + return 0; +} \ No newline at end of file diff --git a/Week 05/id_651/NOTE.md b/Week 05/id_651/NOTE.md index a6321d6e2..02c17a813 100644 --- a/Week 05/id_651/NOTE.md +++ b/Week 05/id_651/NOTE.md @@ -1,4 +1,20 @@ # NOTE +Week 05 + +1. 动态规划- DP + 动态规划和递归(分治,回溯)没有太大的区别。 + DP方程每次刷新状态, 最后的状态就是所需要的结果状态 +2. 动态规划的流程: + a. 找出子问题 + b. 编写状态函数 + c. DP方程实现 +3. 常规的找规律解法 + a. 自顶向下方法 + b. 自底向上方法 + + +总结: +本周的难度呈一个坡度上升,有了一种新的视野, 问题还可以这么处理。 虽然也是递归的一种。 但是在思路上, 却有较大差异。 题目还是都要刷完的, 还不是很熟悉这种题型。 diff --git "a/Week 05/id_676/152.\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" "b/Week 05/id_676/152.\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 000000000..b1f8083e1 --- /dev/null +++ "b/Week 05/id_676/152.\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=152 lang=java + * + * [152] 乘积最大子序列 + */ + +// @lc code=start +class Solution { + public int maxProduct(int[] nums) { + int[] dpmax = new int[nums.length]; + int[] dpmin = new int[nums.length]; + dpmax[0] = nums[0]; + dpmin[0] = nums[0]; + int max = nums[0]; + + for (int i = 1; i < nums.length; i++) { + dpmax[i] = nums[i]*Math.max(1,Math.max(dpmax[i-1], dpmin[i-1])); + dpmin[i] = nums[i]*Math.min(1,Math.min(dpmax[i-1],dpmin[i-1])); + max = Math.max(max, Math.max(dpmax[i], dpmin[i])); + } + return max; + } +} +// @lc code=end +class SolutionOne { + public int maxProduct(int[] nums) { + int imax = nums[0]; + int imin = nums[0]; + int max = nums[0]; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] < 0) { //判断当前元素的符号,如果为负,交换最大最小 + int temp = imax; + imax = imin; + imin = temp; + } + imax = Math.max(nums[i], nums[i]*imax); + imin = Math.min(nums[i], nums[i]*imin); + max = Math.max(max, imax); + } + return max; + } +} diff --git "a/Week 05/id_676/198.\346\211\223\345\256\266\345\212\253\350\210\215.java" "b/Week 05/id_676/198.\346\211\223\345\256\266\345\212\253\350\210\215.java" new file mode 100644 index 000000000..1e742a2a4 --- /dev/null +++ "b/Week 05/id_676/198.\346\211\223\345\256\266\345\212\253\350\210\215.java" @@ -0,0 +1,63 @@ +/* + * @lc app=leetcode.cn id=198 lang=java + * + * [198] 打家劫舍 + */ + + /* + *思路:动态规划: + *分治(分解为子问题) + *状态数组:a[i] 0...i 能偷到的max value a[n-1],但是这样不能表示这个房子偷与不偷得状态,所以可以加一维来表示此状态,a[i][0,1] 0:表示不偷,1:表示偷 + *DP方程 a[i][0] = Max(a[i - 1][0],a[i - 1][1]) a[i][1] = a[i - 1][0] + nums[i] + *简化状态定义 + *a[i] 0...i 且第i天必偷得max value max(a) + *DP方程:a[i] = max(a[i - 1] , a[i - 2] + nums[i]); + */ + +// @lc code=start +class Solution { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + int len = nums.length; + int[][] dp = new int[len][2]; + dp[0][0] = 0; + dp[0][1] = nums[0]; + for (int i = 1;i < len; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]); + dp[i][1] = dp[i - 1][0] + nums[i]; + } + return Math.max(dp[len - 1][0], dp[len - 1][1]); + } +} +// @lc code=end + +class SolutionOne { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + int len = nums.length; + int[] dp = new int[len]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + int max = Math.max(dp[0], dp[1]); + for (int i = 2;i < len; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + max = Math.max(max, dp[i]); + } + return max; + } +} + +//方法同one,只是每一步只需要前两个状态值,所以可以只用两个变量,不用另开数组 +class SolutionTwo{ + public int rob(int[] num) { + int prevMax = 0; + int currMax = 0; + for (int x : num) { + int temp = currMax; + currMax = Math.max(prevMax + x, currMax); + prevMax = temp; + } + return currMax; + } +} \ No newline at end of file diff --git "a/Week 05/id_676/213.\346\211\223\345\256\266\345\212\253\350\210\215-ii.java" "b/Week 05/id_676/213.\346\211\223\345\256\266\345\212\253\350\210\215-ii.java" new file mode 100644 index 000000000..ee54f67a7 --- /dev/null +++ "b/Week 05/id_676/213.\346\211\223\345\256\266\345\212\253\350\210\215-ii.java" @@ -0,0 +1,86 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=213 lang=java + * + * [213] 打家劫舍 II + */ + +/* +*思路:动态规划DP +*分治(分解成子问题) +*状态数组:a[i][0,1] 0代表不偷,1代表偷 max value a[i - 1] +*DP方程:a[i][0] = Max(a[i - 1][1],a[i - 1][0]) a[i][1] = a[i - 1][0] + nums[i] +*该问题同198题,区别在于房屋是环状的,需要将问题分解为2种情况:第一个房屋不偷(2~n) 第一个房屋偷(1~n-1) +*简化状态为一维 +*a[i] 0....i且第i家一定偷 max value max(a) +*a[i] = Max(a[i - 1],a[i - 2] + nums[i]) +*/ + +// @lc code=start +class Solution { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + if (nums.length == 2) return nums[0] > nums[1]? nums[0] : nums[1]; + int len = nums.length; + return Math.max(helper(0, len - 2, nums),helper(1, len - 1, nums)); + } + + private int helper(int start, int end, int[] nums) { + int[] newNums = Arrays.copyOfRange(nums, start, end + 1); //将数组从start ~ end拷贝到新数组中 + int[][] dp = new int[newNums.length][2]; + dp[0][0] = 0; + dp[0][1] = newNums[0]; + for (int i = 1; i < newNums.length; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]); + dp[i][1] = dp[i - 1][0] + newNums[i]; + } + return Math.max(dp[newNums.length - 1][0], dp[newNums.length - 1][1]); + } +} +// @lc code=end + +class SolutionOne { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + if (nums.length == 2) return nums[0] > nums[1]? nums[0] : nums[1]; + int len = nums.length; + return Math.max(helper(0, len - 2, nums),helper(1, len - 1, nums)); + } + + private int helper(int start, int end, int[] nums) { + int[] newNums = Arrays.copyOfRange(nums,start, end + 1); + int[] dp = new int[newNums.length]; + dp[0]= newNums[0]; + dp[1] = Math.max(newNums[0], newNums[1]); + int max = Math.max(dp[0],dp[1]); + for (int i = 2; i < newNums.length; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + newNums[i]); + max = Math.max(max, dp[i]); + } + return max; + } +} + +class SolutionTwo { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + if (nums.length == 2) return nums[0] > nums[1]? nums[0] : nums[1]; + int len = nums.length; + return Math.max(helper(0, len - 2, nums),helper(1, len - 1, nums)); + } + public int helper(int start, int end, int[] nums) { + int[] newNums = Arrays.copyOfRange(nums, start, end + 1); + int prevMax = 0; + int currMax = 0; + for (int x : newNums) { + int temp = currMax; + currMax = Math.max(prevMax + x, currMax); + prevMax = temp; + } + return currMax; + } +} \ No newline at end of file diff --git "a/Week 05/id_676/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" "b/Week 05/id_676/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" new file mode 100644 index 000000000..390ea617a --- /dev/null +++ "b/Week 05/id_676/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=53 lang=java + * + * [53] 最大子序和 + */ + +/* +*思路:动态规划 +*1.分治(分解成子问题):max_sum(i) = Max(max_sum(i-1)+nums[i],nums[i]) +*2.状态数组:f[i] +*3.DP方程:f[i] = Max(f[i - 1],0) + nums[i]; +*/ + +// @lc code=start +class Solution { + public int maxSubArray(int[] nums) { + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + int max = dp[0]; + for (int i = 1; i < nums.length; i++) { + dp[i] = Math.max(0, dp[i - 1]) + nums[i]; + //dp[i] = nums[i] + dp[i - 1] > 0 ? dp[i - 1] : 0; + max = Math.max(max, dp[i]); + } + return max; + } +} +// @lc code=end +class SolutionOne { + public int maxSubArray(int[] nums) { + int max = nums[0]; + for (int i = 1; i < nums.length; i++) { + nums[i] = Math.max(0, nums[i - 1]) + nums[i]; + //nums[i] = nums[i-1] > 0?nums[i-1] + nums[i] : nums[i]; + max = Math.max(max, nums[i]); + } + return max; + } +} diff --git "a/Week 05/id_676/62.\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/Week 05/id_676/62.\344\270\215\345\220\214\350\267\257\345\276\204.java" new file mode 100644 index 000000000..8a0e04fa4 --- /dev/null +++ "b/Week 05/id_676/62.\344\270\215\345\220\214\350\267\257\345\276\204.java" @@ -0,0 +1,42 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=62 lang=java + * + * [62] 不同路径 + */ + + /* + *思路:动态规划dp + */ + +// @lc code=start +class Solution { + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for (int i = 0; i < m; i++) dp[i][0] = 1; + for (int i = 0; i < n; i++) dp[0][i] =1; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j ++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1] [n -1]; + } + + //我们不需要存储整个二维数组,只要得到i - 1 和 i-2即可 + public int uniquePaths1(int m, int n) { + if (m == 0 || n == 0) return 0; + if (m == 1 || n == 1) return 1; + int[] dp = new int[n]; + Arrays.fill(dp, 1); + for (int i = 1;i < m;i++) { + for (int j = 1; j < n; j++) { + dp[j] = dp[j] + dp[j - 1]; + } + } + return dp[n - 1]; + } +} +// @lc code=end + diff --git "a/Week 05/id_676/63.\344\270\215\345\220\214\350\267\257\345\276\204-ii.java" "b/Week 05/id_676/63.\344\270\215\345\220\214\350\267\257\345\276\204-ii.java" new file mode 100644 index 000000000..49df595bb --- /dev/null +++ "b/Week 05/id_676/63.\344\270\215\345\220\214\350\267\257\345\276\204-ii.java" @@ -0,0 +1,63 @@ +/* + * @lc app=leetcode.cn id=63 lang=java + * + * [63] 不同路径 II + */ + +// @lc code=start +class Solution { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int [][] dp = new int[m][n]; + for (int i = 0; i < m; i++) { + if (obstacleGrid[i][0] == 1) { + while (i < m) { + dp[i][0] = 0; + i++; + } + } else { + dp[i][0] = 1; + } + } + + for (int i = 0; i < n; i++) { + if (obstacleGrid[0][i] == 1) { + while (i < n) { + dp[0][i] = 0; + i++; + } + } else { + dp[0][i] = 1; + } + } + + for (int i = 1; i < m; i++) { + for (int j = 1;j < n; j++) { + if (obstacleGrid[i][j] == 1) { + dp[i][j] = 0; + } else { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + } + return dp[m - 1][n - 1]; + } + + public int uniquePathsWithObstacles1(int[][] obstacleGrid) { + int n = obstacleGrid[0].length; + int[] dp = new int[n]; + dp[0] = 1; + for (int[] row : obstacleGrid) { + for (int j = 0; j < n; j++) { + if (row[j] == 1) + dp[j] = 0; + else if (j > 0) + dp[j] += dp[j - 1]; + } + } + return dp[n-1]; + } +} +// @lc code=end + diff --git a/Week 05/id_681/LeetCode_32_681.java b/Week 05/id_681/LeetCode_32_681.java new file mode 100644 index 000000000..78807cf0f --- /dev/null +++ b/Week 05/id_681/LeetCode_32_681.java @@ -0,0 +1,17 @@ +public class Solution { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} diff --git a/Week 05/id_681/LeetCode_64_681.java b/Week 05/id_681/LeetCode_64_681.java new file mode 100644 index 000000000..185021a7c --- /dev/null +++ b/Week 05/id_681/LeetCode_64_681.java @@ -0,0 +1,18 @@ +public class Solution { + public int minPathSum(int[][] grid) { + int[] dp = new int[grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + dp[j] = grid[i][j] + dp[j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[j] = grid[i][j] + dp[j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]); + else + dp[j] = grid[i][j]; + } + } + return dp[0]; + } +} diff --git a/Week 05/id_686/LeetCode_120_686.java b/Week 05/id_686/LeetCode_120_686.java new file mode 100644 index 000000000..5ba25dc06 --- /dev/null +++ b/Week 05/id_686/LeetCode_120_686.java @@ -0,0 +1,41 @@ +//给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 +// +// 例如,给定三角形: +// +// [ +// [2], +// [3,4], +// [6,5,7], +// [4,1,8,3] +//] +// +// +// 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 +// +// 说明: +// +// 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 +// Related Topics 数组 动态规划 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int minimumTotal(List> triangle) { + int n = triangle.size(); + int[] dp =new int[n]; + for (int i = 0; i< n;i++) { + dp[i] = triangle.get(n - 1).get(i); + } + + + for (int i = n - 2; i >= 0;i--) { + int len = i + 1; + for (int j = 0; j 0? matrix[0].length: 0; + int maxsqlen = 0; + int[][] dp = new int[rows + 1][cols + 1]; + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + if (maxtrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + + return maxsqlen * maxsqlen; + } +} \ No newline at end of file diff --git a/Week 05/id_691/691-Week 05/LeetCode-31-691.java b/Week 05/id_691/691-Week 05/LeetCode-31-691.java new file mode 100644 index 000000000..aa24f619d --- /dev/null +++ b/Week 05/id_691/691-Week 05/LeetCode-31-691.java @@ -0,0 +1,18 @@ +class Solution { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + + for (int i = 1; i < s.length(); i++){ + if(s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2? dp[i - 2] : 0) + 2; + } else if ( i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2]: 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} \ No newline at end of file diff --git a/Week 05/id_691/691-Week 05/LeetCode-64-691.java b/Week 05/id_691/691-Week 05/LeetCode-64-691.java new file mode 100644 index 000000000..26b354e3c --- /dev/null +++ b/Week 05/id_691/691-Week 05/LeetCode-64-691.java @@ -0,0 +1,21 @@ +class Solution { + public int minPathSum(int[][] grid) { + int m = grid.length;//row + int n = grid[0].length;//column + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j != 0) { + grid[i][j] = grid[i][j] + grid[i][j - 1]; + } else if (i != 0 && j == 0) { + grid[i][j] = grid[i][j] + grid[i - 1][j]; + } else if (i == 0 && j == 0) { + grid[i][j] = grid[i][j]; + } else { + grid[i][j] = Math.min(grid[i][j - 1],grid[i - 1][j]) + grid[i][j]; + } + } + } + + return grid[m - 1][n - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_691/691-Week 05/LeetCode-72-691.java b/Week 05/id_691/691-Week 05/LeetCode-72-691.java new file mode 100644 index 000000000..2117c29ea --- /dev/null +++ b/Week 05/id_691/691-Week 05/LeetCode-72-691.java @@ -0,0 +1,27 @@ +class Solution { + public int minDistance(String word1, String word2) { + int m = word1.length(); + int n = word2.length(); + + int[][] cost = new int[m + 1][n + 1]; + for (int i = 0; i < m; i++) + cost[i][0] = i; + for (int i = 1; i <= n; i++) + cost[0][i] = i; + + for(int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (word1.charAt(i) == word2.charAt(j)) + cost[i + 1][j + 1] = cost[i][j]; + else { + int replace = cost[i][j]; + int delete = cost[i][j + 1]; + int insert = cost[i + 1][j]; + cost[i + 1][j + 1] = Math.min(replace, Math.min(delete,insert)) + 1; + } + } + } + + return cost[m][n]; + } +} \ No newline at end of file diff --git a/Week 05/id_691/691-Week 05/Leetcode-91-691.java b/Week 05/id_691/691-Week 05/Leetcode-91-691.java new file mode 100644 index 000000000..c0d4d6a28 --- /dev/null +++ b/Week 05/id_691/691-Week 05/Leetcode-91-691.java @@ -0,0 +1,25 @@ +class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + int n = s.length(); + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + for (int i = 2; i <= n; i++) { + int first = Integer.valueOf(s.substring(i - 1, i)); + int second = Integer.valueOf(s.substring(i - 2, i)); + if (first >= 1 && first <= 9) { + dp[i] += dp[i - 1]; + } + + if (second >= 10 && second <= 26) { + dp[i] += dp[i - 2]; + } + } + + return dp[n]; + } +} \ No newline at end of file diff --git a/Week 05/id_696/LeetCode_647_696.java b/Week 05/id_696/LeetCode_647_696.java new file mode 100644 index 000000000..83b4e43d3 --- /dev/null +++ b/Week 05/id_696/LeetCode_647_696.java @@ -0,0 +1,22 @@ +package week05; + +class Solution { + public int countSubstrings(String s) { + int result = 0; + for (int i = 0; i < s.length(); i++) { + //以当前点i位置,向两边扩展,以i i+1位置向两边扩展 + result += countSegment(s, i, i); + result += countSegment(s, i, i + 1); + } + return result; + } + + private int countSegment(String s, int start, int end) { + int count = 0; + //start往左边跑,end往右边跑,注意边界 + while (start >= 0 && end < s.length() && s.charAt(start--) == s.charAt(end++)) { + count++; + } + return count; + } +} diff --git a/Week 05/id_696/LeetCode_64_696.java b/Week 05/id_696/LeetCode_64_696.java new file mode 100644 index 000000000..d944258e3 --- /dev/null +++ b/Week 05/id_696/LeetCode_64_696.java @@ -0,0 +1,17 @@ +package week05; + +class Solution { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + return grid[0][0]; + } +} diff --git a/Week 05/id_701/LeetCode_032_701.py b/Week 05/id_701/LeetCode_032_701.py new file mode 100644 index 000000000..6cdb55bb2 --- /dev/null +++ b/Week 05/id_701/LeetCode_032_701.py @@ -0,0 +1,11 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + dp, stack = [0] * (len(s) + 1), [] + for i in range(len(s)): + if s[i] == '(': + stack.append(i) + else: + if stack: + p = stack.pop() + dp[i+1] = dp[p] + i - p + 1 + return max(dp) \ No newline at end of file diff --git a/Week 05/id_701/LeetCode_072_701.py b/Week 05/id_701/LeetCode_072_701.py new file mode 100644 index 000000000..28585310d --- /dev/null +++ b/Week 05/id_701/LeetCode_072_701.py @@ -0,0 +1,15 @@ +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + import functools + @functools.lru_cache(None) + def helper(i, j): + if i == len(word1) or j == len(word2): + return len(word1) - i + len(word2) - j + if word1[i] == word2[j]: + return helper(i + 1, j + 1) + else: + inserted = helper(i, j + 1) + deleted = helper(i + 1, j) + replaced = helper(i + 1, j + 1) + return min(inserted, deleted, replaced) + 1 + return helper(0, 0) diff --git a/Week 05/id_701/NOTE.md b/Week 05/id_701/NOTE.md index a6321d6e2..d5c9688b9 100644 --- a/Week 05/id_701/NOTE.md +++ b/Week 05/id_701/NOTE.md @@ -1,4 +1,61 @@ -# NOTE +# 【701-week5】第五周学习总结 - +### 递归 +```python +def recur(level:int, param:int): + # terminator + if level > MAX_LEVEL: + # process result + return + + # process current logic + process(level, param) + + # drill down + recur(level+1, newParam) + + # restore curret status +``` + +### 分治 + +```python +def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + + # revert the current level state +``` + +注意事项: + +- 避免人肉递归低效、很累 +- 找到最近最简方法,将其拆解成可重复解决的问题 +- 数学归纳法思维(抵制人肉递归的诱惑) + +> 本质:寻找重复性 —> 计算机指令 + +### 动态规划 + +关键点: + +- 动态规划 和 递归或者分治 没有根本上的区别(关键看有无最优的子结构) +- 共性:找到重复子问题 +- 差异性:最优子结构、中途可以淘汰次优解 + +#### 字符串问题 \ No newline at end of file diff --git a/Week 05/id_711/Leetcode_198_711.java b/Week 05/id_711/Leetcode_198_711.java new file mode 100644 index 000000000..464421cc3 --- /dev/null +++ b/Week 05/id_711/Leetcode_198_711.java @@ -0,0 +1,46 @@ +package Week5; + +public class Leetcode_198_711 { + public static void main(String[] args) { + int[] nums = {1,2,3,1}; + System.out.println(rob1(nums)); + } + + /** + * 题解做法。。 + * 执行用时 :0 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :33.9 MB, 在所有 java 提交中击败了90.38%的用户 + * @param nums + * @return + */ + private static int rob1(int[] nums) { + int preMax = 0; + int curMax = 0; //巧妙地解决了1,2的处理 + for (int x : nums) { + int temp = curMax; + curMax = Math.max(x + preMax,curMax); + preMax = temp; + } + return curMax; + } + + /** + * f[i] = Math.max(f[i - 2] + nums[i], f[i - 1]); + * 执行用时 :0 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :34 MB, 在所有 java 提交中击败了90.38%的用户 + * @param nums + * @return + */ + private static int rob(int[] nums) { + int n = nums.length; + if (n < 1) + return 0; + if (n < 2) + return nums[0]; + nums[1] = Math.max(nums[0],nums[1]); + for (int i = 2; i < n; i++) { + nums[i] = Math.max(nums[i - 2] + nums[i], nums[i - 1]); + } + return nums[n - 1]; + } +} diff --git a/Week 05/id_711/Leetcode_221_711.java b/Week 05/id_711/Leetcode_221_711.java new file mode 100644 index 000000000..adef52548 --- /dev/null +++ b/Week 05/id_711/Leetcode_221_711.java @@ -0,0 +1,56 @@ +package Week5; + +public class Leetcode_221_711 { + public static void main(String[] args) { + char[][] matrix = { + {'1','0','1','0','0'}, + {'1','0','1','1','1'}, + {'1','1','1','1','1'}, + {'1','0','0','1','0'} + }; + System.out.println(maximalSquare(matrix)); + } + + /** + * 预处理一下,a[i][j] 记录这行到j有多少个1,b[i][j]记录这列到i有多少个1 + * 当前为'1'时, + * dp[i][j] = min(a[i][j],b[i][j]) > dp[i - 1][j - 1](不为0) ? dp[i - 1][j - 1] + 1 : min(a[i][j], b[i][j]) + * 执行用时 :7 ms, 在所有 java 提交中击败了68.58%的用户 + * 内存消耗 :42.5 MB, 在所有 java 提交中击败了88.89%的用户 + * @param matrix + * @return + */ + private static int maximalSquare(char[][] matrix) { + int n = matrix.length, m = matrix[0].length; + int[][] dp = new int[n + 1][m + 1]; + int[][] a = new int[n + 1][m + 1]; + int[][] b = new int[n + 1][m + 1]; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m ; j++) { + if (matrix[i - 1][j - 1] == '1') { + a[i][j] = a[i][j - 1] + 1; + b[i][j] = b[i - 1][j] + 1; + } + } + } + int ans = 0; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m ; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = 1; + int x = Math.min(a[i][j],b[i][j]); + if (dp[i - 1][j - 1] > 0) { + if (x > dp[i - 1][j - 1]) { + dp[i][j] += dp[i - 1][j - 1]; + } + else { + dp[i][j] = x; + } + } + ans = Math.max(ans, dp[i][j]); + } + } + } + return ans * ans; + } +} diff --git a/Week 05/id_711/Leetcode_32_711.java b/Week 05/id_711/Leetcode_32_711.java new file mode 100644 index 000000000..1432a3d77 --- /dev/null +++ b/Week 05/id_711/Leetcode_32_711.java @@ -0,0 +1,48 @@ +package Week5; + +public class Leetcode_32_711 { + public static void main(String[] args) { + String s = "))(()(()()"; + System.out.println(longestValidParentheses(s)); + } + + /** + * 草稿纸上写写画画想出来拉。 + * + * 执行用时 :3 ms, 在所有 java 提交中击败了82.01%的用户 + * 内存消耗 :37.1 MB, 在所有 java 提交中击败了84.11%的用户 + * @param s + * @return + */ + private static int longestValidParentheses(String s) { + int ans = 0; + int n = s.length(); + int[] f = new int[n]; + for (int i = 1; i < n; i++) { + if (s.charAt(i) == '(') { + f[i] = 0; + } + else { + if (s.charAt(i - 1) == '(') { + f[i] = 2; + if (i - 2 > 0) { + f[i] += f[i - 2]; + } + } + else { + int len = f[i - 1]; + if (i - len > 0) { + if (s.charAt(i - len - 1) == '(') { + f[i] = f[i - 1] + 2; + if (i - len - 2 > 0) { + f[i] += f[i - len - 2]; + } + } + } + } + } + ans = Math.max(ans, f[i]); + } + return ans; + } +} diff --git a/Week 05/id_711/Leetcode_64_711.java b/Week 05/id_711/Leetcode_64_711.java new file mode 100644 index 000000000..9b422361b --- /dev/null +++ b/Week 05/id_711/Leetcode_64_711.java @@ -0,0 +1,37 @@ +package Week5; + +public class Leetcode_64_711 { + public static void main(String[] args) { + int[][] grid = { + {1,3,1}, + {1,5,1}, + {4,2,1} + }; + System.out.println(minPathSum(grid)); + } + + /** + * f[i][j] = min(f[i - 1][j],f[i][j - 1]) + grid[i][j]; + * 执行用时 :3 ms, 在所有 java 提交中击败了91.94%的用户 + * 内存消耗 :40 MB, 在所有 java 提交中击败了84.28%的用户 + * @param grid + * @return + */ + private static int minPathSum(int[][] grid) { + int n = grid.length, m = grid[0].length; + int[][] f = new int[n][m]; + f[0][0] = grid[0][0]; + for (int i = 1; i < m; i++) { + f[0][i] = f[0][i - 1] + grid[0][i]; + } + for (int i = 1; i < n; i++) { + f[i][0] = f[i - 1][0] + grid[i][0]; + } + for (int i = 1; i < n; i++) { + for (int j = 1; j < m; j++) { + f[i][j] = Math.min(f[i][j - 1],f[i - 1][j]) + grid[i][j]; + } + } + return f[n - 1][m - 1]; + } +} diff --git a/Week 05/id_711/Leetcode_72_711.java b/Week 05/id_711/Leetcode_72_711.java new file mode 100644 index 000000000..63effe6e6 --- /dev/null +++ b/Week 05/id_711/Leetcode_72_711.java @@ -0,0 +1,38 @@ +package Week5; + +public class Leetcode_72_711 { + public static void main(String[] args) { + String word1 = ""; + String word2 = "a"; + System.out.println(minDistance(word1,word2)); + } + + /** + * 自己想出来的解法,nice,看了题解,和题解做法差不多,nice + * f[i][j]表示word1以第i个字符结尾的子串和word2第j个字符结尾的子串的最小编辑距离 + * f[i][j] = min(f[i][j - 1], f[i - 1][j], f[i - 1][j - 1]) + 1; + * if (word1[i] == word2[j]) f[i][j] = min(f[i - 1][j - 1], f[i][j]); + * @param word1 + * @param word2 + * @return + */ + private static int minDistance(String word1, String word2) { + int n = word1.length(), m = word2.length(); + int[][] f = new int[n + 1][m + 1]; + for (int i = 0; i <= n; i++) { + f[i][0] = i; + } + for (int i = 0; i <= m; i++) { + f[0][i] = i; + } + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + f[i][j] = Math.min(Math.min(f[i][j - 1], f[i - 1][j]),f[i - 1][j - 1]) + 1; + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + f[i][j] = Math.min(f[i - 1][j - 1], f[i][j]); + } + } + } + return f[n][m]; + } +} diff --git a/Week 05/id_711/Leetcode_91_711.java b/Week 05/id_711/Leetcode_91_711.java new file mode 100644 index 000000000..b5f4f6c00 --- /dev/null +++ b/Week 05/id_711/Leetcode_91_711.java @@ -0,0 +1,59 @@ +package Week5; + +public class Leetcode_91_711 { + public static void main(String[] args) { + String s = "0"; + System.out.println(numDecodings1(s)); + } + + /** + * 题解更优美写法 + * @param s + * @return + */ + private static int numDecodings1(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int n = s.length(); + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = s.charAt(0) == '0' ? 1 : 0; + for (int i = 2; i <= n ; i++) { + int x = Integer.valueOf(s.substring(i - 1, i)); + int y = Integer.valueOf(s.substring(i - 2, i)); + if (x > 0) { + dp[i] += dp[i - 1]; + } + if (y > 9 && y < 27) { + dp[i] += dp[i - 2]; + } + } + return dp[n]; + } + + /** + * f[i] = f[i - 1] + f[i - 2](如果满足条件) + * 执行用时 :3 ms, 在所有 java 提交中击败了47.93%的用户 + * 内存消耗 :36 MB, 在所有 java 提交中击败了28.73%的用户 + * @param s + * @return + */ + private static int numDecodings(String s) { + int n = s.length(); + int[] f = new int[n + 1]; + f[0] = 1; + if (Integer.parseInt(s.substring(0,1)) > 0) + f[1] = 1; + for (int i = 2; i <= n ; i++) { + if (Integer.parseInt(s.substring(i - 1,i)) > 0) { + f[i] = f[i - 1]; + } + int x = Integer.valueOf(s.substring(i - 2, i)); + if (x > 9 && x < 27) { + f[i] += f[i - 2]; + } + } + return f[n]; + } +} diff --git a/Week 05/id_716/LeetCode_120_716.java b/Week 05/id_716/LeetCode_120_716.java new file mode 100644 index 000000000..cf01a2c79 --- /dev/null +++ b/Week 05/id_716/LeetCode_120_716.java @@ -0,0 +1,76 @@ +import java.util.List; + +// https://leetcode-cn.com/problems/triangle +// 120. 三角形最小路径和 +// + +public class LeetCode_120_716 { + private int row; + + // 1.1 递归,傻递归,复杂度较高 + // 自顶向下的递归求解,关键是找到重复性,运用递归思想,不要人肉递归 + public int minimumTotal11(List> triangle) { + row = triangle.size(); + return helper(0, 0, triangle); + } + + private int helper(int level, int col, List> triangle) { + // terminator + if (level == row - 1) return triangle.get(level).get(col); + + // drill down + int left = helper(level + 1, col, triangle); + int right = helper(level + 1, col + 1, triangle); + + // process current logic + return Math.min(left, right) + triangle.get(level).get(col); + } + + // 1.2 同样是使用递归,由于单纯递归的复杂度较高,考虑cache临时的中间结果,降低计算复杂度 + public int minimumTotal12(List> triangle) { + row = triangle.size(); + Integer[][] memo = new Integer[row][row]; + return helper(0, 0, memo, triangle); + } + + private int helper(int level, int col, Integer[][] memo, List> triangle) { + // terminator + if (level == row - 1) return triangle.get(level).get(col); + + if (memo[level][col] != null) return memo[level][col]; + + // drill down + int left = helper(level + 1, col, memo, triangle); + int right = helper(level + 1, col + 1, memo, triangle); + memo[level][col] = Math.min(left, right) + triangle.get(level).get(col); + return memo[level][col]; + } + + // 2. dp, bottom-up + // 复杂问题分解为子问题(分治),split your big prob + // 定义状态数组,有n个阶段的子问题,存放每个阶段的中间状态 + // 状态转移方程,dp方程,状态的推导方程 + public int minimumTotal21(List> triangle) { + row = triangle.size(); + int[][] dp = new int[row + 1][row + 1]; + for (int level = row - 1; level >= 0; level--) { + for (int col = 0; col <= level; col++) { + dp[level][col] = Math.min(dp[level + 1][col], dp[level + 1][col + 1]) + + triangle.get(level).get(col); + } + } + return dp[0][0]; + } + + // 2.2 优化dp, bottom-up + public int minimumTotal22(List> triangle) { + row = triangle.size(); + int[] dp = new int[row + 1]; + for (int level = row - 1; level >= 0; level--) { + for (int col = 0; col <= level; col++) { + dp[col] = Math.min(dp[col], dp[col + 1]) + triangle.get(level).get(col); + } + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week 05/id_716/LeetCode_221_716.java b/Week 05/id_716/LeetCode_221_716.java new file mode 100644 index 000000000..163da4362 --- /dev/null +++ b/Week 05/id_716/LeetCode_221_716.java @@ -0,0 +1,45 @@ +// https://leetcode-cn.com/problems/maximal-square/ +// 221. 最大正方形 + +public class LeetCode_221_716 { + // dp + public int maximalSquare1(char[][] matrix) { + int row = matrix.length, col = row > 0 ? matrix[0].length : 0; + int[][] dp = new int[row + 1][col + 1]; + int maxlen = 0; + + for (int i = 1; i <= row; i++) { + for (int j = 1; j <= col; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1], dp[i][j - 1])) + 1; + maxlen = Math.max(maxlen, dp[i][j]); + } + } + } + return maxlen * maxlen; + } + + // 优化空间 dp + public int maximalSquare2(char[][] matrix) { + int row = matrix.length, col = row > 0 ? matrix[0].length : 0; + int[] dp = new int[col + 1]; + int maxlen = 0; + int leftUp = 0; + + for (int i = 1; i <= row; i++) { + for (int j = 1; j <= col; j++) { + int temp = dp[j]; + if (matrix[i - 1][j - 1] == '1') { + dp[j] = Math.min(dp[j], Math.min(dp[j - 1], leftUp)) + 1; + maxlen = Math.max(maxlen, dp[j]); + } else { + dp[j] = 0; + } + leftUp = temp; + } + } + return maxlen * maxlen; + } + + // 应该还可以使用 bfs +} \ No newline at end of file diff --git a/Week 05/id_716/LeetCode_322_716.java b/Week 05/id_716/LeetCode_322_716.java new file mode 100644 index 000000000..f33cde5bf --- /dev/null +++ b/Week 05/id_716/LeetCode_322_716.java @@ -0,0 +1,71 @@ +// https://leetcode-cn.com/problems/coin-change +// 322. 零钱兑换 +// + +public class LeetCode_322_716 { + // 1. 暴力求解,利用回溯思想 + public int coinChange1(int[] coins, int amount) { + // terminator + if (amount == 0) return 0; + + int res = Integer.MAX_VALUE; + for (int coin : coins) { + // 不满足条件,直接忽略 + if (amount - coin < 0) continue; + + // drill down + int subRes = coinChange1(coins, amount - coin); + + // 子问题无解,直接忽略,结束下钻 + if (subRes == -1) continue; + + // 每一层都取子问题的最小值(合并结果) + res = Math.min(res, subRes + 1); + } + + // 每层返回时都返回最小值 + return res == Integer.MAX_VALUE ? -1 : res; + } + + // 2. 带备忘录的递归求解,使用备忘录减少重叠子问题的计算量,大大节省时间 + public int coinChange2(int[] coins, int amount) { + Integer[] memo = new Integer[amount + 1]; + return coinChange2(coins, amount, memo); + } + + private int coinChange2(int[] coins, int amount, Integer[] memo) { + // terminator + if (amount == 0) return 0; + + if (memo[amount] != null) return memo[amount]; + + int res = Integer.MAX_VALUE; + for (int coin : coins) { + if (amount - coin < 0) continue; + int subRes = coinChange2(coins, amount - coin, memo); + if (subRes == -1) continue; + res = Math.min(res, subRes + 1); + } + // 记录 + memo[amount] = res == Integer.MAX_VALUE ? -1 : res; + return memo[amount]; + } + + // 3. dp + public int coinChange3(int[] coins, int amount) { + // state array + // dp[i] 表示达到金额i所需要的最小硬币数 + int[] dp = new int[amount + 1]; + for (int i = 0; i < dp.length; i++) { + dp[i] = amount + 1; + } + + for (int i = 0; i < amount; i++) { + for (int coin : coins) { + if (coin <= i) + dp[i] = Math.min(dp[i - coin] + 1, dp[i]); + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } +} \ No newline at end of file diff --git a/Week 05/id_716/LeetCode_62_716.java b/Week 05/id_716/LeetCode_62_716.java new file mode 100644 index 000000000..67a471345 --- /dev/null +++ b/Week 05/id_716/LeetCode_62_716.java @@ -0,0 +1,38 @@ +import java.util.Arrays; + +// https://leetcode-cn.com/problems/unique-paths +// 62. 不同路径 + +public class LeetCode_62_716 { + // 1. 自顶向下的递归实现 + 记忆化搜索 + // 单纯的递归实现会超出时间限制,复杂度过高,因为是指数级的时间复杂度 + // 1.1 + public int uniquePaths11(int m, int n) { + // 记忆状态,省去重复计算,降低时间复杂度 + int[][] memo = new int[m][n]; + return uniquePaths(m, n, memo); + } + + private int uniquePaths(int m, int n, int[][] memo) { + // terminator + if (m == 0 || n == 0) return 0; + if (m == 1 || n == 1) return 1; + if (memo[m][n] > 0) return memo[m][n]; + + // drill down + memo[m][n] = uniquePaths(m - 1, n, memo) + uniquePaths(m, n - 1, memo); + return memo[m][n]; + } + + // 2. dp loop + public int uniquePaths2(int m, int n) { + int[] memo = new int[n]; + Arrays.fill(memo, 1); + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + memo[j] = memo[j] + memo[j - 1]; + } + } + return memo[n - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_716/LeetCode_63_716.java b/Week 05/id_716/LeetCode_63_716.java new file mode 100644 index 000000000..6ca024028 --- /dev/null +++ b/Week 05/id_716/LeetCode_63_716.java @@ -0,0 +1,30 @@ +// https://leetcode-cn.com/problems/unique-paths-ii/ +// 63. 不同路径 II + +public class LeetCode_63_716 { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid[0][0] == 1) return 0; + + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + + int[] memo = new int[n]; + int[] memoHelper = new int[m]; + memo[0] = 1; + memoHelper[0] = 1; + + for (int i = 1; i < n; i++) + memo[i] = obstacleGrid[0][i] == 1 || memo[i - 1] == 0 ? 0 : 1; + for (int i = 1; i < m; i++) + memoHelper[i] = obstacleGrid[i][0] == 1 || memoHelper[i - 1] == 0 ? 0 : 1; + + for (int i = 1; i < m; i++) { + for (int j = 0; j < n; j++) { + if (j == 0) memo[j] = memoHelper[i]; + else memo[j] = obstacleGrid[i][j] == 1 ? 0 : memo[j] + memo[j - 1]; + } + } + + return memo[n - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_716/LeetCode_64_716.java b/Week 05/id_716/LeetCode_64_716.java new file mode 100644 index 000000000..560a1150f --- /dev/null +++ b/Week 05/id_716/LeetCode_64_716.java @@ -0,0 +1,20 @@ +// https://leetcode-cn.com/problems/minimum-path-sum/ +// 64. 最小路径和 + +public class LeetCode_64_716 { + + // dp + public int minPathSum(int[][] grid) { + int m = grid.length, n = grid[0].length; + int[] dp = new int[n]; + dp[0] = grid[0][0]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j > 0) dp[j] = dp[j - 1] + grid[i][j]; + else if (i > 0 && j == 0) dp[j] = dp[j] + grid[i][j]; + else if (i > 0 && j > 0) dp[j] = Math.min(dp[j - 1], dp[j]) + grid[i][j]; + } + } + return dp[n - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_716/NOTE.md b/Week 05/id_716/NOTE.md index a6321d6e2..3fed1ea80 100644 --- a/Week 05/id_716/NOTE.md +++ b/Week 05/id_716/NOTE.md @@ -1,4 +1,204 @@ # NOTE - +## 动态规划笔记 +分治、递归、动态规划本质上是一样的。 + +- 误区 + +1. 人肉递归低效,很累,一定不要做人肉递归 +2. 找到最近最简方法,将其拆解成可重复解决的问题;复杂的大问题肯定可以拆解成更小的多个子问题 +3. 使用数学归纳法思维,抵制人肉递归;比如n=1,n=2时的情况,n和n+1之间的关系等 +4. 本质:寻找重复性,转变成计算机指令集(if-else,loop,递归等) +5. 如果想要体验一下递归的话,画递归状态树 + +- 动态规划 + +动态规划的定义:[wiki Dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)。把复杂的问题分解成简单的子问题,一般是采用递归的方式。等价于分治+最优子结构。 + +可以理解为动态递推。动态规划和分治或者递归没有根本性区别,关键看有无最优的子结构。共性是找到重复子问题。差异是最优子结构,中途可以淘汰次优解。 + +关键步骤: + +1. 将原问题化繁为简成为子问题 +2. 定义好状态空间 +3. 找出DP方程,动态规划的方程 + +解决DP问题的两种常见方式是:递归+记忆化搜索(这个是自顶向下),另外一个是循环递推(这个是自底向上),建立DP Table bottom-up + +- 题目 + +1. Fibonacci 数列 +2. 路径计数 count the path (done) +3. 路径计数II (done) +4. 最长公共子序列题目 +5. 如果可以走1,2,3步,该怎么解决;如果是相邻的两步不能相同,如何解决? +6. (done) +7. +8. (done) +9. (done) +10. (done) +11. https://leetcode-cn.com/problems/house-robber/ +https://leetcode-cn.com/problems/house-robber-ii/description/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/#/description +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ +https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + +高级DP题目: + +https://leetcode-cn.com/problems/perfect-squares/ +https://leetcode-cn.com/problems/edit-distance/ (重点) +https://leetcode-cn.com/problems/jump-game/ +https://leetcode-cn.com/problems/jump-game-ii/ +https://leetcode-cn.com/problems/unique-paths/ +https://leetcode-cn.com/problems/unique-paths-ii/ +https://leetcode-cn.com/problems/unique-paths-iii/ +https://leetcode-cn.com/problems/coin-change/ +https://leetcode-cn.com/problems/coin-change-2/ + +作业: + +https://leetcode-cn.com/problems/longest-valid-parentheses/ +https://leetcode-cn.com/problems/minimum-path-sum/ (done) +https://leetcode-cn.com/problems/edit-distance/ +https://leetcode-cn.com/problems/decode-ways +https://leetcode-cn.com/problems/maximal-square/ (done) +https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/ +https://leetcode-cn.com/problems/frog-jump/ +https://leetcode-cn.com/problems/split-array-largest-sum +https://leetcode-cn.com/problems/student-attendance-record-ii/ +https://leetcode-cn.com/problems/task-scheduler/ +https://leetcode-cn.com/problems/palindromic-substrings/ +https://leetcode-cn.com/problems/minimum-window-substring/ +https://leetcode-cn.com/problems/burst-balloons/ + +--- + +## 总结 + +### 【716-Week 05】分治、回溯、贪心和动态规划 + +本周是第五周,主要学习动态规划相关的内容,以前总有一个感觉是DP是一个很玄学的东西,不知所云。每每看到用动态规划解决问题的时候,就会觉得解法如此巧妙,但是却难以理解。而本周通过听讲解,做题,看解法,看相关文章和书籍,重新认识了动态规划。 + +本质上,动态规划是一种算法设计技巧,最终都会有一些可以复用的规律。动态规划是用来解决最优化问题的,所以一般情况下的最优化问题都可以使用它来解决。而动态规划相关的问题有一些套路,演化规律是:使用暴力递归解决 -> 使用带有备忘录的递归解决 -> 使用非递归的动态规划(自顶向下和自底向上);整个过程是层层递进,从递归树中一点点找到可以重复利用的规律。 + +我们知道,适合用动态规划的最优化问题需要具备两个基本要素:最优子结构和重叠子问题,那么正确理解这两个基本要素是非常重要的。 + +- 最优子结构 + +怎么理解最优子结构呢?最优子结构意思是原问题的解由子问题的最优解构成,也就是说可以用子问题的最优解来推导出问题的最优解,仍然是很抽象。比如 Coin Change 问题,用 coins 中的哪个硬币之间并不会相互影响,子问题的解之间是相互独立的,也就是说 f(11) = f(10) + f(9) + f(6),子问题 f(10)/f(9)/f(6) 之间是相互独立的且组合后可以推导出问题的解,这种性质就是说明该问题具备最优子结构的性质,这个很关键。 + +- 重叠子问题 + +这是另外一个DP的基本特性。在求解DP问题时,子问题的空间要足够小,递归算法会反复求解相同的子问题,而不是一直生成新的子问题,还是很抽象。比如求解斐波那契额数列时,计算 f(10), 需要计算 f(9) 和 f(8), 计算 f(9) 需要计算 f(8) 和 f(7), 可见子问题 f(8) 被重复计算了多次,而 f(8) 这种现象就是重叠子问题,以此类推,会有很多这样的重叠子问题,重叠子问题带来的坏处是大量的重复计算,要消去重叠子问题带来的影响,一种办法就是使用备忘录,通过查询备忘录减少重复计算。在动态规划中可以使用状态转移表。 + +除此之外,状态转移方程是解决DP问题时又一个重要的特点。我们从最优子结构特性可以知道通过递归求解子问题来得到问题的解,所以可以得到递归推导式,也可以叫做状态转移方程。一般有自顶向下的备忘录递归解法和自底向上的迭代推导解法。能够正确找到状态转移方程是解决DP问题的关键一步。 + +### 爬楼梯问题的升级 + +优秀题解参考: + +#### 题目 + +爬楼梯问题的原问题1:假设你正在爬楼梯,每次你可以爬 1 个或者 2 个台阶,你有多少种不同的方法可以爬到第 n 阶呢? +升级版的问题2:假设你正在爬楼梯,每次你可以爬 1 个、2 个或 3 个台阶,那么在相邻步数不能相同的条件下,你有多少种不同的方法可以爬到第 n 阶呢? + +#### 思路 + +对于问题1,相对来讲会简单一些,解决方法有如下两类:使用自顶向下的递归和自底向上的迭代递推。 + +- 自顶向下的递归实现中可以发现存在大量的重叠子问题,所以利用备忘录功能可以优化效率,代码如下 + +```java +public class Stairs { + public int climbStairs(int n) { + int[] memo = new int[n + 1]; + return climbStairs(n, memo); + } + + private int climbStairs(int n, int[] memo) { + if (n <= 2) return n; + if (memo[n] > 0) return memo[n]; + memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); + return memo[n]; + } +} +``` + +- 自底向上的迭代递推实现可以借助动态规划的思想来解决 + +状态转移方程:当 `n = 1` 或 `n = 2` 时,返回 `n`;否则 f(n) = f(n-1) + f(n-2);也就是说将求解原问题的解转换成求子问题 `n-1` 和子问题 `n-2` 的解。 + +```java +public class Stairs { + public int climbStairs(int n) { + // 状态转移数组 + int[] dp = new int[n + 1]; + dp[1] = 1; + dp[2] = 2; + for (int i = 3; i <= n; i++) { + // 状态转移方程 + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } +} +``` + +对于问题2,增加了一些限制:可以一次走三步和相邻步数不能相同。 + +先考虑一次走三步的情况: + +```text +当 n=1 时,f(1)=1 +当 n=2 时,f(2)=2 +当 n=3 时,f(3)=4 +当 n>3 时,f(n)=f(n-1) + f(n-2) + f(n-3) +``` + +可见这个和只能走1步或2步没有太大的区别。现在我们考虑相邻步数不能相同的情况 + +我们使用动态规划来求解该问题,一般步骤是: + +1. 原问题拆分为子问题,进行分治,通过一定方法证明该问题具备最优子结构 +2. 定义状态数组 +3. 推导分析出DP方程 + +拆分子问题,找最优子结构 + +1. 如果当前爬1步,那么上一步只能是爬2步或者3步 +2. 如果当前爬2步,那么上一步只能是爬1步或者3步 +3. 如果当前爬3步,那么上一步只能是爬1步或者2步 + +由此可见,问题的解是上面三种情况相加得到,可以得到 + +1. 若是从第 n-1 个台阶爬了 1 个台阶到达了第 n 个台阶,那么此时到达第n个台阶的方法数 = 上一步爬 2 个台阶到达第 n-1 个台阶的方法数 + 上一步爬 3 个台阶到达第 n-1 个台阶的方法数; +2. 若是从第 n-2 个台阶爬了 2 个台阶到达了第 n 个台阶,那么此时到达第n个台阶的方法数 = 上一步爬 1 个台阶到达第 n-2 个台阶的方法数 + 上一步爬 3 个台阶到达第 n-2 个台阶的方法数; +3. 若是从第 n-3 个台阶爬了 3 个台阶到达了第 n 个台阶,那么此时到达第n个台阶的方法数 = 上一步爬 1 个台阶到达第 n-3 个台阶的方法数 + 上一步爬 2 个台阶到达第 n-3 个台阶的方法数; + +我们可以构建一个二维的状态数组`dp[i][j]`,用来表示状态转移过程,i 取 1、2、3,j 表示台阶,`dp[i][j]` 表示从上一个位置爬 i 个台阶到达第 j 个台阶所有的方法数 + +```java +public int climbStairs(int n) { + if (n <= 2) return 1; + if (n == 3) return 3; + + // state array + int[][] dp = new int[4][n + 1]; + dp[1][1] = 1; + dp[2][2] = 1; + dp[1][3] = dp[2][3] = dp[3][3] = 1; + + for (int i = 4; i <= n; i++) { + // dp 状态转移 + dp[1][i] = dp[2][i - 1] + dp[3][i - 1]; + dp[2][i] = dp[1][i - 2] + dp[3][i - 2]; + dp[3][i] = dp[1][i - 3] + dp[2][i - 3]; + } + return dp[1][n] + dp[2][n] + dp[3][n]; +} +``` diff --git a/Week 05/id_721/LeetCode_647_721.java b/Week 05/id_721/LeetCode_647_721.java new file mode 100644 index 000000000..f50228422 --- /dev/null +++ b/Week 05/id_721/LeetCode_647_721.java @@ -0,0 +1,40 @@ +package dynamic_programming; + +/** + * @author alis + * @date 2019/11/17 11:25 PM + * @description + */ +public class LeetCode_647_721 { + public int countSubstrings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int result = 0; + boolean[][] dp = buildDPForCountSubstrings(s); + for (int j = 0; j < dp.length; j++) { + for (int i = 0; i <= j; i++) { + if (dp[i][j]) { + result++; + } + } + } + return result; + } + + private boolean[][] buildDPForCountSubstrings(String s) { + int n = s.length(); + boolean[][] dp = new boolean[n][n]; + //注意i 和j 的边界,只计算上半部分,j - i <= 1是为了处理边界,dp[i + 1][j - 1]是dp[i][j]砍头去尾后的是否是回文 + for (int j = 0; j < n; j++) { + for (int i = 0; i <= j; i++) { + if (i == j) { + dp[i][j] = true; + } else { + dp[i][j] = s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i + 1][j - 1]); + } + } + } + return dp; + } +} diff --git a/Week 05/id_721/LeetCode_64_721.java b/Week 05/id_721/LeetCode_64_721.java new file mode 100644 index 000000000..9a23b795f --- /dev/null +++ b/Week 05/id_721/LeetCode_64_721.java @@ -0,0 +1,47 @@ +package dynamic_programming; + +/** + * @author alis + * @date 2019/11/17 10:54 PM + * @description + */ +public class LeetCode_64_721 { + /** + * 解法:暴力遍历所有路径的和的解法就不实现了,就算实现出来也是超时; + * 直接使用DP来实现 + * 最优dp方程:dp(i,j)=grid(i,j)+min(dp(i+1,j),dp(i,j+1)) + * dp三部曲: + * 1. 子问题 + * 2. 状态定义 + * 3. DP方程 + * + * @param grid 网格 + * @return + * @date 2019/11/17 10:55 PM + */ + public int minPathSum(int[][] grid) { + int rows = grid.length; + int column = grid[0].length; + if (rows == 0 && column == 0) return 0; + int[][] dp = new int[rows][column]; + for (int i = rows - 1; i >= 0; i--) { + for (int j = column - 1; j >= 0; j--) { + + if (i == rows - 1 && j != column - 1) + // 最后一行排除最后一列的节点([rows-1][column-1]) + // 最后一行的路径数计算只会从上一步加过来 + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if (j == column - 1 && i != rows - 1) + // 最后一列排除最后一行的节点[rows-1][column-1] + // 当前节点计数需要从上一个节点反推 + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if (j != column - 1 && i != rows - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + +} diff --git a/Week 05/id_731/LeetCode_221_731.txt b/Week 05/id_731/LeetCode_221_731.txt new file mode 100644 index 000000000..baa5e3ca0 --- /dev/null +++ b/Week 05/id_731/LeetCode_221_731.txt @@ -0,0 +1,31 @@ +class Solution { +public: + int maximalSquare(vector>& matrix) { + if(matrix.empty() || matrix[0].empty()) return 0; + + int rows = matrix.size(), cols = matrix[0].size(); + vector> dp(rows, vector(cols,0)); + int maxLen = 0; + // ʼһ + for (int i = 0; i < rows; ++i) { + dp[i][0] = matrix[i][0] - '0'; + maxLen = max(maxLen,dp[i][0]); + } + // ʼһ + for (int j = 0; j < cols; ++j) { + dp[0][j] = matrix[0][j] - '0'; + maxLen = max(maxLen,dp[0][j]); + } + for (int i = 1; i < rows; ++i) { + for (int j = 1; j < cols; ++j) { + if (matrix[i][j]=='0') continue; // Ϊ0 + int len1 = dp[i-1][j]; + int len2 = dp[i][j-1]; + int len3 = dp[i-1][j-1]; + dp[i][j] = min(min(len1,len2),len3) + 1; // ߳ + maxLen = max(dp[i][j], maxLen); + } + } + return maxLen*maxLen; + } +}; \ No newline at end of file diff --git a/Week 05/id_731/LeetCode_32_731.txt b/Week 05/id_731/LeetCode_32_731.txt new file mode 100644 index 000000000..274a7ccde --- /dev/null +++ b/Week 05/id_731/LeetCode_32_731.txt @@ -0,0 +1,33 @@ +class Solution { +public: + int longestValidParentheses(string s) { + int res = 0; + int left = 0; + int mark = 0; + for (int i = 0; i < s.size(); ++i) { + int prev_mark = mark; + mark = max(0, mark + ((s[i] == '(') ? 1 : -1)); + if (mark == 0) { + if (prev_mark > 0) { + res = max(i - left + 1, res); + } else { + left = i + 1; + } + } + } + mark = 0; + int right = s.size() - 1; + for (int i = s.size() - 1; i >= 0; --i) { + int prev_mark = mark; + mark = max(0, mark + ((s[i] == ')') ? 1 : -1)); + if (mark == 0) { + if (prev_mark > 0) { + res = max(right - i + 1, res); + } else { + right = i - 1; + } + } + } + return res; + } +}; \ No newline at end of file diff --git a/Week 05/id_756/[621]Task Scheduler.java b/Week 05/id_756/[621]Task Scheduler.java new file mode 100644 index 000000000..54f8b58f1 --- /dev/null +++ b/Week 05/id_756/[621]Task Scheduler.java @@ -0,0 +1,13 @@ +public class Solution { + public int leastInterval(char[] tasks, int n) { + int[] map = new int[26]; + for (char c: tasks) + map[c - 'A']++; + Arrays.sort(map); + int max_val = map[25] - 1, idle_slots = max_val * n; + for (int i = 24; i >= 0 && map[i] > 0; i--) { + idle_slots -= Math.min(map[i], max_val); + } + return idle_slots > 0 ? idle_slots + tasks.length : tasks.length; + } +} \ No newline at end of file diff --git a/Week 05/id_756/[64]Minimum Path Sum.java b/Week 05/id_756/[64]Minimum Path Sum.java new file mode 100644 index 000000000..5c9bf583c --- /dev/null +++ b/Week 05/id_756/[64]Minimum Path Sum.java @@ -0,0 +1,13 @@ +class Solution { + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} \ No newline at end of file diff --git a/Week 05/id_766/LeetCode_221_766.java b/Week 05/id_766/LeetCode_221_766.java new file mode 100644 index 000000000..c00d2d6bf --- /dev/null +++ b/Week 05/id_766/LeetCode_221_766.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=221 lang=java + * + * [221] 最大正方形 + */ + +// @lc code=start +class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[] dp = new int[cols + 1]; + int maxsqlen = 0, prev = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + int temp = dp[j]; + if (matrix[i - 1][j - 1] == '1') { + dp[j] = Math.min(Math.min(dp[j - 1], prev), dp[j]) + 1; + maxsqlen = Math.max(maxsqlen, dp[j]); + + + } else { + dp[j] = 0; + } + prev = temp; + } + } + return maxsqlen * maxsqlen; + + + } +} +// @lc code=end + diff --git a/Week 05/id_766/LeetCode_621_766.java b/Week 05/id_766/LeetCode_621_766.java new file mode 100644 index 000000000..81b4015a5 --- /dev/null +++ b/Week 05/id_766/LeetCode_621_766.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=621 lang=java + * + * [621] 任务调度器 + */ + +// @lc code=start +class Solution { + public int leastInterval(char[] tasks, int n) { + + int[] c = new int[26]; + for (char t : tasks) { + c[t - 'A']++; + } + Arrays.sort(c); + int i = 25; + while(i >= 0 && c[i] == c[25]) i--; + + return Math.max(tasks.length, (c[25] - 1) * (n + 1) + 25 - i); + + } +} +// @lc code=end + diff --git a/Week 05/id_766/LeetCode_64_766.java b/Week 05/id_766/LeetCode_64_766.java new file mode 100644 index 000000000..9f165089e --- /dev/null +++ b/Week 05/id_766/LeetCode_64_766.java @@ -0,0 +1,23 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (i ==0 && j ==0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j -1]) + grid[i][j]; + } + } + return grid[grid.length -1][grid[0].length - 1]; + + } +} +// @lc code=end + diff --git a/Week 05/id_766/LeetCode_91_766.java b/Week 05/id_766/LeetCode_91_766.java new file mode 100644 index 000000000..f965ad66d --- /dev/null +++ b/Week 05/id_766/LeetCode_91_766.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=91 lang=java + * + * [91] 解码方法 + */ + +// @lc code=start +class Solution { + public int numDecodings(String s) { + int len = s.length(); + int end = 1; + int cur = 0; + if (s.charAt(len - 1) != '0') { + cur = 1; + + } + for (int i = len -2; i >= 0; i--) { + if (s.charAt(i) == '0' ) { + end = cur; + cur = 0; + continue; + } + int ans1 = cur; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = end; + } + end = cur; + cur = ans1 + ans2; + } + return cur; + + } +} +// @lc code=end + diff --git a/Week 06/id_006/LeetCode_127_006.java b/Week 06/id_006/LeetCode_127_006.java new file mode 100644 index 000000000..49746d8c3 --- /dev/null +++ b/Week 06/id_006/LeetCode_127_006.java @@ -0,0 +1,117 @@ +package com.mrglint.leetcode.week06.solution127; + + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 双向BFS + * @author luhuancheng + * @since 2019-11-24 21:36 + */ +public class TwoEndedBfsSolution { + + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + // HashSet提供O(1)时间复杂度的查询 + Set words = new HashSet<>(wordList); + // 记录访问过的单词,转换路径中每个单词只能使用一次 + Set visited = new HashSet<>(); + + // 长度包含第一个单词 + int count = 1; + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + beginSet.add(beginWord); + endSet.add(endWord); + + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + + // 交换一下遍历方向 + if (beginSet.size() > endSet.size()) { + Set temp = beginSet; + beginSet = endSet; + endSet = temp; + } + + Set tempSet = new HashSet<>(); + + for (String word : beginSet) { + char[] chars = word.toCharArray(); + for (int i = 0; i < chars.length; i++) { + for (char c = 'a'; c <= 'z'; c++) { + char oldChar = chars[i]; + chars[i] = c; + String newWord = String.valueOf(chars); + // 两个遍历方向重叠 + if (endSet.contains(newWord)) { + return count + 1; + } + if (!visited.contains(newWord) && words.contains(newWord)) { + tempSet.add(newWord); + visited.add(newWord); + } + chars[i] = oldChar; + } + } + } + count++; + beginSet = tempSet; + } + return 0; + } +} + + +package com.mrglint.leetcode.week06.solution127; + +import java.util.*; + +/** + * 朴素BFS + * @author luhuancheng + * @since 2019-11-24 21:10 + */ +public class BfsSolution { + + private static final String ALL_ALPHABETIC = "abcdefghijklmnopqrstuvwxyz"; + + public int ladderLength(String beginWord, String endWord, List wordList) { + Set wordLists = new HashSet<>(wordList); + + int count = 1; + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + while (!queue.isEmpty()) { + + int size = queue.size(); + while (size-- > 0) { + String queueHead = queue.poll(); + if (Objects.equals(queueHead, endWord)) { + return count; + } + // 进行一次转换 + char[] chars = queueHead.toCharArray(); + for (int i = 0; i < chars.length; i++) { + for (Character c : ALL_ALPHABETIC.toCharArray()) { + char oldChar = chars[i]; + chars[i] = c; + String newWord = new String(chars); + if (wordLists.contains(newWord)) { + queue.offer(newWord); + wordLists.remove(newWord); + } + chars[i] = oldChar; + } + } + } + // 每次转换长度加1 + count++; + } + return 0; + } +} + diff --git a/Week 06/id_006/LeetCode_130_006.java b/Week 06/id_006/LeetCode_130_006.java new file mode 100644 index 000000000..b41b3d405 --- /dev/null +++ b/Week 06/id_006/LeetCode_130_006.java @@ -0,0 +1,101 @@ +package com.mrglint.leetcode.week06.solution130; + +/** + * @author luhuancheng + * @since 2019-11-21 09:01 + */ +public class Solution { + + private static final int[][] DIRECTIONS = new int[][]{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + + private static class UF { + int count; + int[] parent; + // 用于路径压缩 + int[] rank; + + public UF(char[][] grid) { + int rows = grid.length; + int cols = grid[0].length; + parent = new int[rows * cols + 1]; + rank = new int[rows * cols + 1]; + for (int i = 0; i < parent.length; i++) { + parent[i] = i; + } + } + + void union(int i, int j) { + int iRoot = find(i); + int jRoot = find(j); + if (iRoot == jRoot) { + return; + } + // 在合并时,利用rank来进行路径压缩。路径短的合并到路径长的 + if (rank[iRoot] > rank[jRoot]) { + parent[jRoot] = iRoot; + } else if (rank[iRoot] < rank[jRoot]){ + parent[iRoot] = jRoot; + } else { + parent[iRoot] = jRoot; + rank[iRoot] += 1; + } + count--; + } + + int find(int i) { + while (parent[i] != i) { + // 路径压缩 + parent[i] = parent[parent[i]]; + i = parent[i]; + } + return parent[i]; + } + + boolean connected(int i, int j) { + return find(i) == find(j); + } + } + + public void solve(char[][] board) { + if (board.length == 0 || board[0].length == 0) { + return; + } + + int rows = board.length; + int cols = board[0].length; + UF uf = new UF(board); + // 将rows * cols 视为边界为'O'的一个集合 + // 遍历矩阵,连接所有'O',将边界的'O'与rows * cols连接 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') { + // 如果处于边界,则与rows * cols连接 + if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) { + uf.union(node(i, j, cols), rows * cols); + } else { + // 连接上下左右节点为'O'的节点 + for (int[] direction : DIRECTIONS) { + if (board[i + direction[0]][j + direction[1]] == 'O') { + uf.union(node(i, j, cols), node(i + direction[0], j + direction[1], cols)); + } + } + } + } + } + } + + // 替换所有不与边界'O'相连的'O'为'X' + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (!uf.connected(node(i, j, cols), rows * cols)) { + board[i][j] = 'X'; + } + } + } + } + + private int node(int row, int col, int cols) { + return row * cols + col; + } +} + diff --git a/Week 06/id_006/LeetCode_200_006.java b/Week 06/id_006/LeetCode_200_006.java new file mode 100644 index 000000000..c5cd1fb87 --- /dev/null +++ b/Week 06/id_006/LeetCode_200_006.java @@ -0,0 +1,102 @@ +package com.mrglint.leetcode.week06.solution200; + +/** + * @author luhuancheng + * @since 2019-11-21 07:52 + */ +public class Solution { + + /** + * 声明坐标位上「上、左、下、右」四个位置的偏移量 + */ + private static final int[][] DIRECTIONS = new int[][]{{1, 0}, {0, 1}}; + + private static class UF { + int count; + int[] parent; + // 用于路径压缩 + int[] rank; + + public UF(char[][] grid) { + int rows = grid.length; + int cols = grid[0].length; + parent = new int[rows * cols]; + rank = new int[rows * cols]; + + // 将每个'1'初始化为"并查集"中的一个独立节点 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == '1') { + parent[i * cols + j] = i * cols + j; + rank[i * cols + j] = 0; + count++; + } + } + } + } + + void union(int i, int j) { + int iRoot = find(i); + int jRoot = find(j); + if (iRoot == jRoot) { + return; + } + // 在合并时,利用rank来进行路径压缩。路径短的合并到路径长的 + if (rank[iRoot] > rank[jRoot]) { + parent[jRoot] = iRoot; + } else if (rank[iRoot] < rank[jRoot]){ + parent[iRoot] = jRoot; + } else { + parent[iRoot] = jRoot; + rank[iRoot] += 1; + } + count--; + } + + int find(int i) { + while (parent[i] != i) { + // 路径压缩 + parent[i] = parent[parent[i]]; + i = parent[i]; + } + return parent[i]; + } + } + + + public int numIslands(char[][] grid) { + if (grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + + UF uf = new UF(grid); + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + // 连通周围的'1' + for (int[] direction : DIRECTIONS) { + int newRow = i + direction[0]; + int newCol = j + direction[1]; + if (validateCoordinate(newRow, newCol, rows, cols) && grid[newRow][newCol] == '1') { + uf.union(newRow * cols + newCol, i * cols + j); + } + } + } + } + } + return uf.count; + } + + private boolean validateCoordinate(int row, int col, int rows, int cols) { + return row >= 0 && row < rows && col >= 0 && col < cols; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + solution.numIslands(new char[][]{{'1'}, {'1'}}); + } +} + diff --git a/Week 06/id_006/LeetCode_208_006.java b/Week 06/id_006/LeetCode_208_006.java new file mode 100644 index 000000000..cdee6106a --- /dev/null +++ b/Week 06/id_006/LeetCode_208_006.java @@ -0,0 +1,89 @@ +package com.mrglint.leetcode.week06.solution208; + +/** + * @author luhuancheng + * @since 2019-11-18 08:43 + */ +public class Trie { + + private static class TrieNode { + TrieNode[] children = new TrieNode[26]; + boolean endWord; + + boolean containsKey(char c) { + return children[c - 'a'] != null; + } + + TrieNode put(char c) { + children[c - 'a'] = new TrieNode(); + return children[c - 'a']; + } + + TrieNode get(char c) { + return children[c - 'a']; + } + + public boolean isEndWord() { + return endWord; + } + + public void setEndWord(boolean endWord) { + this.endWord = endWord; + } + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + root.endWord = false; + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + char[] chars = word.toCharArray(); + for (char c : chars) { + if (node.containsKey(c)) { + node = node.get(c); + } else { + node = node.put(c); + } + } + node.setEndWord(true); + } + + private TrieNode searchNode(String word) { + TrieNode node = root; + char[] chars = word.toCharArray(); + for (char c : chars) { + if (node.containsKey(c)) { + node = node.get(c); + } else { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode trieNode = searchNode(word); + return trieNode != null && trieNode.endWord; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + return searchNode(prefix) != null; + } + + public static void main(String[] args) { + Trie trie = new Trie(); + trie.insert("word"); + System.out.println(trie.search("word")); + System.out.println(trie.startsWith("wor")); + System.out.println(trie.startsWith("dwor")); + } +} + diff --git a/Week 06/id_006/LeetCode_212_006.java b/Week 06/id_006/LeetCode_212_006.java new file mode 100644 index 000000000..5afc3598c --- /dev/null +++ b/Week 06/id_006/LeetCode_212_006.java @@ -0,0 +1,143 @@ +package com.mrglint.leetcode.week06.solution212; + +import java.util.*; + +/** + * 1. 将单词列表构建Trie树 + * 2. 遍历board中的每个字母作为单词开头,从该字母DFS继续遍历。将走过的路径到Trie中查找,如果存在的话就放到结果集中(注意同一单元格内的字母在一个单词中不允许重复使用) + * @author luhuancheng + * @since 2019-11-19 07:16 + */ +public class Solution { + + /** + * 四连通图的坐标偏移 + */ + private final static int[][] DIRECTIONS = new int[][]{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + + private static class Trie { + + private static class TrieNode { + TrieNode[] children = new TrieNode[26]; + boolean endWord; + + boolean containsKey(char c) { + return children[c - 'a'] != null; + } + + TrieNode put(char c) { + children[c - 'a'] = new TrieNode(); + return children[c - 'a']; + } + + TrieNode get(char c) { + return children[c - 'a']; + } + + public boolean isEndWord() { + return endWord; + } + + public void setEndWord(boolean endWord) { + this.endWord = endWord; + } + } + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + root.endWord = false; + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + char[] chars = word.toCharArray(); + for (char c : chars) { + if (node.containsKey(c)) { + node = node.get(c); + } else { + node = node.put(c); + } + } + node.setEndWord(true); + } + + private TrieNode searchNode(String word) { + TrieNode node = root; + char[] chars = word.toCharArray(); + for (char c : chars) { + if (node.containsKey(c)) { + node = node.get(c); + } else { + return null; + } + } + return node; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode trieNode = searchNode(word); + return trieNode != null && trieNode.endWord; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + return searchNode(prefix) != null; + } + } + + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + for (String word : words) { + trie.insert(word); + } + Set result = new HashSet<>(); + + int rows = board.length; + int cols = board[0].length; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + dfs(row, col, rows, cols, board, "", trie, result); + } + } + return new ArrayList<>(result); + } + + private void dfs(int row, int col, int rows, int cols, char[][] board, String tempWord, Trie trie, Set result) { + if (!validateCoordinate(board, row, rows, col, cols)) { + return; + } + + tempWord = tempWord + board[row][col]; + char temp = board[row][col]; + board[row][col] = '#'; + + Trie.TrieNode trieNode = trie.searchNode(tempWord); + if (Objects.nonNull(trieNode)) { + if (Objects.equals(trieNode.endWord, true)) { + result.add(tempWord); + } + for (int[] direction : DIRECTIONS) { + dfs(row + direction[0], col + direction[1], rows, cols, board, tempWord, trie, result); + } + } + board[row][col] = temp; + } + + private boolean validateCoordinate(char[][] board, int row, int rows, int col, int cols) { + return row >= 0 && row < rows && col >= 0 && col < cols && board[row][col] != '#'; + } +} + diff --git a/Week 06/id_006/LeetCode_36_006.java b/Week 06/id_006/LeetCode_36_006.java new file mode 100644 index 000000000..4110a9dfa --- /dev/null +++ b/Week 06/id_006/LeetCode_36_006.java @@ -0,0 +1,64 @@ +package com.mrglint.leetcode.week06.solution36; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-11-23 07:32 + */ +public class Solution { + + /** + * 1. 遍历整个矩阵 + * 2. 根据矩阵中元素的坐标,计算出子数独的索引:假设坐标位(i, j),矩阵为rows * cols,子数独索引计算公式:(i / 3) * 3 + j / 3 + * + * + * @param board + * @return + */ + public boolean isValidSudoku(char[][] board) { + List> rows = new ArrayList<>(); + List> cols = new ArrayList<>(); + List> subSudokus = new ArrayList<>(); + + // 初始化 + for (int i = 0; i < 9; i++) { + rows.add(new HashMap<>()); + cols.add(new HashMap<>()); + subSudokus.add(new HashMap<>()); + } + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[i].length; j++) { + if (board[i][j] != '.') { + Map rowsMap = rows.get(i); + Map colsMap = cols.get(j); + Map subSudokusMap = subSudokus.get(subSudokuIndex(i, j)); + if (inValidate(rowsMap, i, j, board) || inValidate(colsMap, i, j, board) || inValidate(subSudokusMap, i, j, board)) { + return false; + } + } + } + } + return true; + } + + private int subSudokuIndex(int row, int col) { + return (row / 3) * 3 + col / 3; + } + + private boolean inValidate(Map map, int row, int col, char[][] board) { + // 如果不存在返回-1 + Integer count = map.getOrDefault(board[row][col], -1); + // 当前行、列、子数独未包含该字符 + if (count == -1) { + map.put(board[row][col], 1); + return false; + } else { + // 当前行、列、子数独未包含该字符 + return true; + } + } + +} + diff --git a/Week 06/id_006/LeetCode_37_006.java b/Week 06/id_006/LeetCode_37_006.java new file mode 100644 index 000000000..4dc0fa246 --- /dev/null +++ b/Week 06/id_006/LeetCode_37_006.java @@ -0,0 +1,72 @@ +package com.mrglint.leetcode.week06.solution37; + +/** + * @author luhuancheng + * @since 2019-11-23 09:08 + */ +public class Solution { + + public void solveSudoku(char[][] board) { + + boolean[][] rowsUsed = new boolean[9][10]; + boolean[][] colsUsed = new boolean[9][10]; + // 子数独 + boolean[][] subSudokusUsed = new boolean[9][10]; + + // 初始化 + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + int placeNumber = board[i][j] - '0'; + rowsUsed[i][placeNumber] = true; + colsUsed[j][placeNumber] = true; + // 根据坐标,计算所在的子数独索引 + int subSudokuNum = subSudokuIndex(i, j); + subSudokusUsed[subSudokuNum][placeNumber] = true; + } + } + } + + // 递归求解,遍历所有格子,为空格时,对1 - 9进行筛选(行、列、小区域不能重复)选取一个合适的数字填入格子中,进入下一个格子。 + // 如果下探到下一格子时无法求解,则回溯到下探前的格子 + // 直到遍历到最后一个格子 + solveSudoku(board, rowsUsed, colsUsed, subSudokusUsed); + } + + private boolean solveSudoku(char[][] board, boolean[][] rowsUsed, boolean[][] colsUsed, boolean[][] subSudokusUsed) { + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] == '.') { + for (int placeNumber = 1; placeNumber <= 9; placeNumber++) { + if (canPlace(i, j, rowsUsed, colsUsed, subSudokusUsed, placeNumber)) { + // 放置数字 + board[i][j] = Character.forDigit(placeNumber, 10); + rowsUsed[i][placeNumber] = true; + colsUsed[j][placeNumber] = true; + subSudokusUsed[subSudokuIndex(i, j)][placeNumber] = true; + if (solveSudoku(board, rowsUsed, colsUsed, subSudokusUsed)) { + return true; + } + board[i][j] = '.'; + rowsUsed[i][placeNumber] = false; + colsUsed[j][placeNumber] = false; + subSudokusUsed[subSudokuIndex(i, j)][placeNumber] = false; + } + } + return false; + } + } + } + return true; + } + + private int subSudokuIndex(int row, int col) { + return (row / 3) * 3 + col / 3; + } + + private boolean canPlace(int row, int col, boolean[][] rowsUsed, boolean[][] colsUsed, boolean[][] subSudokusUsed, int number) { + return !rowsUsed[row][number] && !colsUsed[col][number] && !subSudokusUsed[subSudokuIndex(row, col)][number]; + } + +} + diff --git a/Week 06/id_006/LeetCode_51_006.java b/Week 06/id_006/LeetCode_51_006.java new file mode 100644 index 000000000..1871838ce --- /dev/null +++ b/Week 06/id_006/LeetCode_51_006.java @@ -0,0 +1,70 @@ +package com.mrglint.leetcode.week06.solution51; + +import java.util.*; + +/** + * @author luhuancheng + * @since 2019-11-22 08:39 + */ +public class Solution { + + public List> solveNQueens(int n) { + Set cols = new HashSet<>(); + Set pie = new HashSet<>(); + Set na = new HashSet<>(); + List> result = new ArrayList<>(); + + solveNQueens(0, n, cols, pie, na, new ArrayList<>(), result); + return renderResult(result); + } + + private List> renderResult(List> result) { + List> res = new ArrayList<>(); + for (List cols : result) { + List subRes = new ArrayList<>(); + for (Integer col : cols) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < cols.size(); i++) { + if (i != col) { + stringBuilder.append('.'); + } else { + stringBuilder.append('Q'); + } + } + subRes.add(stringBuilder.toString()); + } + res.add(subRes); + } + return res; + } + + private void solveNQueens(int row, int n, Set cols, Set pie, Set na, + List subResult, List> result) { + // terminator + if (row == n) { + result.add(subResult); + return; + } + + // process logical + for (int col = 0; col < n; col++) { + if (cols.contains(col) || pie.contains(row + col) || na.contains(row - col)) { + continue; + } + cols.add(col); + pie.add(row + col); + na.add(row - col); + subResult.add(col); + + // drill down + solveNQueens(row + 1, n, cols, pie, na, new ArrayList<>(subResult), result); + // restore state + cols.remove(col); + pie.remove(row + col); + na.remove(row - col); + // 回溯时,需要删除下探前的 + subResult.remove(subResult.size() - 1); + } + } +} + diff --git a/Week 06/id_006/LeetCode_547_006.java b/Week 06/id_006/LeetCode_547_006.java new file mode 100644 index 000000000..1173b300f --- /dev/null +++ b/Week 06/id_006/LeetCode_547_006.java @@ -0,0 +1,66 @@ +package com.mrglint.leetcode.week06.solution547; + +/** + * @author luhuancheng + * @since 2019-11-20 07:56 + */ +public class UnionFindSolution { + + private static class UF { + int count; + int[] parent; + + public UF(int count) { + parent = new int[count]; + this.count = count; + // 初始化并查集 + for (int i = 0; i < count; i++) { + // 初始化时,每个元素自成一格集合 + parent[i] = i; + } + } + + void union(int i, int j) { + int iRoot = find(i); + int jRoot = find(j); + if (iRoot == jRoot) { + return; + } + parent[iRoot] = jRoot; + // 维护集合的个数 + count--; + } + + int find(int i) { + while (parent[i] != i) { + // 重新设定父节点指向,路径压缩 + parent[i] = parent[parent[i]]; + i = parent[i]; + } + return i; + } + } + + public int findCircleNum(int[][] M) { + UF uf = new UF(M.length); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1) { + uf.union(i, j); + } + } + } + return uf.count; + } + + public static void main(String[] args) { + UnionFindSolution solution = new UnionFindSolution(); + // 1 0 0 1 + // 0 1 1 0 + // 0 1 1 1 + // 1 0 1 1 + int circleNum = solution.findCircleNum(new int[][]{{1, 0, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1}, {1, 0, 1, 1}}); + System.out.println(circleNum); + } +} + diff --git a/Week 06/id_006/NOTE.md b/Week 06/id_006/NOTE.md index a6321d6e2..ce312da4f 100644 --- a/Week 06/id_006/NOTE.md +++ b/Week 06/id_006/NOTE.md @@ -1,4 +1,12 @@ -# NOTE - +# 学习总结 +## 并查集 +- 解决分组、集合问题。优化点:路径压缩 +## 高级搜索 +### 剪枝 +- 去掉不必要的分支,提早杜绝执行 +### 双向BFS +- 从起点和末尾分别进行搜索,每次选取遍历次数少的一端进行搜索,提高效率 +### 启发式搜索 +- 没消化好~~ diff --git a/Week 06/id_011/friend-circles.go b/Week 06/id_011/friend-circles.go new file mode 100644 index 000000000..50f71503f --- /dev/null +++ b/Week 06/id_011/friend-circles.go @@ -0,0 +1,30 @@ +package algorithm00401 + +func findCircleNum(M [][]int) int { + N := len(M) + res := N + + friend := make([]int, res) + for i := 0; i < res; i++ { + friend[i] = i + } + + for i := 0; i < N; i++ { + for j := i + 1; j < N; j++ { + if M[i][j] == 1 && friend[i] != friend[j] { + res-- + union(friend[i], friend[j], friend) + } + } + } + + return res +} + +func union(x, y int, friend []int) { + for i := 0; i < len(friend); i++ { + if friend[i] == x { + friend[i] = y + } + } +} diff --git a/Week 06/id_011/implement-trie-prefix-tree.go b/Week 06/id_011/implement-trie-prefix-tree.go new file mode 100644 index 000000000..76f39a879 --- /dev/null +++ b/Week 06/id_011/implement-trie-prefix-tree.go @@ -0,0 +1,44 @@ +package algorithm00401 + +type Trie struct { + val byte + sons [26]*Trie + isEnd bool +} + +func Constructor() Trie { + return Trie{} +} + +func (this *Trie) Insert(word string) { + for i := 0; i < len(word); i++ { + idx := word[i] - 'a' + if this.sons[idx] == nil { + this.sons[idx] = &Trie{val: word[i]} + } + this = this.sons[idx] + } + this.isEnd = true +} + +func (this *Trie) Search(word string) bool { + for i := 0; i < len(word); i++ { + idx := word[i] - 'a' + if this.sons[idx] == nil { + return false + } + this = this.sons[idx] + } + return this.isEnd +} + +func (this *Trie) StartsWith(prefix string) bool { + for i := 0; i < len(prefix); i++ { + idx := prefix[i] - 'a' + if this.sons[idx] == nil { + return false + } + this = this.sons[idx] + } + return true +} diff --git a/Week 06/id_011/valid-sudoku.go b/Week 06/id_011/valid-sudoku.go new file mode 100644 index 000000000..43c290f47 --- /dev/null +++ b/Week 06/id_011/valid-sudoku.go @@ -0,0 +1,23 @@ +package algorithm00401 + +func isValidSudoku(board [][]byte) bool { + var row, col, block [9]uint + var cur uint + + for i := 0; i < 9; i++ { + for j := 0; j < 9; j++ { + if board[i][j] == '.' { + continue + } + cur = 1 << (board[i][j] - '1') + bi := i/3 + j/3*3 + if (row[i]&cur)|(col[j]&cur)|(block[bi]&cur) != 0 { + return false + } + row[i] |= cur + col[j] |= cur + block[bi] |= cur + } + } + return true +} diff --git a/Week 06/id_011/word-search-ii.go b/Week 06/id_011/word-search-ii.go new file mode 100644 index 000000000..1a6fb2bcf --- /dev/null +++ b/Week 06/id_011/word-search-ii.go @@ -0,0 +1,78 @@ +package algorithm00401 + +func findWords(board [][]byte, words []string) []string { + var results []string + + m := len(board) + n := len(board[0]) + if m == 0 || n == 0 { + return results + } + + trie := buildTrie(words) + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + dfs(board, i, j, trie, &results) + } + } + + return results +} + +type Trie struct { + next [26]*Trie + word string +} + +func buildTrie(words []string) *Trie { + root := new(Trie) + for _, word := range words { + cur := root + for _, c := range word { + idx := c - 'a' + if cur.next[idx] == nil { + cur.next[idx] = new(Trie) + } + cur = cur.next[idx] + } + cur.word = word + } + return root +} + +func dfs(board [][]byte, i, j int, trie *Trie, results *[]string) { + // termination + c := board[i][j] + if c == '#' || trie.next[c-'a'] == nil { + return + } + + // process logic of current level + trie = trie.next[c-'a'] + if trie.word != "" { + *results = append(*results, trie.word) + trie.word = "" + } + board[i][j] = '#' + + // drill down + if i > 0 { + dfs(board, i-1, j, trie, results) + } + + if i < len(board)-1 { + dfs(board, i+1, j, trie, results) + } + + if j > 0 { + dfs(board, i, j-1, trie, results) + } + + if j < len(board[0])-1 { + dfs(board, i, j+1, trie, results) + } + + // restore + board[i][j] = c +} diff --git a/Week 06/id_016/LeetCode_208_016.js b/Week 06/id_016/LeetCode_208_016.js new file mode 100644 index 000000000..23eba2bfe --- /dev/null +++ b/Week 06/id_016/LeetCode_208_016.js @@ -0,0 +1,120 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-11-19 22:30:26 + * @LastEditTime: 2019-11-22 10:19:09 + */ +/* + * @lc app=leetcode id=208 lang=javascript + * + * [208] Implement Trie (Prefix Tree) + * + * https://leetcode.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (41.09%) + * Likes: 2046 + * Dislikes: 36 + * Total Accepted: 218.5K + * Total Submissions: 520K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * Implement a trie with insert, search, and startsWith methods. + * + * Example: + * + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // returns true + * trie.search("app"); // returns false + * trie.startsWith("app"); // returns true + * trie.insert("app"); + * trie.search("app"); // returns true + * + * + * Note: + * + * + * You may assume that all inputs are consist of lowercase letters a-z. + * All inputs are guaranteed to be non-empty strings. + * + * + */ + +// @lc code=start +// 时间复杂度 O(n) +/** + * Initialize your data structure here. + */ +var Trie = function() { + this.isWord = false; + this.next = {}; +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + let cur = this; + for (let i = 0; i < word.length; i++) { + if (!cur.next[word[i]]) { + cur.next[word[i]] = new Trie(); + } + cur = cur.next[word[i]]; + } + cur.isWord = true; +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let cur = this; + for (let i = 0; i < word.length; i++) { + if (!cur.next.hasOwnProperty(word[i])) { + return false; + } + cur = cur.next[word[i]]; + } + return cur.isWord; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + let cur = this; + for (let i = 0; i < prefix.length; i++) { + if (!cur.next.hasOwnProperty(prefix[i])) { + return false; + } + cur = cur.next[prefix[i]]; + } + return true; +}; + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ +// @lc code=end + +let trie = new Trie(); + +trie.insert("apple"); +console.log(trie); +console.log(trie.search("appl")); +console.log(trie.search("apple")); +console.log(trie.startsWith("app")); diff --git a/Week 06/id_016/LeetCode_212_016.js b/Week 06/id_016/LeetCode_212_016.js new file mode 100644 index 000000000..927da0da9 --- /dev/null +++ b/Week 06/id_016/LeetCode_212_016.js @@ -0,0 +1,136 @@ +/* + * @lc app=leetcode id=212 lang=javascript + * + * [212] Word Search II + * + * https://leetcode.com/problems/word-search-ii/description/ + * + * algorithms + * Hard (30.35%) + * Likes: 1558 + * Dislikes: 84 + * Total Accepted: 145.5K + * Total Submissions: 469.8K + * Testcase Example: '[["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]]\n["oath","pea","eat","rain"]' + * + * Given a 2D board and a list of words from the dictionary, find all words in + * the board. + * + * Each word must be constructed from letters of sequentially adjacent cell, + * where "adjacent" cells are those horizontally or vertically neighboring. The + * same letter cell may not be used more than once in a word. + * + * + * + * Example: + * + * + * Input: + * board = [ + * ⁠ ['o','a','a','n'], + * ⁠ ['e','t','a','e'], + * ⁠ ['i','h','k','r'], + * ⁠ ['i','f','l','v'] + * ] + * words = ["oath","pea","eat","rain"] + * + * Output: ["eat","oath"] + * + * + * + * + * Note: + * + * + * All inputs are consist of lowercase letters a-z. + * The values of words are distinct. + * + * + */ + +// @lc code=start +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +var findWords = function(board, words) { + // 时间复杂度 O(n) + var Trie = function(){ + this.next = {}; + this.isEnd = false; + } + Trie.prototype.insert = function(word){ + let cur = this; + for(let i = 0; i < word.length; i++){ + if(!cur.next[word[i]]){ + cur.next[word[i]] = new Trie(); + } + cur = cur.next[word[i]]; + } + cur.isEnd = true; + } + Trie.prototype.search = function(word){ + let cur = this; + for(let i = 0; i < word.length; i++){ + if(!cur.next[word[i]]){ + return false + } + cur = cur.next[word[i]]; + } + return cur.isEnd; + } + Trie.prototype.startWith = function(word){ + let cur = this; + for(let i = 0; i < word.length; i++){ + if(!cur.next[word[i]]){ + return false + } + cur = cur.next[word[i]]; + } + return true; + } + + + + let m = board.length; + let n = board[0].length; + let res = []; + // 构建trie树 + let trie = new Trie(); + words.forEach(item=>{ + trie.insert(item); + }) + + // 深度优先遍历 + let dfs = (i, j, str, node) => { + // terminator + if(node && node.isEnd){ + res.push(str); + node.isEnd = false + } + if(i<0||j<0||i>=m||j>=n || !node){ + return; + } + // process + let temp = board[i][j]; + str+=temp; + board[i][j] = "#"; + // drill down + dfs(i-1,j,str,node.next[temp]); + dfs(i,j-1,str,node.next[temp]); + dfs(i+1,j,str,node.next[temp]); + dfs(i,j+1,str,node.next[temp]); + // 回溯 + board[i][j] = temp; + } + // 时间 O(m*n) + for(let i = 0; i < m; i++){ + for(let j = 0; j < n; j++){ + dfs(i,j,"",trie); + } + } + return res; +}; +// @lc code=end + diff --git a/Week 06/id_016/LeetCode_36_016.js b/Week 06/id_016/LeetCode_36_016.js new file mode 100644 index 000000000..d1fecb9b6 --- /dev/null +++ b/Week 06/id_016/LeetCode_36_016.js @@ -0,0 +1,122 @@ +/* + * @lc app=leetcode id=36 lang=javascript + * + * [36] Valid Sudoku + * + * https://leetcode.com/problems/valid-sudoku/description/ + * + * algorithms + * Medium (45.03%) + * Likes: 1130 + * Dislikes: 382 + * Total Accepted: 287.2K + * Total Submissions: 629.8K + * Testcase Example: '[["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]' + * + * Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be + * validated according to the following rules: + * + * + * Each row must contain the digits 1-9 without repetition. + * Each column must contain the digits 1-9 without repetition. + * Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without + * repetition. + * + * + * + * A partially filled sudoku which is valid. + * + * The Sudoku board could be partially filled, where empty cells are filled + * with the character '.'. + * + * Example 1: + * + * + * Input: + * [ + * ⁠ ["5","3",".",".","7",".",".",".","."], + * ⁠ ["6",".",".","1","9","5",".",".","."], + * ⁠ [".","9","8",".",".",".",".","6","."], + * ⁠ ["8",".",".",".","6",".",".",".","3"], + * ⁠ ["4",".",".","8",".","3",".",".","1"], + * ⁠ ["7",".",".",".","2",".",".",".","6"], + * ⁠ [".","6",".",".",".",".","2","8","."], + * ⁠ [".",".",".","4","1","9",".",".","5"], + * ⁠ [".",".",".",".","8",".",".","7","9"] + * ] + * Output: true + * + * + * Example 2: + * + * + * Input: + * [ + * ["8","3",".",".","7",".",".",".","."], + * ["6",".",".","1","9","5",".",".","."], + * [".","9","8",".",".",".",".","6","."], + * ["8",".",".",".","6",".",".",".","3"], + * ["4",".",".","8",".","3",".",".","1"], + * ["7",".",".",".","2",".",".",".","6"], + * [".","6",".",".",".",".","2","8","."], + * [".",".",".","4","1","9",".",".","5"], + * [".",".",".",".","8",".",".","7","9"] + * ] + * Output: false + * Explanation: Same as Example 1, except with the 5 in the top left corner + * being + * ⁠ modified to 8. Since there are two 8's in the top left 3x3 sub-box, it + * is invalid. + * + * + * Note: + * + * + * A Sudoku board (partially filled) could be valid but is not necessarily + * solvable. + * Only the filled cells need to be validated according to the mentioned + * rules. + * The given board contain only digits 1-9 and the character '.'. + * The given board size is always 9x9. + * + * + */ + +// @lc code=start +/** + * @param {character[][]} board + * @return {boolean} + */ +var isValidSudoku = function(board) { + let len = board.length; + let row = []; + let col = []; + let box = []; + for (let i = 0; i < len; i++) { + row[i] = []; + col[i] = []; + box[i] = []; + } + + for (let i = 0; i < len; i++) { + for (let j = 0; j < len; j++) { + let cur = board[i][j]; + if (cur === ".") continue; + let boxIndex = parseInt(i / 3) * 3 + parseInt(j / 3); + if ( + row[i].indexOf(cur) === -1 && + col[j].indexOf(cur) === -1 && + box[boxIndex].indexOf(cur) === -1 + ) { + row[i].push(cur); + col[j].push(cur); + box[boxIndex].push(cur); + continue; + } else { + return false; + } + } + } + return true; +}; +// @lc code=end diff --git a/Week 06/id_016/LeetCode_547_016.js b/Week 06/id_016/LeetCode_547_016.js new file mode 100644 index 000000000..b1282dbe8 --- /dev/null +++ b/Week 06/id_016/LeetCode_547_016.js @@ -0,0 +1,125 @@ +/* + * @lc app=leetcode id=547 lang=javascript + * + * [547] Friend Circles + * + * https://leetcode.com/problems/friend-circles/description/ + * + * algorithms + * Medium (55.38%) + * Likes: 1330 + * Dislikes: 105 + * Total Accepted: 117.3K + * Total Submissions: 209.8K + * Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' + * + * + * There are N students in a class. Some of them are friends, while some are + * not. Their friendship is transitive in nature. For example, if A is a direct + * friend of B, and B is a direct friend of C, then A is an indirect friend of + * C. And we defined a friend circle is a group of students who are direct or + * indirect friends. + * + * + * + * Given a N*N matrix M representing the friend relationship between students + * in the class. If M[i][j] = 1, then the ith and jth students are direct + * friends with each other, otherwise not. And you have to output the total + * number of friend circles among all the students. + * + * + * Example 1: + * + * Input: + * [[1,1,0], + * ⁠[1,1,0], + * ⁠[0,0,1]] + * Output: 2 + * Explanation:The 0th and 1st students are direct friends, so they are in a + * friend circle. The 2nd student himself is in a friend circle. So return + * 2. + * + * + * + * Example 2: + * + * Input: + * [[1,1,0], + * ⁠[1,1,1], + * ⁠[0,1,1]] + * Output: 1 + * Explanation:The 0th and 1st students are direct friends, the 1st and 2nd + * students are direct friends, so the 0th and 2nd students are indirect + * friends. All of them are in the same friend circle, so return 1. + * + * + * + * + * Note: + * + * N is in range [1,200]. + * M[i][i] = 1 for all students. + * If M[i][j] = 1, then M[j][i] = 1. + * + * + */ + +// @lc code=start +/** + * @param {number[][]} M + * @return {number} + 本质上是使用数组存储当前的所有值和引用 + */ +var findCircleNum = function(M) { + let count = M.length; + let n = M.length; + let p = []; + + // 初始化数组 + let init = n => { + for (let i = 0; i < n; i++) { + p[i] = i; + } + }; + + // 查找某个父节点 + let find = index => { + while (index !== p[index]) { + p[index] = p[p[index]]; + index = p[index]; + } + return index; + }; + + // 合并并查集 + let union = (index1, index2) => { + let root1 = find(index1); + let root2 = find(index2); + if (root1 === root2) return; + p[root1] = root2; + count--; + }; + + // 初始化并查集 + init(n); + + // 遍历二维数组,合并关联集 + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (M[i][j] === 1) { + union(i, j); + } + } + } + + return count; +}; +// @lc code=end + +console.log( + findCircleNum([ + [1, 1, 0], + [1, 1, 1], + [0, 1, 1] + ]) +); \ No newline at end of file diff --git a/Week 06/id_016/NOTE.md b/Week 06/id_016/NOTE.md index a6321d6e2..6dcbd9dfb 100644 --- a/Week 06/id_016/NOTE.md +++ b/Week 06/id_016/NOTE.md @@ -1,4 +1,152 @@ # NOTE +一、并查集 +1. 情景 +组团、配对问题 - +(微信朋友圈好友) +2. 基本操作 +makeSet(s):建立一个新的并查集,其中包含s个单元素集合 + +unionSet(x,y):把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交不合并 + +find(x):找到元素x所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将他们各自的代表比较以下就可以了 + + + +二、高级搜索 +1.剪枝 +状态树是树和分支的形态 + +2.回溯 +回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是几步的计算,再通过其它可能的分步解答再次寻找问题的答案。 + +回溯法通常采用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: + +找到一个可能存在的正确的答案 +在尝试了所有可能的分步方法后宣告该问题没有答案 +在最坏的情况下,回溯法会导致一次复杂度为指数级时间的计算。 + +3.双向BFS +和单向BFS异曲同工 +用set来表示 + +4.启发式搜索 +根据某一项条件,优化搜索方向 +通过优先级 + +三、平衡二叉树 +AVL树 +红黑树 +B树 +23树 +1.AVL树 +为什么需要出现AVL树:极端情况下,树变成链表,查询效率变成logn +平衡二叉树 + +Balance Factor(平衡因子)任何结点它左子树的高度减去它的右子树的高度(有时相反):{0,1-1} +通过旋转操作 +左旋 +右旋 +左右旋 +右左旋 +不足: +结点需要存储额外信息,且调整频次频繁 + +2.红黑树 +近似平衡二叉树(Binary Search Tree),它能够确保任何一个结点的左右子树的高度小于两倍。具体来说,红黑树是满足于如下条件的二叉搜索树 + +每个结点要么是红色,要么是黑色 +根结点是黑色 +每个结点(NIL结点,空结点)是黑色 +不能有相邻接的两个红色结点 +从任一结点到其每个叶子结点的所有路径都包含相同数目的黑色结点 +时间复杂度logn,调整时间相对比较小 + + +Trie模版 + +```javascript +var Trie = function() { + this.isWord = false; + this.next = {}; +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + let cur = this; + for (let i = 0; i < word.length; i++) { + if (!cur.next[word[i]]) { + cur.next[word[i]] = new Trie(); + } + cur = cur.next[word[i]]; + } + cur.isWord = true; +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let cur = this; + for (let i = 0; i < word.length; i++) { + if (!cur.next.hasOwnProperty(word[i])) { + return false; + } + cur = cur.next[word[i]]; + } + return cur.isWord; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + let cur = this; + for (let i = 0; i < prefix.length; i++) { + if (!cur.next.hasOwnProperty(prefix[i])) { + return false; + } + cur = cur.next[prefix[i]]; + } + return true; +}; + +``` + +并查集示例 +```javascript + let p = []; + // 初始化数组 + let init = n => { + for (let i = 0; i < n; i++) { + p[i] = i; + } + }; + + // 查找某个父节点 + let find = index => { + while (index !== p[index]) { + p[index] = p[p[index]]; + index = p[index]; + } + return index; + }; + + // 合并并查集 + let union = (index1, index2) => { + let root1 = find(index1); + let root2 = find(index2); + if (root1 === root2) return; + p[root1] = root2; + count--; + }; +``` \ No newline at end of file diff --git a/Week 06/id_021/algorithm.zip b/Week 06/id_021/algorithm.zip new file mode 100644 index 000000000..4d96a0c18 Binary files /dev/null and b/Week 06/id_021/algorithm.zip differ diff --git a/Week 06/id_026/LeetCode_208_026.java b/Week 06/id_026/LeetCode_208_026.java new file mode 100644 index 000000000..7dcda26ef --- /dev/null +++ b/Week 06/id_026/LeetCode_208_026.java @@ -0,0 +1,67 @@ +class Trie { + public boolean isWord; + public char word; + public Trie[] tries = new Trie[26]; + + public Trie() { + this.isWord =false; + this.word=' '; + + } + + public void insert(String word) { + char [] array = word.toCharArray(); + Trie node=this; + for(int i=0;iarray.length;i++){ + if(node.tries[array[i]-'a']==null){ + node.tries[array[i]-'a']=new Trie(); + } + node=node.tries[array[i]-'a']; + node.word=array[i]; + if(i==array.length-1){ + node.isWord=true; + } + } + + } + + public boolean search(String word) { + char [] array =word.toCharArray(); + Trie node =this; + for(int i=0;iarray.length;i++){ + if(node.tries[array[i]-'a']!=null){ + node =node.tries[array[i]-'a']; + if(node.word ==array[i]) + continue; + else + return false; + }else + return false; + + } + return node.isWord==truetruefalse; + + + + + } + + public boolean startsWith(String prefix) { + char [] array =prefix.toCharArray(); + Trie node =this; + for(int i=0;iarray.length;i++){ + if(node.tries[array[i]-'a']!=null){ + node =node.tries[array[i]-'a']; + if(node.word ==array[i]) + continue; + else + return false; + } + else + return false; + + } + return true; + } +} + \ No newline at end of file diff --git a/Week 06/id_026/LeetCode_547_026.java b/Week 06/id_026/LeetCode_547_026.java new file mode 100644 index 000000000..afdeda238 --- /dev/null +++ b/Week 06/id_026/LeetCode_547_026.java @@ -0,0 +1,31 @@ +class FindCircleNum { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_041/LeetCode_208_041.java b/Week 06/id_041/LeetCode_208_041.java new file mode 100644 index 000000000..d843fc5f7 --- /dev/null +++ b/Week 06/id_041/LeetCode_208_041.java @@ -0,0 +1,83 @@ +package LeetCode_208_041; + +class Trie { + public boolean isWord; + public char word; + public Trie[] tries = new Trie[26]; + + /** + * Initialize your data structure here. + */ + public Trie() { + this.word = ' '; + this.isWord = false; + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] == null) { + node.tries[array[i] - 'a'] = new Trie(); + } + node = node.tries[array[i] - 'a']; + node.word = array[i]; + if (i == array.length - 1) {//当i 等于字符长度时说明单词插入完毕,将isWord赋为true + node.isWord = true; + } + + } + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) { + continue; + } else { + return false; + } + } else { + return false; + } + } + return node.isWord; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + char[] array = prefix.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) { + continue; + } else { + return false; + } + } else { + return false; + } + } + return true; + } +} +/** + * 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); + */ diff --git a/Week 06/id_041/LeetCode_36_041.java b/Week 06/id_041/LeetCode_36_041.java new file mode 100644 index 000000000..e57779d7f --- /dev/null +++ b/Week 06/id_041/LeetCode_36_041.java @@ -0,0 +1,20 @@ +package LeetCode_36_041; + +import java.util.HashSet; +import java.util.Set; + +class Solution { + public boolean isValidSudoku(char[][] board) { + Set set =new HashSet(); + for (int i = 0; i < 9; i++){ + for(int j = 0; j < 9;j++){ + char number = board[i][j]; + if(number != '.'){ + if(!set.add(number + "in cow" + i) || !set.add(number+ "in column "+ j) + || !set.add(number + "in block "+ i/3 + "-" + j/3)) return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_046/LeetCode_208_046.java b/Week 06/id_046/LeetCode_208_046.java new file mode 100644 index 000000000..6a6f933f4 --- /dev/null +++ b/Week 06/id_046/LeetCode_208_046.java @@ -0,0 +1,65 @@ +class TrieNode{ + boolean isEnd; + TrieNode child[]; + + public TrieNode(){ + isEnd = false; + child = new TrieNode[26]; + } +} +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 node = root; + for (int i = 0; i < word.length(); i++) { + char cur = word.charAt(i); + if (node.child[cur-'a'] == null) { + node.child[cur-'a'] = new TrieNode(); + } + node = node.child[cur-'a']; + } + node.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char cur = word.charAt(i); + if (node.child[cur-'a'] == null) { + return false; + } + node = node.child[cur-'a']; + } + return node.isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = root; + for (int i = 0; i < prefix.length(); i++) { + char cur = prefix.charAt(i); + if (node.child[cur-'a'] == null) { + return false; + } + node = node.child[cur-'a']; + } + return true; + } +} + +/** + * 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/Week 06/id_046/LeetCode_36_046.java b/Week 06/id_046/LeetCode_36_046.java new file mode 100644 index 000000000..01926e3c5 --- /dev/null +++ b/Week 06/id_046/LeetCode_36_046.java @@ -0,0 +1,19 @@ +class Solution { + + public boolean isValidSudoku(char[][] board) { + // 国际站学习到的解法:利用了set中没有重复元素这一特性 + Set seen = new HashSet(); + + for (int i=0; i<9; ++i) { + for (int j=0; j<9; ++j) { + char number = board[i][j]; + if (number != '.') + if (!seen.add(number + " in row " + i) || + !seen.add(number + " in column " + j) || + !seen.add(number + " in block " + i/3 + "-" + j/3)) + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_071/LeetCode_051_071.go b/Week 06/id_071/LeetCode_051_071.go new file mode 100644 index 000000000..7ef23ce41 --- /dev/null +++ b/Week 06/id_071/LeetCode_051_071.go @@ -0,0 +1,45 @@ +package week06 + +//3.1 https://leetcode-cn.com/problems/n-queens/ +func solveNQueens(n int) [][]string { + var res [][]string + doSolve(&res,n,[]int{}) + return res +} + +func doSolve(res *[][]string, n int, path []int) { + if len(path) == n { + var queenPrint []string + for _, q := range path { + var line bytes.Buffer + i := 1 + for i < q { + line.WriteString(".") + i++ + } + line.WriteString("Q") + i = q + 1 + for i <= n { + line.WriteString(".") + i++ + } + queenPrint = append(queenPrint,line.String()) + } + *res = append(*res, queenPrint) + return + } + + var queenX = len(path) + 1 + OUTLOOP: + for queenY := 1; queenY <= n; queenY++ { + for i, existQueenY := range path { + existQueenX := i + 1 + if existQueenX + existQueenY = queenY + queenX || existQueenY == queenY || existQueenX - existQueenY == queenX - queenY { + continue OUTLOOP + } + } + path = append(path,queenY) + doSolve(res,n,path) + path = path[:len(path) - 1] + } +} \ No newline at end of file diff --git a/Week 06/id_071/LeetCode_079_071.go b/Week 06/id_071/LeetCode_079_071.go new file mode 100644 index 000000000..4c2484fee --- /dev/null +++ b/Week 06/id_071/LeetCode_079_071.go @@ -0,0 +1,36 @@ +package week06 + +// 1.2 https://leetcode-cn.com/problems/word-search/ +// dfs +func exist(board [][]byte, word string) bool { + if len(board) == 0 { + return false + } + + for i := 0; i < len(board); i++ { + for j := 0; j < len(board[0]); j++ { + if dfs(board, i, j, word, 0){ + return true + } + } + } + return false +} + +func dfs(board [][]byte, i, j int, word string, index int) bool { + if index == len(word) { + return true + } + + if i >= len(board) || i < 0 || j >= len(board[0]) || j < 0 || word[index] != board[i][j] { + return false + } + + temp := board[i][j] + board[i][j] = '%' + + a := dfs(board, i+1, j, word, index+1) || dfs(board, i, j+1, word, index+1) || dfs(board, i-1, j, word, index+1) || dfs(board, i, j-1, word, index+1) + board[i][j] = temp + + return a +} \ No newline at end of file diff --git a/Week 06/id_071/LeetCode_127_071.go b/Week 06/id_071/LeetCode_127_071.go new file mode 100644 index 000000000..8a5d3a9d8 --- /dev/null +++ b/Week 06/id_071/LeetCode_127_071.go @@ -0,0 +1,58 @@ +package week06 + +//3.2 https://leetcode-cn.com/problems/word-ladder/ +func ladderLength(beginWord string, endWord string, wordList []string) int { + wordMap := getWordMap(wordList, beginWord) + que := []string{beginWord} + depth := 0 + for len(que) > 0 { + depth++ + + qlen := len(que) + for i := 0; i < qlen; i++ { + word := que[0] + que = que[1:] + + candidates := getCandidates(word) + for _, candidate := range candidates { + if _, ok := wordMap[candidate]; ok { + if candidate == endWord { + return depth + 1 + } + + delete(wordMap, candidate) + que = append(que, candidate) + } + } + } + } + return 0 +} + +func getWordMap (wordList []string, beginWord string) map[string]int{ + + wordMap := make(map[string]int) + for i, word := range wordList { + if _, ok := wordMap[word]; !ok { + if word != beginWord { + wordMap[word] = i + } + } + } + + return wordMap +} + +func getCandidates(word string) []string { + + var res []string + for i := 0; i < 26; i++ { + for j := 0; j < len(word); j++ { + if word[j] != byte(int('a')+i) { + res = append(res, word[ :j] + string(int('a') + i) + word[j+1: ]) + } + } + } + + return res +} \ No newline at end of file diff --git a/Week 06/id_071/LeetCode_200_071.go b/Week 06/id_071/LeetCode_200_071.go new file mode 100644 index 000000000..89acc9444 --- /dev/null +++ b/Week 06/id_071/LeetCode_200_071.go @@ -0,0 +1,50 @@ +package week06 + +//2.1 https://leetcode-cn.com/problems/number-of-islands/ +func numIslands(grid [][]byte) int { + mlen := len(grid) + if mlen == 0 { + return 0 + } + + nlen := len(grid[0]) + + res, visited := 0, newVisited(mlen, nlen) + for i := 0; i < mlen; i++ { + for j := 0; j < nlen; j++ { + if grid[i][j] == '1' && visited[i][j] == 0 { + res++ + fill(grid, visited, i, j, mlen, nlen) + } + } + } + return res +} + +func fill( grid [][]byte, visited [][]int, i, j int, mlen, nlen int){ + visited[i][j] = 1 + if i-1 >= 0 && grid[i-1][j] == '1' && visited[i-1][j] == 0 { + fill(grid, visited, i-1, j, mlen, nlen) + } + + if i+1 >= 0 && grid[i+1][j] == '1' && visited[i+1][j] == 0 { + fill(grid, visited, i+1, j, mlen, nlen) + } + + if j-1 >= 0 && grid[i][j-1] == '1' && visited[i][j-1] == 0 { + fill(grid, visited, i, j-1, mlen, nlen) + } + + if j+1 >= 0 && grid[i][j+1] == '1' && visited[i][j+1] == 0 { + fill(grid, visited, i, j+1, mlen, nlen) + } +} + +func newVisited(m, n int ) [][]int { + v := make([][]int, m) + for i := 0; i < m; i++ { + v[i] = make([]int, n) + } + return v +} + diff --git a/Week 06/id_071/LeetCode_208_071.go b/Week 06/id_071/LeetCode_208_071.go new file mode 100644 index 000000000..422da5b9b --- /dev/null +++ b/Week 06/id_071/LeetCode_208_071.go @@ -0,0 +1,68 @@ +package week06 + +//1.1 https://leetcode-cn.com/problems/implement-trie-prefix-tree/ +type Trie struct { + isEnd bool + children map[rune]*Trie +} + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{ + isEnd: false, + children: make(map[rune]*Trie), + } +} + + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + parent := this + for _, r := range word { + if child, ok := parent.children[r]; ok { + parent = child + }else{ + newChild := &Trie{isEnd: false,children:make(map[rune]*Trie)} + parent.children[r] = newChild + parent = newChild + } + } + parent.isEnd = true +} + + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + parent := this + for _, r := range word { + if child, ok := parent.children[r]; ok { + parent = child + continue + } + return false + } + return parent.isEnd +} + + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + parent := this + for _, r := range prefix { + if child, ok := parent.children[r]; ok { + parent = child + continue + } + return false + } + return true +} + + +/** + * Your Trie object will be instantiated and called as such: + * obj := Constructor(); + * obj.Insert(word); + * param_2 := obj.Search(word); + * param_3 := obj.StartsWith(prefix); + */ \ No newline at end of file diff --git a/Week 06/id_071/LeetCode_547_071.go b/Week 06/id_071/LeetCode_547_071.go new file mode 100644 index 000000000..8964dbcff --- /dev/null +++ b/Week 06/id_071/LeetCode_547_071.go @@ -0,0 +1,48 @@ +package week06 + +//2.2 https://leetcode-cn.com/problems/friend-circles/ + +func findCircleNum(M [][]int) int { + if len(M) <= 1 { + return len(M) + } + + count := 0 + visited := make([]bool,len(M)) + for i, _ := range M { + if visited[i] == false { + BFS(M, visited, i) + count++ + } + } + + return count +} + +func dfs(M [][]int, visited []bool, c int){ + for j := 0; j < len(M); j++ { + if M[c][j] == 1 && visited[j] == false { + visited[j] = true + dfs(M, visited, j) + } + } +} + + +func BFS(M [][]int, visited []bool, c int){ + new := make([]int, 0) + new = append(new, c) + visited[c] = true + + for len(new) > 0 { + c = new[0] + new = new[1:] + + for i := 0; i < len(M); i++ { + if M[c][i] == 1 && visited[i] == false{ + visited[i] = true + new = append(new, i) + } + } + } +} \ No newline at end of file diff --git a/Week 06/id_071/NOTE.md b/Week 06/id_071/NOTE.md index a6321d6e2..ad5d3851a 100644 --- a/Week 06/id_071/NOTE.md +++ b/Week 06/id_071/NOTE.md @@ -1,4 +1,109 @@ # NOTE - +> Trie & UnionFind + +##### Trie 单词查找树 或 键树 树形结构 空间换时间 + + 典型应用是用于统计和排序大量的字符串,用于文本词频统计 + 优点是:最大限度的减少无谓的字符串比较,查询效率比哈希表高 + + +``` +graph TD +/-->|B| B +/-->|S| S +B-->|C|BC +B-->|D|BD +BC-->|E|BCE +BD-->|F|BDF +S-->|H|SH +S-->|E|SE +SH-->|E|SHE +``` + + + 二叉树的层次遍历 dfs bfs(水波纹) + 二叉搜索树 子树的关系 升序序列 + +##### Unionfind disjoint set + + makeSet(s) + + unionSet(x,y) + + find(x) + +**** + + +> Search + +##### 初级搜索 + + 1. 朴素搜索 + 2. 优化方式 不重复(fabonacci) 剪枝(生成括号问题) + 3. 搜索方向 + + DFS(depth) 递归 / 先入先出的 栈 + BFS(breadth) 先入后出的 队列 + +##### 高级搜索 + + 剪枝 + 爬楼梯 => fib + 括号生成 (DP) + + + 双向搜索 + + + 启发式搜索 A*算法 优先队列 + + + +**** + +> AVL Tree & Red black Tree + + Tree + Binary search Tree + AVL tree + Red black tree + B+ tree + +##### 保证性能 + + 保证二维维度 => 左右子树结点平衡 + 平衡二叉树 balanced + +##### AVL Tree 平衡二叉搜索树 + + 引入平衡因子( 左子树的高度 减去 它的右子树的高度 ) balance factor = {-1, 0, 1} + 通过旋转操作 + 左旋 + 右旋 + 左右旋 + 右左旋 + + 不足:结点需要存储额外信息,且调整次数频繁 + +##### Red Black Tree 近似平衡的二叉搜索树 + + 确保任何一个结点的 左右子树的高度差 小于 两倍 + + + 1.每个结点要么红色,要么黑色 + 2.根节点是黑色 + 3.每个叶结点(nil结点 空结点) 是黑色的 + 4.不能有相邻的两个红色结点 + 5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点 + + + +对比 | AVL Tree | Red Black Tree +---|---|--- +lookups | faster | +insert | | faster +removal | | faster + diff --git a/Week 06/id_071/UnionFind.go b/Week 06/id_071/UnionFind.go new file mode 100644 index 000000000..e020bc54e --- /dev/null +++ b/Week 06/id_071/UnionFind.go @@ -0,0 +1,30 @@ +package week06 + +type UnionFind struct { + count int + parent []int +} + +func (this *UnionFind) UnionFind(n int) { + this.count = n + for i := 0; i < n; i++ { + this.parent = append(this.parent, i) + } +} + +func (this *UnionFind) find (p int) int { + for p != this.parent[p] { + this.parent[p] = this.parent[this.parent[p]] + p = this.parent[p] + } + return p +} + +func (this *UnionFind) union(p, q int){ + rootp := this.find(p) + rootq := this.find(q) + if rootp != rootq { + this.parent[rootp] = rootq + this.count-- + } +} diff --git a/Week 06/id_076/LeetCode_32_076.java b/Week 06/id_076/LeetCode_32_076.java new file mode 100644 index 000000000..0ffcf2d00 --- /dev/null +++ b/Week 06/id_076/LeetCode_32_076.java @@ -0,0 +1,37 @@ +package week05; + +/** + * + * 最长有效括号 + * + * dp[i]=dp[i−2]+2 + * dp[i]=dp[i−1]+dp[i−dp[i−1]−2]+2 + * + * 复杂度分析 + * 时间复杂度: O(n)O(n) 。遍历整个字符串一次,就可以将 dpdp 数组求出来。 + * 空间复杂度: O(n)O(n) 。需要一个大小为 nn 的 dpdp 数组。 + * + * @author tangzhenhua + * @date 2019/11/17 21:12 + */ +public class LeetCode_32_076 { + + + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } + + +} diff --git a/Week 06/id_076/LeetCode_64_076.java b/Week 06/id_076/LeetCode_64_076.java new file mode 100644 index 000000000..d6e56aafa --- /dev/null +++ b/Week 06/id_076/LeetCode_64_076.java @@ -0,0 +1,50 @@ +package week05; + +/** + * 动态规划 采用二维数组 + * + * 复杂度分析 + * 时间复杂度 :O(mn)O(mn)。遍历整个矩阵恰好一次。 + * 空间复杂度 :O(mn)O(mn)。额外的一个同大小矩阵。 + * @author tangzhenhua + * @date 2019/11/17 20:51 + */ +public class LeetCode_64_076 { + + + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + + public static void main(String[] args) { + int[][] grid = new int[3][3]; + grid[0][0] = 1; + grid[0][1] = 3; + grid[0][2] = 1; + + grid[1][0] = 1; + grid[1][1] = 5; + grid[1][2] = 1; + + grid[2][0] = 4; + grid[2][1] = 2; + grid[2][2] = 1; + + LeetCode_64_076 leet = new LeetCode_64_076(); + int min = leet.minPathSum(grid); + System.out.println(min); + } +} diff --git a/Week 06/id_076/NOTE.md b/Week 06/id_076/NOTE.md index a6321d6e2..e93991d3f 100644 --- a/Week 06/id_076/NOTE.md +++ b/Week 06/id_076/NOTE.md @@ -1,4 +1,16 @@ -# NOTE - - - +# NOTE + +第5周 动态规划 + +1.最优子结构 +2.存储中间状态 +3.递推公式(状态转移方程,DP方程) +fib:opt[n] = opt[n-1] + opt[n-2] +二维路径:opt[i, j] = opt[i+1, j] + opt[i, j+1](可能需要判断 a[i, j] 是否能走) + +4.递归、分治、回溯、动态规划 都是找到问题的共性,将一个问题拆分为子问题,进而求解 + 递归:要注意重复问题,可以增加 子问题cache去除重复计算。 + 分治:将一个大问题,拆分几个子问题,每个子问题继续进行递归拆分。最终将结果合并。 + 动态规划:分治 + 最优子结构,淘汰次优结构。 + +5.二维动态规划算是入门,复杂点的问题都是三维四维。 \ No newline at end of file diff --git a/Week 06/id_081/NQueens.java b/Week 06/id_081/NQueens.java new file mode 100644 index 000000000..c30a79f38 --- /dev/null +++ b/Week 06/id_081/NQueens.java @@ -0,0 +1,60 @@ +public class NQueens { + int n; + Set cols; + Set pies; + Set nas; + List> res; + + LinkedList queue; + + /** + * 在的思路是剪枝 + */ + public List> solveNQueens(int n) { + if (n == 0) return new ArrayList<>(); + + this.n = n; + nas = new HashSet<>(); + cols = new HashSet<>(); + pies = new HashSet<>(); + queue = new LinkedList<>(); + res = new ArrayList<>(); + _solveNQueue(0); + return res; + } + + public void _solveNQueue(int row) { + if (row >= n) { + res.add(generateList(new LinkedList<>(queue), n)); + return; + } + + for (int col = 0; col < n; ++col) { + if (cols.contains(col) || pies.contains(row + col) || nas.contains(row - col)) + continue; + cols.add(col); + pies.add(row + col); + nas.add(row - col); + queue.addLast(col); + + _solveNQueue(row + 1); + + queue.removeLast(); + cols.remove(col); + pies.remove(row + col); + nas.remove(row - col); + } + } + + public List generateList(Queue queue, int n) { + List board = new ArrayList<>(); + for (Integer integer : queue) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; ++i) + sb.append("."); + sb.replace(integer, integer + 1, "Q"); + board.add(sb.toString()); + } + return board; + } +} \ No newline at end of file diff --git a/Week 06/id_081/Tire.java b/Week 06/id_081/Tire.java new file mode 100644 index 000000000..73991e0d6 --- /dev/null +++ b/Week 06/id_081/Tire.java @@ -0,0 +1,69 @@ +class Trie { + private TreeNode root; + + public Trie() { + root = new TreeNode(); + } + + public void insert(String word) { + TreeNode node = root; + for(int i = 0; i < word.length(); ++i) { + if (!node.isContains(word.charAt(i))) + node.putTreeNode(word.charAt(i), new TreeNode()); + node = node.getTreeNode(word.charAt(i)); + } + node.setEnd(); +} + +public boolean search(String word) { + TreeNode node = root; + for(int i = 0; i < word.length(); ++i) { + if (node.getTreeNode(word.charAt(i)) == null) + return false; + node = node.getTreeNode(word.charAt(i)); + } + return node.isEnd(); +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +public boolean startsWith(String prefix) { + TreeNode node = root; + for(int i = 0; i < prefix.length(); ++i) { + if (node.getTreeNode(prefix.charAt(i)) == null) + return false; + node = node.getTreeNode(prefix.charAt(i)); + } + return true; +} +} + + +class TreeNode { + private TreeNode[] links; + private final int SIZE = 26; + private boolean isEnd; + + public TreeNode(){ + links = new TreeNode[SIZE]; + } + + public boolean isContains(char ch) { + return links[ch - 'a'] != null; + } + + public TreeNode getTreeNode(char ch) { + return links[ch - 'a']; + } + + public void putTreeNode(char ch, TreeNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd(){ + return isEnd; + } +} \ No newline at end of file diff --git a/Week 06/id_081/WordLadder.java b/Week 06/id_081/WordLadder.java new file mode 100644 index 000000000..126bd0e03 --- /dev/null +++ b/Week 06/id_081/WordLadder.java @@ -0,0 +1,52 @@ +/** + * WordLadder + */ +public class WordLadder { + + public int ladderLength(String beginWord, String endWord, List wordList) { + Set dic = new HashSet<>(wordList); + + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + + int count = 1; + Set visited = new HashSet<>(); + int strLength = beginWord.length(); + + if (dic.contains(endWord)) { + beginSet.add(beginWord); + endSet.add(endWord); + } + + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + if(beginSet.size() > endSet.size()){ + Set tempSet = beginSet; + beginSet = endSet; + endSet = tempSet; + } + Set temp = new HashSet<>(); + for (String word : beginSet) { + char[] chs = word.toCharArray(); + for(int i = 0; i < chs.length; ++i) { + for(char j = 'a'; j <= 'z'; ++j) { + char old = chs[i]; + chs[i] = j; + String target = String.valueOf(chs); + + if(endSet.contains(target)) + return count + 1; + + if(!visited.contains(target) && dic.contains(target)){ + visited.add(target); + temp.add(target); + } + chs[i] = old; + } + } + beginSet = temp; + } + count++; + } + return 0; + } +} \ No newline at end of file diff --git a/Week 06/id_086/LeetCode_200_086.java b/Week 06/id_086/LeetCode_200_086.java new file mode 100644 index 000000000..433db2f80 --- /dev/null +++ b/Week 06/id_086/LeetCode_200_086.java @@ -0,0 +1,47 @@ +/** + * LeetCode_200_086,广度优先 + */ +class Solution { + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + + for (int i = 0; i < nr; i++) { + for (int j = 0; j < nc; j++) { + if (grid[i][j] == '1') { + ++num_islands; + grid[i][j] = '0'; + Queue que = new LinkedList<>(); + que.add(i * nc + j); + while (!que.isEmpty()) { + int id = que.remove(); + int row = id / nc; + int col = id % nc; + if (row - 1 >= 0 && grid[row-1][col] == '1') { + que.add((row-1) * nc + col); + grid[row-1][col] = '0'; + } + if (row + 1 < nr && grid[row+1][col] == '1') { + que.add((row+1) * nc + col); + grid[row+1][col] = '0'; + } + if (col - 1 >= 0 && grid[row][col-1] == '1') { + que.add(row * nc + col-1); + grid[row][col-1] = '0'; + } + if (col + 1 < nc && grid[row][col+1] == '1') { + que.add(row * nc + col+1); + grid[row][col+1] = '0'; + } + } + } + } + } + return num_islands; + } +} diff --git a/Week 06/id_086/LeetCode_208_086.java b/Week 06/id_086/LeetCode_208_086.java new file mode 100644 index 000000000..20e3fa31b --- /dev/null +++ b/Week 06/id_086/LeetCode_208_086.java @@ -0,0 +1,66 @@ +class TrieNode { + TrieNode[] child; + boolean is_end; + public TrieNode() { + child = new TrieNode[26]; + is_end = false; + } + +} + +public class Trie { + + TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode ptr = root; + for (int i=0;i int: + q, n = [(0, 0, 2)], len(grid) + if grid[0][0] or grid[-1][-1]: + return -1 + elif n <= 2: + return n + for i, j, d in q: + for x, y in [(i - 1, j - 1), (i - 1, j), (i - 1, j + 1), (i, j - 1), (i, j + 1), (i + 1, j - 1), (i + 1, j), + (i + 1, j + 1)]: + if 0 <= x < n and 0 <= y < n and not grid[x][y]: + if x == n - 1 and y == n - 1: + return d + q += [(x, y, d + 1)] + grid[x][y] = 1 + return -1 diff --git a/Week 06/id_091/Leetcode_208_091.py b/Week 06/id_091/Leetcode_208_091.py new file mode 100644 index 000000000..496d0fc12 --- /dev/null +++ b/Week 06/id_091/Leetcode_208_091.py @@ -0,0 +1,32 @@ +class Trie: + + def __init__(self): + self.root = {} + self.end_of_word = "#" + + def insert(self, word): + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + + def search(self, word): + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix): + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week 06/id_091/Leetcode_37_091.py b/Week 06/id_091/Leetcode_37_091.py new file mode 100644 index 000000000..8e4917798 --- /dev/null +++ b/Week 06/id_091/Leetcode_37_091.py @@ -0,0 +1,39 @@ +from typing import List + + +class Solution: + + def solveSudoku(self, board: List[List[str]]) -> None: + row = [set(range(1, 10)) for _ in range(9)] # 行剩余可用数字 + col = [set(range(1, 10)) for _ in range(9)] # 列剩余可用数字 + block = [set(range(1, 10)) for _ in range(9)] # 块剩余可用数字 + + empty = [] # 收集需填数位置 + for i in range(9): + for j in range(9): + if board[i][j] != '.': # 更新可用数字 + val = int(board[i][j]) + row[i].remove(val) + col[j].remove(val) + block[(i // 3) * 3 + j // 3].remove(val) + else: + empty.append((i, j)) + + def backtrack(iter=0): + if iter == len(empty): # 处理完empty代表找到了答案 + return True + i, j = empty[iter] + b = (i // 3) * 3 + j // 3 + for val in row[i] & col[j] & block[b]: + row[i].remove(val) + col[j].remove(val) + block[b].remove(val) + board[i][j] = str(val) + if backtrack(iter + 1): + return True + row[i].add(val) # 回溯 + col[j].add(val) + block[b].add(val) + return False + + backtrack() diff --git a/Week 06/id_106/208.implement-trie-prefix-tree.java b/Week 06/id_106/208.implement-trie-prefix-tree.java new file mode 100644 index 000000000..cc23d1aa2 --- /dev/null +++ b/Week 06/id_106/208.implement-trie-prefix-tree.java @@ -0,0 +1,107 @@ +/* + * @lc app=leetcode id=208 lang=java + * + * [208] Implement Trie (Prefix Tree) + * + * https://leetcode.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (41.23%) + * Likes: 2057 + * Dislikes: 36 + * Total Accepted: 219.2K + * Total Submissions: 521.1K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * Implement a trie with insert, search, and startsWith methods. + * + * Example: + * + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // returns true + * trie.search("app"); // returns false + * trie.startsWith("app"); // returns true + * trie.insert("app"); + * trie.search("app"); // returns true + * + * + * Note: + * + * + * You may assume that all inputs are consist of lowercase letters a-z. + * All inputs are guaranteed to be non-empty strings. + * + * + */ + +// @lc code=start +class TrieNode { + public char val; + public boolean isWord; + public TrieNode[] children = new TrieNode[26]; + public TrieNode() {} + TrieNode(char c){ + TrieNode node = new TrieNode(); + node.val = c; + } +} +class Trie { + private TrieNode root; + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + root.val = ' '; + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode ws = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(ws.children[c - 'a'] == null){ + ws.children[c - 'a'] = new TrieNode(c); + } + ws = ws.children[c - 'a']; + } + ws.isWord = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode ws = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return ws.isWord; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode ws = root; + for(int i = 0; i < prefix.length(); i++){ + char c = prefix.charAt(i); + if(ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return true; + } +} + +/** + * 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); + */ +// @lc code=end +/** + * trie 每一层有26个子,共26层 代表所有字母 + * 其中char - 'a'代表 计算字符是26个字母之一 字符a的asciicode为97 null的asciicode是0 同时将字母的ascii转换位移到0-25的索引 + * + */ diff --git a/Week 06/id_106/212.word-search-ii.java b/Week 06/id_106/212.word-search-ii.java new file mode 100644 index 000000000..8a7dc0155 --- /dev/null +++ b/Week 06/id_106/212.word-search-ii.java @@ -0,0 +1,107 @@ +/* + * @lc app=leetcode id=212 lang=java + * + * [212] Word Search II + * + * https://leetcode.com/problems/word-search-ii/description/ + * + * algorithms + * Hard (30.42%) + * Likes: 1562 + * Dislikes: 84 + * Total Accepted: 145.7K + * Total Submissions: 470.3K + * Testcase Example: '[["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]]\n["oath","pea","eat","rain"]' + * + * Given a 2D board and a list of words from the dictionary, find all words in + * the board. + * + * Each word must be constructed from letters of sequentially adjacent cell, + * where "adjacent" cells are those horizontally or vertically neighboring. The + * same letter cell may not be used more than once in a word. + * + * + * + * Example: + * + * + * Input: + * board = [ + * ⁠ ['o','a','a','n'], + * ⁠ ['e','t','a','e'], + * ⁠ ['i','h','k','r'], + * ⁠ ['i','f','l','v'] + * ] + * words = ["oath","pea","eat","rain"] + * + * Output: ["eat","oath"] + * + * + * + * + * Note: + * + * + * All inputs are consist of lowercase letters a-z. + * The values of words are distinct. + * + * + */ + +// @lc code=start +class Solution { + public List findWords(char[][] board, String[] words) { + List res = new ArrayList<>(); + TrieNode root = buildTrie(words); + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + dfs (board, i, j, root, res); + } + } + return res; + } + public void dfs(char[][] board, int i, int j, TrieNode p, List res) { + char c = board[i][j]; + if (c == '#' || p.next[c - 'a'] == null) return; + p = p.next[c - 'a']; + if (p.word != null) { // found one + res.add(p.word); + p.word = null; // de-duplicate + } + + board[i][j] = '#'; + if (i > 0) dfs(board, i - 1, j ,p, res); + if (j > 0) dfs(board, i, j - 1, p, res); + if (i < board.length - 1) dfs(board, i + 1, j, p, res); + if (j < board[0].length - 1) dfs(board, i, j + 1, p, res); + board[i][j] = c; + } + + public TrieNode buildTrie(String[] words) { + TrieNode root = new TrieNode(); + for (String w : words) { + TrieNode p = root; + for (char c : w.toCharArray()) { + int i = c - 'a'; + if (p.next[i] == null) p.next[i] = new TrieNode(); + p = p.next[i]; + } + p.word = w; + } + return root; + } + + +} +class TrieNode { + TrieNode[] next = new TrieNode[26]; + String word; +} +// @lc code=end +/** + * 使用trie + * 1 使用trie 先将words构建成trie 前序的 + * 2 对board 使用DFS的方式去搜索 + * 3 分析时间复杂度 + * + */ diff --git a/Week 06/id_106/NOTE.md b/Week 06/id_106/NOTE.md index a6321d6e2..8f0353bbc 100644 --- a/Week 06/id_106/NOTE.md +++ b/Week 06/id_106/NOTE.md @@ -1,4 +1,46 @@ -# NOTE +# 20191118-1124 学习总结 - +本周主要学习了 字典树 并查集 剪枝 双向BFS 启发式搜索 AVL 红黑树 + +其中字典树的特点是使用空间换时间,对于单词的搜索有天然的便利 +一般的单词搜索字典树由每层26个子去实现,分别代表26个字母,搜索一个单词搜索的深度即为单子字母个数 + +并查集是一种特殊的数据结构,适用于集合的合并,关系查找。 +每个节点有一个parent,当parent为自己时即为当前集合的代表元素。 +集合的合并也即为将parent指向另一个节点即可完成 +并查集的代码模板 +```java +class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } +} +``` + +剪枝是指在树遍历时如果能提前判断较优的路径,可以将次优的路径“剪掉”,减少遍历的步骤 +典型的题目是八皇后 数独 + +双向BFS是指从树的两端进行BFS,当元素碰撞的时候即得到结果 + +启发式搜索是在BFS的基础上使用优先级队列,根据不同的题目定义函数,来减少遍历的步骤 diff --git a/Week 06/id_111/NOTE.md b/Week 06/id_111/NOTE.md index a6321d6e2..2546e2096 100644 --- a/Week 06/id_111/NOTE.md +++ b/Week 06/id_111/NOTE.md @@ -1,4 +1,43 @@ -# NOTE +# WEEK 06 +--- +## Trie 字典树 + 又称单词查找树或键树,一种树形结构 +### 数据结构 +- 按层次打印二叉树 +- DFS BFS +- 二叉搜索树 +- 前中后序遍历 +- 图解释义 +### 核心思想 +- 应用:用户统计和排序大量的字符串,常被搜索引擎系统用于文本词频统计 +- 优点:最大限度减少五位的字符串比较,查询效率比哈希表高 +### 基本性质 +1. 结点本身不存完整单词; +2. 从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的 字符串; +3. 每个结点的所有子结点路径代表的字符都不相同 +--- +## 并查集 + 主要处理组团、配对问题(Group or not) +### 基本操作 +- makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合。 +- unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在 的集合不相交,如果相交则不合并。 +- find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元 素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。 +### 实战练习 +1. 朋友圈问题: + • https://leetcode-cn.com/problems/friend-circles + + 类似于之前的炸岛问题 +--- +# 高级搜索 +基于 之前的 BFS DFS 等搜索 +## 初级搜索 + + +## 剪枝 +优化方式 + +搜索方向 +BFS 双向搜索 diff --git a/Week 06/id_111/leetcode_208_111.py b/Week 06/id_111/leetcode_208_111.py new file mode 100644 index 000000000..237129fba --- /dev/null +++ b/Week 06/id_111/leetcode_208_111.py @@ -0,0 +1,68 @@ +""" +实现一个 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 构成的。 +保证所有输入均为非空字符串。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree +""" + +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.end_of_word = "#" + + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for char in word: + node = node.setdefault(char,{}) + node[self.end_of_word] = self.end_of_word + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week 06/id_111/leetcode_212_111.py b/Week 06/id_111/leetcode_212_111.py new file mode 100644 index 000000000..60cf23b18 --- /dev/null +++ b/Week 06/id_111/leetcode_212_111.py @@ -0,0 +1,56 @@ +''' +LEETCODE - WORD SEARCH II +给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。 +同一个单元格内的字母在一个单词中不允许被重复使用。 + +示例: +输入: +words = ["oath","pea","eat","rain"] and board = +[ + ['o','a','a','n'], + ['e','t','a','e'], + ['i','h','k','r'], + ['i','f','l','v'] +] + +输出: ["eat","oath"] +说明: +你可以假设所有输入都由小写字母 a-z 组成。 + +提示: +你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/word-search-ii +''' +# 方法一: 对words 进行遍历 --> board search +# 时间复杂度: O(N*m*m*4^k) N:单词个数 m:二维网格边长 4:下个字符的四个通路 k:单词长度 +#方法二 : Trie +#1. all words --> Trie 构建起字典树 (prefix +#2. borad DFS +#时间复杂度 +# + +END_OF_WORD = "#" +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + if not board or not board[0]:return[] + if not words: return[] + self.result = set() + + #建构Trie + root = collections.defaultdict() + for word in words: + node = root + for char in word: + node = node.setdefault(char,collections.defaultdict()) + node[END_OF_WORD] = END_OF_WORD + + self.m,self.n = len(board),len(board[0]) + for i in xrange(self.m): + for j in yrange(self.n): + if board[i][j] in root: + self.__dfs(board,i,j,"",root) + return list(self.result) \ No newline at end of file diff --git a/Week 06/id_126/LeetCode_212_126.py b/Week 06/id_126/LeetCode_212_126.py new file mode 100644 index 000000000..5ba28eec4 --- /dev/null +++ b/Week 06/id_126/LeetCode_212_126.py @@ -0,0 +1,31 @@ +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + trie = {} + for word in words: + t = trie + for w in word: + t = t.setdefault(w, {}) + t["end"] = 1 + #print(trie) + res = [] + row = len(board) + col = len(board[0]) + def dfs(i, j, trie, s): + #print(i, j, trie, s) + c = board[i][j] + if c not in trie: return + trie = trie[c] + if "end" in trie and trie["end"] == 1: + res.append(s + c) + trie["end"] = 0 # 防止重复数组加入 + board[i][j] = "#" + for x, y in [[-1, 0], [1, 0], [0, 1], [0, -1]]: + tmp_i = x + i + tmp_j = y + j + if 0 <= tmp_i < row and 0 <= tmp_j < col and board[tmp_i][tmp_j] != "#": + dfs(tmp_i, tmp_j, trie, s + c) + board[i][j] = c + for i in range(row): + for j in range(col): + dfs(i, j, trie, "") + return res diff --git a/Week 06/id_126/LeetCode_51_126.py b/Week 06/id_126/LeetCode_51_126.py new file mode 100644 index 000000000..fa277596e --- /dev/null +++ b/Week 06/id_126/LeetCode_51_126.py @@ -0,0 +1,40 @@ +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + def could_place(row, col): + return not (cols[col] + hill_diagonals[row - col] + dale_diagonals[row + col]) + + def place_queen(row, col): + queens.add((row, col)) + cols[col] = 1 + hill_diagonals[row - col] = 1 + dale_diagonals[row + col] = 1 + + def remove_queen(row, col): + queens.remove((row, col)) + cols[col] = 0 + hill_diagonals[row - col] = 0 + dale_diagonals[row + col] = 0 + + def add_solution(): + solution = [] + for _, col in sorted(queens): + solution.append('.' * col + 'Q' + '.' * (n - col - 1)) + output.append(solution) + + def backtrack(row = 0): + for col in range(n): + if could_place(row, col): + place_queen(row, col) + if row + 1 == n: + add_solution() + else: + backtrack(row + 1) + remove_queen(row, col) + + cols = [0] * n + hill_diagonals = [0] * (2 * n - 1) + dale_diagonals = [0] * (2 * n - 1) + queens = set() + output = [] + backtrack() + return output \ No newline at end of file diff --git a/Week 06/id_131/LeetCode_1091_131_1.java b/Week 06/id_131/LeetCode_1091_131_1.java new file mode 100644 index 000000000..21406b2d4 --- /dev/null +++ b/Week 06/id_131/LeetCode_1091_131_1.java @@ -0,0 +1,80 @@ +package com.lzhlyle.leetcode.recite.no1091; + +import java.util.*; + +public class ShortestPathInBinaryMatrix { + // bfs + public int shortestPathBinaryMatrix(int[][] grid) { + // base condition + if (grid[0][0] == 1 || grid[grid.length - 1][grid[0].length - 1] == 1) return -1; + if (grid.length == 1) return 1; + + int level = 1; + + // bfs + Queue nextSteps = new LinkedList<>(Collections.singleton(new Cell(0, 0))); + grid[0][0] = 1; // visited + // terminator + while (!nextSteps.isEmpty()) { + level++; + List positions = new ArrayList<>(); + while (!nextSteps.isEmpty()) positions.add(nextSteps.remove()); // remove all + for (Cell position : positions) { + // process + // drill down + List children = this._getNeighbors(position.x, position.y, grid); + // pruning + for (Cell child : children) { + if (child.x == grid.length - 1 && child.y == grid[0].length - 1) return level; + + if (grid[child.x][child.y] == 1) continue; + + grid[child.x][child.y] = 1; // visited + nextSteps.add(new Cell(child.x, child.y)); + } + } + + // reverse state + } + + return -1; + } + + // directions + private static final int[] dx = new int[]{0, 0, -1, 1, -1, -1, 1, 1}; + private static final int[] dy = new int[]{1, -1, 0, 0, 1, -1, 1, -1}; + + private List _getNeighbors(int x, int y, int[][] grid) { + List res = new ArrayList<>(); + for (int i = 0; i < dx.length; i++) { + if (x + dx[i] > grid.length - 1 || x + dx[i] < 0 + || y + dy[i] > grid[0].length - 1 || y + dy[i] < 0) continue; + res.add(new Cell(x + dx[i], y + dy[i])); + } + return res; + } + + class Cell { + int x; + int y; + + public Cell(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static void main(String[] args) { + int[][] grid = { + {0, 0, 1, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 1}, + {0, 0, 1, 0, 1, 0, 0}, + {0, 0, 0, 1, 1, 1, 0}, + {1, 0, 0, 1, 1, 0, 0}, + {1, 1, 1, 1, 1, 0, 1}, + {0, 0, 1, 0, 0, 0, 0} + }; + int res = new ShortestPathInBinaryMatrix().shortestPathBinaryMatrix(grid); + System.out.println(res); + } +} diff --git a/Week 06/id_131/LeetCode_1091_131_2.java b/Week 06/id_131/LeetCode_1091_131_2.java new file mode 100644 index 000000000..dabcc4d29 --- /dev/null +++ b/Week 06/id_131/LeetCode_1091_131_2.java @@ -0,0 +1,84 @@ +package com.lzhlyle.leetcode.recite.no1091; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; + +public class ShortestPathInBinaryMatrix_2 { + // bfs A* search BUT DO NOT WORK BETTER..so sad + public int shortestPathBinaryMatrix(int[][] grid) { + // base condition + int maxX = grid.length - 1; + int maxY = grid[0].length - 1; + if (grid[0][0] == 1 || grid[maxX][maxY] == 1) return -1; + if (grid.length == 1) return 1; + + int level = 1; + + // bfs + PriorityQueue nextSteps = new PriorityQueue<>(Comparator.comparingInt(c -> (maxX - c.x + maxY - c.y))); + nextSteps.add(new Cell(0, 0)); + grid[0][0] = 1; // visited + // terminator + while (!nextSteps.isEmpty()) { + level++; + List positions = new ArrayList<>(); + while (!nextSteps.isEmpty()) positions.add(nextSteps.remove()); // remove all + for (Cell position : positions) { + // process + // drill down + List children = this._getNeighbors(position.x, position.y, grid); + // pruning + for (Cell child : children) { + if (child.x == grid.length - 1 && child.y == grid[0].length - 1) return level; + + if (grid[child.x][child.y] == 1) continue; + + grid[child.x][child.y] = 1; // visited + nextSteps.add(new Cell(child.x, child.y)); + } + } + + // reverse state + } + + return -1; + } + + // directions + private static final int[] dx = new int[]{0, 0, -1, 1, -1, -1, 1, 1}; + private static final int[] dy = new int[]{1, -1, 0, 0, 1, -1, 1, -1}; + + private List _getNeighbors(int x, int y, int[][] grid) { + List res = new ArrayList<>(); + for (int i = 0; i < dx.length; i++) { + if (x + dx[i] > grid.length - 1 || x + dx[i] < 0 + || y + dy[i] > grid[0].length - 1 || y + dy[i] < 0) continue; + res.add(new Cell(x + dx[i], y + dy[i])); + } + return res; + } + + class Cell { + int x; + int y; + + Cell(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static void main(String[] args) { + int[][] grid = { + {0, 1, 0, 1, 0}, + {1, 0, 0, 0, 1}, + {0, 0, 1, 1, 1}, + {0, 0, 0, 0, 0}, + {1, 0, 1, 0, 0} + }; + int res = new ShortestPathInBinaryMatrix_2().shortestPathBinaryMatrix(grid); + System.out.println(res); + } +} diff --git a/Week 06/id_131/LeetCode_1091_131_3.java b/Week 06/id_131/LeetCode_1091_131_3.java new file mode 100644 index 000000000..4684d0bc8 --- /dev/null +++ b/Week 06/id_131/LeetCode_1091_131_3.java @@ -0,0 +1,104 @@ +package com.lzhlyle.leetcode.recite.no1091; + +import java.util.*; + +public class ShortestPathInBinaryMatrix_3 { + // two-ended bfs + public int shortestPathBinaryMatrix(int[][] grid) { + // base condition + int maxX = grid.length - 1; + int maxY = grid[0].length - 1; + if (grid[0][0] == 1 || grid[maxX][maxY] == 1) return -1; + if (grid.length == 1) return 1; + + Set beginSet = new HashSet<>(Collections.singleton(new Cell(0, 0))); + boolean[][] beginVisited = new boolean[maxX + 1][maxY + 1]; + beginVisited[0][0] = true; + + Set endSet = new HashSet<>(Collections.singleton(new Cell(maxX, maxY))); + boolean[][] endVisited = new boolean[maxX + 1][maxY + 1]; + endVisited[maxX][maxY] = true; + + // bfs + return this.searchBfs(1, beginSet, endSet, grid, beginVisited, endVisited, maxX, maxY); + } + + // bfs recursion + private int searchBfs(int step, Set beginSet, Set endSet, int[][] grid, + boolean[][] beginVisited, boolean[][] endVisited, int maxX, int maxY) { + // terminator + if (beginSet.isEmpty() || endSet.isEmpty()) return -1; // cannot find + + // process + step++; + // always from less to more + if (beginSet.size() > endSet.size()) { + Set swap = beginSet; + beginSet = endSet; + endSet = swap; + + endVisited = beginVisited; + } + + Set nextBegin = new HashSet<>(); + boolean[][] nextVisited = new boolean[maxX + 1][maxY + 1]; + for (Cell begin : beginSet) { + // flood-fill + grid[begin.x][begin.y] = 1; + + List neighbors = this._getNeighbors(begin.x, begin.y, grid); + // pruning + for (Cell neighbor : neighbors) { + if (endVisited[neighbor.x][neighbor.y]) return step; // meet + if (grid[neighbor.x][neighbor.y] == 1) continue; + grid[neighbor.x][neighbor.y] = 1; // flood-fill + + nextBegin.add(neighbor); + nextVisited[neighbor.x][neighbor.y] = true; + } + } + beginSet = nextBegin; + beginVisited = nextVisited; + + // drill down + return this.searchBfs(step, beginSet, endSet, grid, beginVisited, endVisited, maxX, maxY); + } + + // directions + private static final int[] dx = new int[]{0, 0, -1, 1, -1, -1, 1, 1}; + private static final int[] dy = new int[]{1, -1, 0, 0, 1, -1, 1, -1}; + + private List _getNeighbors(int x, int y, int[][] grid) { + List res = new ArrayList<>(); + for (int i = 0; i < dx.length; i++) { + if (x + dx[i] > grid.length - 1 || x + dx[i] < 0 + || y + dy[i] > grid[0].length - 1 || y + dy[i] < 0) continue; + res.add(new Cell(x + dx[i], y + dy[i])); + } + return res; + } + + class Cell { + int x; + int y; + + Cell(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static void main(String[] args) { + int[][] grid = { + {0, 0, 1, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 1}, + {0, 0, 1, 0, 1, 0, 0}, + {0, 0, 0, 1, 1, 1, 0}, + {1, 0, 0, 1, 1, 0, 0}, + {1, 1, 1, 1, 1, 0, 1}, + {0, 0, 1, 0, 0, 0, 0} + }; + int res = new ShortestPathInBinaryMatrix_3().shortestPathBinaryMatrix(grid); + System.out.println(res); + } +} diff --git a/Week 06/id_131/LeetCode_127_131_1.java b/Week 06/id_131/LeetCode_127_131_1.java new file mode 100644 index 000000000..2525785b5 --- /dev/null +++ b/Week 06/id_131/LeetCode_127_131_1.java @@ -0,0 +1,59 @@ +package com.lzhlyle.leetcode.self.no127; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WordLadder_5 { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord)) return 2; + + Set meets = new HashSet<>(wordList); // O(n) + + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + + return this._search(1, beginSet, endSet, meets); + } + + private int _search(int level, Set beginSet, Set endSet, Set meets) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; + + // process + meets.removeAll(beginSet); + level++; + Set nextLevelSet = new HashSet<>(); + // iter every begin word + for (String beginWord : beginSet) { + char[] chars = beginWord.toCharArray(); + // iter for every char + for (int i = 0; i < chars.length; i++) { // O(k) + char temp = chars[i]; + // replace every letter + for (char ch = 'a'; ch < 'z'; ch++) { // O(1) 都是26遍 + chars[i] = ch; + String newWord = String.valueOf(chars); + if (!meets.contains(newWord)) continue; + if (endSet.contains(newWord)) return level; + nextLevelSet.add(newWord); + } + // reverse + chars[i] = temp; + } + } + + // drill down + // always from less to more + if (nextLevelSet.size() <= endSet.size()) { + beginSet = nextLevelSet; + } else { + beginSet = endSet; + endSet = nextLevelSet; + } + + return this._search(level, beginSet, endSet, meets); + } +} diff --git a/Week 06/id_131/LeetCode_127_131_2.java b/Week 06/id_131/LeetCode_127_131_2.java new file mode 100644 index 000000000..0eb05a87e --- /dev/null +++ b/Week 06/id_131/LeetCode_127_131_2.java @@ -0,0 +1,72 @@ +package com.lzhlyle.leetcode.self.no127; + +import java.util.*; + +public class WordLadder_ViaTemplate_Queue { + public int ladderLength(String beginWord, String endWord, List wordList) { + // base condition + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord) || beginWord.length() == 1) return 2; + + int level = 1; + Set meets = new HashSet<>(wordList); // O(1) for looking up + + Queue beginQueue = new LinkedList<>(Collections.singleton(beginWord)); + Queue endQueue = new LinkedList<>(Collections.singleton(endWord)); + + // terminator + while (!beginQueue.isEmpty() && !endQueue.isEmpty()) { + // process + level++; + + Queue nextBegin = new LinkedList<>(); + // each word in begin queue + meets.removeAll(beginQueue); // 避免找回头 + while (!beginQueue.isEmpty()) { + String begin = beginQueue.remove(); + + List children = this._getChildren(begin); + for (String child : children) { + // pruning + if (!meets.contains(child)) continue; + // terminator + if (endQueue.contains(child)) return level; // meet + nextBegin.add(child); + } + } + + // drill down + beginQueue = nextBegin; + // always from less to more + if (beginQueue.size() > endQueue.size()) { + Queue swap = beginQueue; + beginQueue = endQueue; + endQueue = swap; + } + } + + return 0; // cannot meet + } + + private List _getChildren(String begin) { + List res = new ArrayList<>(); + char[] chars = begin.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char temp = chars[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (temp == c) continue; + chars[i] = c; + res.add(String.valueOf(chars)); + } + // reverse + chars[i] = temp; + } + return res; + } + + public static void main(String[] args) { + int res = new WordLadder_ViaTemplate_Queue().ladderLength("hit", "dot", + Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")); + System.out.println(res); + } +} diff --git a/Week 06/id_131/LeetCode_127_131_3.java b/Week 06/id_131/LeetCode_127_131_3.java new file mode 100644 index 000000000..dd28095b0 --- /dev/null +++ b/Week 06/id_131/LeetCode_127_131_3.java @@ -0,0 +1,68 @@ +package com.lzhlyle.leetcode.self.no127; + +import java.util.*; + +public class WordLadder_ViaTemplate_Recursion { + public int ladderLength(String beginWord, String endWord, List wordList) { + // base condition + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord) || beginWord.length() == 1) return 2; + + int level = 1; + + // initial + Set meets = new HashSet<>(wordList); + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + + return this.searchBfs(level, meets, beginSet, endSet); + } + + private int searchBfs(int level, Set meets, Set beginSet, Set endSet) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; // cannot find + + // process + level++; + // always from less to more + if (beginSet.size() > endSet.size()) { + Set swap = beginSet; + beginSet = endSet; + endSet = swap; + } + + // each word in begin + Set nextBegin = new HashSet<>(); + meets.removeAll(beginSet); + for (String begin : beginSet) { + List neighbors = this._getNeighbors(begin); + for (String neighbor : neighbors) { + if (!meets.contains(neighbor)) continue; + if (endSet.contains(neighbor)) return level; + nextBegin.add(neighbor); + } + } + beginSet = nextBegin; + + // drill down + return this.searchBfs(level, meets, beginSet, endSet); + + // reverse state + } + + private List _getNeighbors(String word) { + List res = new ArrayList<>(); + char[] chars = word.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char temp = chars[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (temp == c) continue; + chars[i] = c; + res.add(String.valueOf(chars)); + } + // reverse + chars[i] = temp; + } + return res; + } +} diff --git a/Week 06/id_131/LeetCode_127_131_4.java b/Week 06/id_131/LeetCode_127_131_4.java new file mode 100644 index 000000000..ac4e14ff8 --- /dev/null +++ b/Week 06/id_131/LeetCode_127_131_4.java @@ -0,0 +1,72 @@ +package com.lzhlyle.leetcode.self.no127; + +import java.util.*; + +public class WordLadder_ViaTemplate_Set { + public int ladderLength(String beginWord, String endWord, List wordList) { + // base condition + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord) || beginWord.length() == 1) return 2; + + int level = 1; + Set meets = new HashSet<>(wordList); // O(1) for looking up + + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + + // terminator + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + // process + level++; + + // always from less to more + if (beginSet.size() > endSet.size()) { + Set swap = beginSet; + beginSet = endSet; + endSet = swap; + } + + meets.removeAll(beginSet); // 避免找回头 + + Set nextBegin = new HashSet<>(); + // each word in begin set + for (String begin : beginSet) { + List children = this._getChildren(begin); + for (String child : children) { + // pruning + if (!meets.contains(child)) continue; + // terminator + if (endSet.contains(child)) return level; // meet + nextBegin.add(child); + } + } + + // drill down + beginSet = nextBegin; + } + + return 0; // cannot meet + } + + private List _getChildren(String begin) { + List res = new ArrayList<>(); + char[] chars = begin.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char temp = chars[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (temp == c) continue; + chars[i] = c; + res.add(String.valueOf(chars)); + } + // reverse + chars[i] = temp; + } + return res; + } + + public static void main(String[] args) { + int res = new WordLadder_ViaTemplate_Set().ladderLength("hit", "dot", + Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")); + System.out.println(res); + } +} diff --git a/Week 06/id_131/LeetCode_208_131.java b/Week 06/id_131/LeetCode_208_131.java new file mode 100644 index 000000000..22c95745c --- /dev/null +++ b/Week 06/id_131/LeetCode_208_131.java @@ -0,0 +1,77 @@ +package com.lzhlyle.leetcode.self.no208; + +class Trie { + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode curr = root; + for (char c : word.toCharArray()) { + if (!curr.contains(c)) curr.set(c, new TrieNode()); + curr = curr.get(c); + } + curr.setEnd(); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode last = searchPrefix(word); + return last != null && last.isEnd(); + } + + private TrieNode searchPrefix(String prefix) { + TrieNode curr = root; + for (char c : prefix.toCharArray()) { + curr = curr.get(c); + if (curr == null) return null; + } + return curr; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + return searchPrefix(prefix) != null; + } +} + +class TrieNode { + private TrieNode[] links; + private boolean isEnd; + + TrieNode() { + links = new TrieNode[26]; + } + + public void set(char c, TrieNode next) { + links[c - 'a'] = next; + } + + public TrieNode get(char c) { + return links[c - 'a']; + } + + public boolean contains(char c) { + return links[c - 'a'] != null; + } + + public boolean isEnd() { + return isEnd; + } + + void setEnd() { + isEnd = true; + } +} diff --git a/Week 06/id_131/LeetCode_51_131.java b/Week 06/id_131/LeetCode_51_131.java new file mode 100644 index 000000000..83a42e0e5 --- /dev/null +++ b/Week 06/id_131/LeetCode_51_131.java @@ -0,0 +1,69 @@ +package com.lzhlyle.leetcode.self.no51; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class NQueens_3 { + public List> solveNQueens(int n) { + // base condition + if (n <= 0) return Collections.emptyList(); + if (n == 1) return Collections.singletonList(Collections.singletonList("Q")); + + // initial + List> result = new ArrayList<>(); + int[] queensCol = new int[n]; + int[] visitedCol = new int[n]; + int[] visitedUphill = new int[2 * n - 1]; // x + y + int[] visitedDownhill = new int[2 * n - 1]; // n - 1 + x - y + + // dfs + this.locate(0, n, result, queensCol, visitedCol, visitedUphill, visitedDownhill); + + return result; + } + + private void locate(int row, int n, List> result, int[] queensCol, + int[] visitedCol, int[] visitedUphill, int[] visitedDownhill) { + // terminator + // each col + for (int col = 0; col < n; col++) { + // current position: (row, col) + if (this.validate(row, col, n, visitedCol, visitedUphill, visitedDownhill)) { + // process + queensCol[row] = col; + visitedCol[col] = 1; + visitedUphill[row + col] = 1; + visitedDownhill[n - 1 + row - col] = 1; + + if (row == n - 1) this.appendBoard(n, queensCol, result); + // drill down + else this.locate(row + 1, n, result, queensCol, visitedCol, visitedUphill, visitedDownhill); + + // reverse state + queensCol[row] = 0; + visitedCol[col] = 0; + visitedUphill[row + col] = 0; + visitedDownhill[n - 1 + row - col] = 0; + } + } + } + + private boolean validate(int x, int y, int n, + int[] visitedCol, int[] visitedUphill, int[] visitedDownhill) { + return visitedCol[y] + visitedUphill[x + y] + visitedDownhill[n - 1 + x - y] == 0; + } + + private void appendBoard(int n, int[] queensCol, List> result) { + List board = new ArrayList<>(); + for (int row = 0; row < n; row++) { + StringBuilder builder = new StringBuilder(); + for (int col = 0; col < n; col++) { + if (queensCol[row] == col) builder.append('Q'); + else builder.append('.'); + } + board.add(builder.toString()); + } + result.add(board); + } +} diff --git a/Week 06/id_131/NOTE.md b/Week 06/id_131/NOTE.md index a6321d6e2..33989081b 100644 --- a/Week 06/id_131/NOTE.md +++ b/Week 06/id_131/NOTE.md @@ -1,4 +1,4 @@ -# NOTE - - - +# NOTE +第六周 + + diff --git a/Week 06/id_141/LeetCode_200_141.swift b/Week 06/id_141/LeetCode_200_141.swift new file mode 100644 index 000000000..33615f8f5 --- /dev/null +++ b/Week 06/id_141/LeetCode_200_141.swift @@ -0,0 +1,51 @@ +// +// NumberOfIsland.swift +// algorithm +// +// Created by pingan on 2019/11/23. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//200. 岛屿数量 +class NumberOfIslands +{ + let directions: [[Int]] = [[-1,0],[0,-1],[1,0],[0,1]]; + var marked: [[Bool]]?; + var rows = 0; + var cols = 0; + var grid: [[Character]]? + func numIslands(_ grid:[[Character]]) -> Int { + rows = grid.count; + if rows == 0 { + return 0; + } + cols = grid[0].count; + self.grid = grid; + marked = Array(repeating: Array(repeating: false, count: cols), count: rows); + var count = 0; + for i in 0.. Bool { + return x >= 0 && x < rows && y >= 0 && y < cols; + } +} diff --git a/Week 06/id_141/LeetCode_208_141.swift b/Week 06/id_141/LeetCode_208_141.swift new file mode 100644 index 000000000..454665227 --- /dev/null +++ b/Week 06/id_141/LeetCode_208_141.swift @@ -0,0 +1,85 @@ +// +// Trie.swift +// algorithm +// +// Created by pingan on 2019/11/21. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//208. 实现 Trie (前缀树) +class TrieNode { + private let R = 26; + private var links: [TrieNode?]; + private var endValue: Bool; + + init() { + links = Array(repeating: nil, count: R); + endValue = false; + } + + public func getIndex(_ ch: Character) -> Int { + return Int(ch.asciiValue! - Character("a").asciiValue!); + } + + public func containsKey(_ ch: Character) -> Bool { + return links[self.getIndex(ch)] != nil; + } + + public func get(_ ch: Character) -> TrieNode { + return links[self.getIndex(ch)]!; + } + + public func put(_ ch: Character, _ node: TrieNode) { + links[self.getIndex(ch)] = node; + } + + public func setEnd() { + self.endValue = true; + } + + public func isEnd() -> Bool { + return endValue; + } +} + +class Trie { + private var root: TrieNode; + + init() { + root = TrieNode(); + } + + public func insert(_ word: String) { + var node = root; + for ch in word { + if !node.containsKey(ch) { + node.put(ch, TrieNode()); + } + node = node.get(ch); + } + node.setEnd(); + } + + public func search(_ word: String) -> Bool{ + let node = searchPrefix(word); + return node != nil && node!.isEnd(); + } + + public func searchPrefix(_ word: String) -> TrieNode? { + var node = root; + for ch in word { + if node.containsKey(ch) { + node = node.get(ch); + }else{ + return nil; + } + } + return node; + } + + public func startsWith(_ prefix: String) -> Bool { + let node = searchPrefix(prefix); + return node != nil; + } +} diff --git a/Week 06/id_141/LeetCode_547_141.swift b/Week 06/id_141/LeetCode_547_141.swift new file mode 100644 index 000000000..36463a77d --- /dev/null +++ b/Week 06/id_141/LeetCode_547_141.swift @@ -0,0 +1,31 @@ +// +// FriendCircles.swift +// algorithm +// +// Created by pingan on 2019/11/23. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//547. 朋友圈 +class FriendCircle { + func findCircleNum(_ M: [[Int]]) -> Int { + var visited: [Int] = Array(repeating: 0, count: M.count); + var count = 0; + for i in 0..>& grid) { + if (grid.empty() || grid[0].empty() || + grid[0][0] == 1 || + grid[grid.size()-1][grid[grid.size()-1].size()-1] == 1) + return -1; + + queue> q; + q.push({0, 0}); + + vector dx = {1, 0, 1, 1,-1,-1, 0,-1}; + vector dy = {1, 1, 0,-1, 1,-1,-1, 0}; + + int step = 1; + while (! q.empty()) { + auto v = q.front(); + q.pop(); + + int x = v.first; + int y = v.second; + if (x == (grid[0].size() - 1) && y == grid.size() - 1) + return step; + + if (grid[y][x] != -1) { + grid[y][x] = -1; + + for (int n = 0; n < 8; ++n) { + int nx = x + dx[n]; + int ny = y + dy[n]; + if (nx >= 0 && nx < grid[0].size() && + ny >= 0 && ny < grid.size() && + grid[ny][nx] == 0) { + q.push({nx, ny}); + } + } + } + ++step; + } + return -1; + } +}; diff --git a/Week 06/id_151/LeetCode_127_151.cpp b/Week 06/id_151/LeetCode_127_151.cpp new file mode 100644 index 000000000..49ecdd975 --- /dev/null +++ b/Week 06/id_151/LeetCode_127_151.cpp @@ -0,0 +1,45 @@ +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set words(wordList.begin(), wordList.end()); + unordered_set q_begin, q_end; + unordered_set marker; + q_begin.insert(beginWord); + q_end.insert(endWord); + + if (! words.count(endWord)) + return 0; + + int dist = 1; + + while (! q_begin.empty() && ! q_end.empty()) { + ++dist; + unordered_set tmp_set; + for (auto word : q_begin) { + for (int n = 0; n < word.size(); ++n) { + char tmp = word[n]; + for (char ch = 'a'; ch <= 'z'; ++ch) { + word[n] = ch; + + if (q_end.count(word)) + return dist; + + if (words.count(word) && ! marker.count(word)) { + + //cout << word << endl; + tmp_set.insert(word); + marker.insert(word); + } + } + word[n] = tmp; + } + } + q_begin = tmp_set; + + if (q_begin.size() > q_end.size()) { + q_begin.swap(q_end); + } + } + return 0; + } +}; diff --git a/Week 06/id_151/LeetCode_130_151.cpp b/Week 06/id_151/LeetCode_130_151.cpp new file mode 100644 index 000000000..f1db1e138 --- /dev/null +++ b/Week 06/id_151/LeetCode_130_151.cpp @@ -0,0 +1,44 @@ +class Solution { +public: + void solve(vector>& board) { + if (board.empty() || board[0].empty()) + return; + + vector dx = {0, 0, 1,-1}; + vector dy = {1,-1, 0, 0}; + for (int y = 0; y < board.size(); ++y) { + if (board[y][0] == 'O') + dfs(board, y, 0, dx, dy); + if (board[y][board[y].size()-1] == 'O') + dfs(board, y, board[y].size()-1, dx, dy); + } + for (int x = 0; x < board[0].size(); ++x) { + if (board[0][x] == 'O') + dfs(board, 0, x, dx, dy); + if (board[board.size()-1][x] == 'O') + dfs(board, board.size()-1, x, dx, dy); + } + for (int y = 0; y < board.size(); ++y) { + for (int x = 0; x < board[y].size(); ++x) { + if (board[y][x] == '@') + board[y][x] = 'O'; + else if (board[y][x] == 'O') + board[y][x] = 'X'; + } + } + } + + void dfs(vector>& board, int y, int x, vector& dx, vector& dy) { + board[y][x] = '@'; + for (int i = 0; i < 4; ++i) { + int nx = x + dx[i]; + int ny = y + dy[i]; + + if (ny >= 0 && ny < board.size() && nx >= 0 && nx < board[ny].size() && + board[ny][nx] == 'O') { + + dfs(board, ny, nx, dx, dy); + } + } + } +}; diff --git a/Week 06/id_151/LeetCode_208_151.cpp b/Week 06/id_151/LeetCode_208_151.cpp new file mode 100644 index 000000000..1d3728029 --- /dev/null +++ b/Week 06/id_151/LeetCode_208_151.cpp @@ -0,0 +1,62 @@ +class Trie { +public: + /** Initialize your data structure here. */ + struct TrieNode { + TrieNode() { + for (int i = 0; i < 26; ++i) + nodes[i] = NULL; + end_of_the_word = false; + } + TrieNode* nodes[26]; + bool end_of_the_word; + }; + + Trie() { + + } + + /** Inserts a word into the trie. */ + void insert(string word) { + TrieNode* root = &root_; + for (const auto& ch : word) { + int index = ch - 'a'; + if (root->nodes[index] == NULL) + root->nodes[index] = new TrieNode(); + root = root->nodes[index]; + } + root->end_of_the_word = true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + TrieNode* node = find(word); + return node != NULL && node->end_of_the_word; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + TrieNode* node = find(prefix); + return node != NULL; + } + +private: + TrieNode* find(string word) { + TrieNode* root = &root_; + for (int i = 0; i < word.size() && root != NULL; ++i) { + int index = word[i] - 'a'; + root = root->nodes[index]; + } + return root; + } + +private: + TrieNode root_; +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ diff --git a/Week 06/id_151/LeetCode_212_151.cpp b/Week 06/id_151/LeetCode_212_151.cpp new file mode 100644 index 000000000..4dfb511bc --- /dev/null +++ b/Week 06/id_151/LeetCode_212_151.cpp @@ -0,0 +1,93 @@ +class Trie { +public: + struct TrieNode { + TrieNode() { + for (int i = 0; i < 26; ++i) + nodes[i] = NULL; + end_of_the_word = false; + } + TrieNode* nodes[26]; + bool end_of_the_word; + }; + + Trie() { + + } + + void insert(string word) { + TrieNode* root = &root_; + for (const auto& ch : word) { + int index = ch - 'a'; + if (root->nodes[index] == NULL) + root->nodes[index] = new TrieNode(); + root = root->nodes[index]; + } + root->end_of_the_word = true; + } + + bool search(string word) { + TrieNode* node = find(word); + return node != NULL && node->end_of_the_word; + } + + bool startsWith(string prefix) { + TrieNode* node = find(prefix); + return node != NULL; + } + +private: + TrieNode* find(string word) { + TrieNode* root = &root_; + for (int i = 0; i < word.size() && root != NULL; ++i) { + int index = word[i] - 'a'; + root = root->nodes[index]; + } + return root; + } + +private: + TrieNode root_; +}; + + +class Solution { +public: + vector findWords(vector>& board, vector& words) { + Trie trie; + set res; + for (const auto& word : words) + trie.insert(word); + + int dx[4] = {0,0,-1,1}; + int dy[4] = {1,-1,0,0}; + + for (int y = 0; y < board.size(); ++y) { + for (int x = 0; x < board[y].size(); ++x) { + dfs(trie, dx, dy, x, y, "", res, board); + } + } + + return vector(res.begin(), res.end()); + } + + void dfs(Trie& trie, int* dx, int* dy, int x, int y, + string cur, set& res, vector>& board) { + if (y >= board.size() || x >= board[y].size() || board[y][x] == '#') + return; + + char tmp = board[y][x]; + cur += tmp; + + if (! cur.empty() && ! trie.startsWith(cur)) + return; + + if (trie.search(cur)) + res.insert(cur); + + board[y][x] = '#'; + for (int i = 0; i < 4; ++i) { + dfs(trie, dx, dy, x + dx[i], y + dy[i], cur, res, board); + } + board[y][x] = tmp; + } +}; diff --git a/Week 06/id_151/LeetCode_36_151.cpp b/Week 06/id_151/LeetCode_36_151.cpp new file mode 100644 index 000000000..b2f186166 --- /dev/null +++ b/Week 06/id_151/LeetCode_36_151.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + bool isValidSudoku(vector>& board) { + vector> cols(board.size(), set()); + auto rows = cols; + auto blocks = cols; + + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[i].size(); ++j) { + char ch = board[i][j]; + if (ch != '.') { + if (cols[j].count(ch)) + return false; + cols[j].insert(ch); + if (rows[i].count(ch)) + return false; + rows[i].insert(ch); + if (blocks[j / 3 * 3 + i / 3].count(ch)) + return false; + blocks[j / 3 * 3 + i / 3].insert(ch); + } + } + } + return true; + } +}; diff --git a/Week 06/id_151/LeetCode_37_151.cpp b/Week 06/id_151/LeetCode_37_151.cpp new file mode 100644 index 000000000..701f36ff5 --- /dev/null +++ b/Week 06/id_151/LeetCode_37_151.cpp @@ -0,0 +1,39 @@ +class Solution { +public: + void solveSudoku(vector>& board) { + solve(board); + } + + bool solve(vector>& board) { + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[i].size(); ++j) { + if (board[i][j] != '.') + continue; + + for (int k = 1; k <= 9; ++k) { + char ch = '0' + k; + if (valid(board, i, j, ch)) { + board[i][j] = ch; + if (solve(board)) + return true; + board[i][j] = '.'; + } + } + return false; + } + } + return true; + } + + bool valid(vector>& board, int i, int j, char ch) { + for (int n = 0; n < 9; ++n) { + if (board[i][n] == ch) + return false; + if (board[n][j] == ch) + return false; + if (board[i / 3 * 3 + n / 3][j / 3 * 3 + n % 3] == ch) + return false; + } + return true; + } +}; diff --git a/Week 06/id_151/LeetCode_51_151.cpp b/Week 06/id_151/LeetCode_51_151.cpp new file mode 100644 index 000000000..4364291b6 --- /dev/null +++ b/Week 06/id_151/LeetCode_51_151.cpp @@ -0,0 +1,33 @@ +class Solution { +public: + vector> solveNQueens(int n) { + vector> ret; + vector cur(n, string(n, '.')); + set shu, pie, na; + solve(ret, cur, shu, pie, na, 0, n); + return ret; + } + + void solve(vector>& ret, vector& cur, + set& shu, set& pie, set& na, int level, int n) { + if (level == n) { + ret.push_back(cur); + return; + } + for (int y = level; y < n; ++y) { + for (int x = 0; x < n; ++x) { + if (! shu.count(x) && ! pie.count(y - x) && ! na.count(x + y)) { + cur[y][x] = 'Q'; + shu.insert(x); + pie.insert(y - x); + na.insert(x + y); + solve(ret, cur, shu, pie, na, level + 1, n); + na.erase(x + y); + pie.erase(y - x); + shu.erase(x); + cur[y][x] = '.'; + } + } + } + } +}; diff --git a/Week 06/id_151/LeetCode_547_151.cpp b/Week 06/id_151/LeetCode_547_151.cpp new file mode 100644 index 000000000..5cf834277 --- /dev/null +++ b/Week 06/id_151/LeetCode_547_151.cpp @@ -0,0 +1,57 @@ +class DisjointSet { +public: + DisjointSet(int n) { + n_ = new int[n]; + count_ = n; + for (int i = 0; i < n; ++i) + n_[i] = i; + } + + int find(int i) { + int n = n_[i]; + while (n != n_[n]) { + n = n_[n]; + } + + while (i != n) { + int tmp = n_[i]; + n_[i] = n; + i = n_[tmp]; + } + + return n; + } + + void uni(int p, int q) { + int rp = find(p); + int rq = find(q); + + if (rp == rq) + return; + + --count_; + n_[rp] = rq; + } + + int count() { return count_; } + +private: + int* n_; + int count_; +}; + +class Solution { +public: + int findCircleNum(vector>& M) { + DisjointSet dj(M.size()); + + for (int y = 0; y < M.size(); ++y) { + for (int x = 0; x < M[y].size(); ++x) { + if (M[y][x] == 1) + dj.uni(y, x); + } + } + + return dj.count(); + } +}; diff --git a/Week 06/id_151/LeetCode_773_151.cpp b/Week 06/id_151/LeetCode_773_151.cpp new file mode 100644 index 000000000..ce3c21328 --- /dev/null +++ b/Week 06/id_151/LeetCode_773_151.cpp @@ -0,0 +1,53 @@ +class Solution { +public: + int slidingPuzzle(vector>& board) { + string s; + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[i].size(); ++j) { + s.append(1, '0' + board[i][j]); + } + } + + map> di = { + {0, {1,3}}, + {1, {0,2,4}}, + {2, {1,5}}, + {3, {0,4}}, + {4, {1,3,5}}, + {5, {2,4}} + }; + + queue q; + unordered_set marker; + q.push(s); + int count = -1; + while (! q.empty()) { + ++count; + int qs = q.size(); + + for (int i = 0; i < qs; ++i) { + string cur = q.front(); + q.pop(); + + if (cur == "123450") + return count; + + if (! marker.count(cur)) { + marker.insert(cur); + + int zero_index = cur.find('0'); + for (const auto& d : di[zero_index]) { + cur[zero_index] = cur[d]; + cur[d] = '0'; + + q.push(cur); + + cur[d] = cur[zero_index]; + cur[zero_index] = '0'; + } + } + } + } + return -1; + } +}; diff --git a/Week 06/id_156/208_java.java b/Week 06/id_156/208_java.java new file mode 100644 index 000000000..57e7bab5e --- /dev/null +++ b/Week 06/id_156/208_java.java @@ -0,0 +1,76 @@ + +class TrieNode { + // R links to node children + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } +} + +class Trie { + private TrieNode root; + + public Trie() { + root = new TrieNode(); + } + + // Inserts a word into the trie. + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + +} + + diff --git a/Week 06/id_156/212_java.java b/Week 06/id_156/212_java.java new file mode 100644 index 000000000..f218cd866 --- /dev/null +++ b/Week 06/id_156/212_java.java @@ -0,0 +1,81 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +//字典树结点 +class trieNode{ + public String val; + public trieNode[] child=new trieNode[26]; + public boolean isLeaf=false; + + trieNode(){ + + } +} + +//字典树 +class wordTrie{ + public trieNode root=new trieNode(); + public void insert(String s){ + trieNode cur=root; + for(char c:s.toCharArray()){ + if(cur.child[c-'a']==null){ + cur.child [c-'a'] = new trieNode(); + cur=cur.child[c-'a']; + }else + cur=cur.child [c-'a']; + } + cur.isLeaf=true; + cur.val=s; + } +} + +class Solution { + public List findWords(char[][] board, String[] words) { + //构建字典树 + wordTrie myTrie=new wordTrie(); + trieNode root=myTrie.root; + for(String s:words) + myTrie.insert(s); + + //使用set防止重复 + Set result =new HashSet<>(); + int m=board.length; + int n=board[0].length; + boolean [][]visited=new boolean[m][n]; + //遍历整个二维数组 + for(int i=0;i(result); + } + private void find(char [] [] board, boolean [][]visited,int i,int j,int m,int n,Set result,trieNode cur){ + //边界以及是否已经访问判断 + if(i<0||i>=m||j<0||j>=n||visited[i][j]) + return; + cur=cur.child[board[i][j]-'a']; + visited[i][j]=true; + if(cur==null) + { + //如果单词不匹配,回退 + visited[i][j]=false; + return; + } + //找到单词加入 + if(cur.isLeaf) + { + result.add(cur.val); + } + find(board,visited,i+1,j,m,n,result,cur); + find(board,visited,i,j+1,m,n,result,cur); + find(board,visited,i,j-1,m,n,result,cur); + find(board,visited,i-1,j,m,n,result,cur); + //最后要回退,因为下一个起点可能会用到上一个起点的字符 + visited[i][j]=false; + } +} + diff --git a/Week 06/id_161/FriendZone.java b/Week 06/id_161/FriendZone.java new file mode 100644 index 000000000..e7ffea24e --- /dev/null +++ b/Week 06/id_161/FriendZone.java @@ -0,0 +1,51 @@ +class Solution { + public int findCircleNum(int[][] M) { + if (M == null || M.length == 0) { + return 0; + } + int n = M.length; + DisjointSet disjointSet = new DisjointSet(n); + for(int i = 0; i < n; i++) { + for(int j = i + 1; j < n; j++){ + if (M[i][j] == 1) { + disjointSet.join(i, j); + } + } + } + return disjointSet.getCount(); + } +} +class DisjointSet { + public int count; + public int[] parent; + + public DisjointSet(int n) { + this.count = n; + parent = new int[n]; + for(int i = 0; i < n; i++) { + parent[i] = i; + } + } + + // 查找根元素 + public int find(int p) { + while(p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + // 合并 + public void join(int m, int n) { + int rootM = find(m); + int rootN = find(n); + if (rootM != rootN) { + parent[rootM] = rootN; + count--; + } + } + // 返回集合个数 + public int getCount(){ + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_161/NumIslands.java b/Week 06/id_161/NumIslands.java new file mode 100644 index 000000000..f4eec68e3 --- /dev/null +++ b/Week 06/id_161/NumIslands.java @@ -0,0 +1,71 @@ +class Solution { + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) return 0; + int rows = grid.length; + int cols = grid[0].length; + int zeroCount = 0; + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '0'){ + zeroCount++; + } + } + } + Disjoint disjoint = new Disjoint(rows * cols); + for(int i = 0; i < rows; i++) { + for(int j = 0; j < cols; j++) { + if (grid[i][j] == '1') { + grid[i][j] = '0'; + if (i - 1 >= 0 && grid[i - 1][j] == '1') { + disjoint.join(i * cols + j, (i - 1) * cols + j); + } + if (i + 1 < rows && grid[i + 1][j] == '1') { + disjoint.join(i * cols + j, (i + 1) * cols + j); + } + if (j - 1 >= 0 && grid[i][j - 1] == '1') { + disjoint.join(i * cols + j, i * cols + j - 1); + } + if (j + 1 < cols && grid[i][j + 1] == '1') { + disjoint.join(i * cols + j, i * cols + j + 1); + } + } + } + } + return disjoint.getCount() - zeroCount; + } +} + +class Disjoint { + private int[] parent; + private int count; + + public Disjoint(int n){ + this.count = n; + parent = new int[n]; + for(int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while(p != parent[p]){ + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void join(int m, int n) { + int rootM = find(m); + int rootN = find(n); + if (rootM != rootN) { + parent[rootM] = rootN; + count--; + } + } + + public int getCount() { + return count; + } + +} \ No newline at end of file diff --git a/Week 06/id_161/SurroundUnion.java b/Week 06/id_161/SurroundUnion.java new file mode 100644 index 000000000..bc5e798d2 --- /dev/null +++ b/Week 06/id_161/SurroundUnion.java @@ -0,0 +1,31 @@ +class UnionFind { + int[] parents; + + public UnionFind(int totalNodes) { + parents = new int[totalNodes]; + for (int i = 0; i < totalNodes; i++) { + parents[i] = i; + } + } + + void union(int node1, int node2) { + int root1 = find(node1); + int root2 = find(node2); + if (root1 != root2) { + parents[root2] = root1; + } + } + + int find(int node) { + while (parents[node] != node) { + parents[node] = parents[parents[node]]; + node = parents[node]; + } + + return node; + } + + boolean isConnected(int node1, int node2) { + return find(node1) == find(node2); + } +} diff --git a/Week 06/id_171/FriendCirclesSol.cs b/Week 06/id_171/FriendCirclesSol.cs new file mode 100644 index 000000000..0071c5d92 --- /dev/null +++ b/Week 06/id_171/FriendCirclesSol.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Poplar.Algorithm.WeekSix +{ + public class FriendCirclesSol + { + public int FindCircleNum(int[][] m) + { + var visited = new int[m.Length]; + var count = 0; + for (int i = 0; i < m.Length; i++) + { + if (visited[i] == 0) + { + Dfs(m, visited, i); + count++; + } + } + return count; + } + + private void Dfs(int[][] m, int[] visited, int i) + { + for (int j = 0; j < visited.Length; j++) + { + if (m[i][j] == 1 && visited[j] == 0) + { + visited[j] = 1; + Dfs(m, visited, j); + } + } + } + } +} diff --git a/Week 06/id_171/ImplementTriePrefixTreeSol.cs b/Week 06/id_171/ImplementTriePrefixTreeSol.cs new file mode 100644 index 000000000..0684b01c8 --- /dev/null +++ b/Week 06/id_171/ImplementTriePrefixTreeSol.cs @@ -0,0 +1,79 @@ +namespace Poplar.Algorithm.WeekSix +{ + public class Trie + { + private readonly short _base; + private readonly Trie[] _tries; + private bool _isEndOfWord; + + public Trie() + { + this._base = (short)'a'; + this._tries = new Trie[26]; + this._isEndOfWord = false; + } + + /** Inserts a word into the trie. */ + public void Insert(string word) + { + var tries = this._tries; + for (int i = 0; i < word.Length; i++) + { + var c = word[i] - this._base; + var trie = tries[c]; + if (trie == null) + { + trie = new Trie(); + tries[c] = trie; + } + if (i == word.Length - 1) + { + trie._isEndOfWord = true; + } + tries = trie._tries; + } + } + + /** Returns if the word is in the trie. */ + public bool Search(string word) + { + var tries = this._tries; + for (int i = 0; i < word.Length; i++) + { + var c = word[i] - this._base; + var trie = tries[c]; + if (trie == null) + { + return false; + } + if (i == word.Length - 1 && !trie._isEndOfWord) + { + return false; + } + tries = trie._tries; + } + return true; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public bool StartsWith(string prefix) + { + var tries = this._tries; + for (int i = 0; i < prefix.Length; i++) + { + var c = prefix[i] - this._base; + var trie = tries[c]; + if (trie == null) + { + return false; + } + if (i == prefix.Length - 1) + { + return true; + } + tries = trie._tries; + } + return true; + } + } +} diff --git a/Week 06/id_176/LeetCode_208_176.swift b/Week 06/id_176/LeetCode_208_176.swift new file mode 100644 index 000000000..9359f56f0 --- /dev/null +++ b/Week 06/id_176/LeetCode_208_176.swift @@ -0,0 +1,51 @@ +public class TrieNode { + public var children: [String: TrieNode] + public var isWord: Bool + public var word: String? + + public init() { + self.children = [String: TrieNode]() + self.isWord = false + self.word = nil + } +} + +public class Trie { + private var root: TrieNode + + public init() { + self.root = TrieNode() + } + + public func insert(_ word: String) { + var current = self.root + for letter in word { + current = current.children[String(letter)]! + } + current.isWord = true + } + + public func search(_ word: String) -> Bool { + var current = self.root + for letter in word { + if let currentNode = current.children[String(letter)] { + current = currentNode + } else { + return false + } + } + return current.isWord + } + + public func startsWith(_ prefix: String) -> Bool { + var current = self.root + for letter in prefix { + if let currentNode = current.children[String(letter)] { + current = currentNode + } else { + return false + } + } + return true + } +} diff --git a/Week 06/id_176/LeetCode_51_176.swift b/Week 06/id_176/LeetCode_51_176.swift new file mode 100644 index 000000000..6dabcd2bf --- /dev/null +++ b/Week 06/id_176/LeetCode_51_176.swift @@ -0,0 +1,45 @@ +class Solution { + func solveNQueens(_ n: Int) -> [[String]] { + var res = [[String]]() + let row = [Character](repeating:".", count: n) + var board = [[Character]](repeating: row, count: n) + dfs(&board, &res, 0) + return res + } + + + func dfs(_ board:inout [[Character]], _ res: inout [[String]], _ col: Int){ + if col == board.count{ + res.append(build(board)); + return + } + + for i in 0.. [String]{ + var res = [String]() + for row in board{ + res.append(String(row)) + } + return res + } + + func valid(_ board:[[Character]], _ x:Int, _ y: Int) -> Bool{ + for i in 0.. None: + """ + Inserts a word into the trie. + """ + node = self.root + for char in word: + # if char not in node: 没必要加这个判断 如果存在 获取分支 继续往下循环 如果不存在 新建分支 + node = node.setdefault(char,{}) + node[self.end_of_word] = self.end_of_word + + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week 06/id_181/LeetCode_36_181.py b/Week 06/id_181/LeetCode_36_181.py new file mode 100644 index 000000000..96a5e6ee9 --- /dev/null +++ b/Week 06/id_181/LeetCode_36_181.py @@ -0,0 +1,24 @@ +class Solution: + def isValidSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: bool + """ + rows = [{} for i in range(9)] + columns = [{} for i in range(9)] + boxes = [{} for i in range(9)] + + for i in range(9): + for j in range(9): + num = board[i][j] + if num != '.': + num = int(num) + box_index = (i // 3 ) * 3 + j // 3 + + rows[i][num] = rows[i].get(num, 0) + 1 + columns[j][num] = columns[j].get(num, 0) + 1 + boxes[box_index][num] = boxes[box_index].get(num, 0) + 1 + + if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1: + return False + return True diff --git a/Week 06/id_181/NOTE.md b/Week 06/id_181/NOTE.md index a6321d6e2..84dc80665 100644 --- a/Week 06/id_181/NOTE.md +++ b/Week 06/id_181/NOTE.md @@ -1,4 +1,62 @@ # NOTE +## trie 字典树 +> Trie 树只是不适合精确匹配查找,这种问题更适合用散列表或者红黑树来解决。Trie 树比较适合的是查找前缀匹配的字符串 + + ```py + class Trie(object): + def __init__(self): + self.root = {} + self.end_of_word ="#" + def insert(self,word): + node = self.root + for char in word: + node = node.setdefault(char,{}) # node = {} + node[self.end_of_word] = self.end_of_end #{'#':'#'} + + def search(self,word): + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + def startsWith(self,prefix): + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + ``` + +## 并查集 + +makeset(s):建立一个新的并查集,其中包含s个单元素集合 + +unionSet(x,y) x y 所在的集合合并,x、y所在的集合不能相交 + +find(x) 找打x所在的集合的代表,改操作用于判断两个元素是否位于同一个集合 + +```py +def int(p): + p = [for i in range(n)] + +def union(self,p,i,j): + p1 = self.parent(p,i) + p2 = self.parent(p,j) + p[p1] = p2 + +def parent(self,p,i): + root = i + while p[root] !=root: + root = p[root] + + while p[i] !=i: + x=i + i=p[i] + p[x] = root + +``` diff --git a/Week 06/id_196/LeetCode_200_196.py b/Week 06/id_196/LeetCode_200_196.py new file mode 100644 index 000000000..d80d83790 --- /dev/null +++ b/Week 06/id_196/LeetCode_200_196.py @@ -0,0 +1,68 @@ +#给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 +# +# 示例 1: +# +# 输入: +#11110 +#11010 +#11000 +#00000 +# +#输出: 1 +# +# +# 示例 2: +# +# 输入: +#11000 +#11000 +#00100 +#00011 +# +#输出: 3 +# +# Related Topics 深度优先搜索 广度优先搜索 并查集 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + f = {} + + def find(x): + f.setdefault(x, x) + if f[x] != x: + f[x] = find(f[x]) + return f[x] + + def union(x, y): + f[find(x)] = find(y) + + if not grid: return 0 + row = len(grid) + col = len(grid[0]) + + for i in range(row): + for j in range(col): + if grid[i][j] == "1": + for x, y in [[-1, 0], [0, -1]]: + tmp_i = i + x + tmp_j = j + y + if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1": + union(tmp_i * col + tmp_j, i * col + j) + # print(f) + res = set() + for i in range(row): + for j in range(col): + if grid[i][j] == "1": + res.add(find((i * col + j))) + return len(res) + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_196/LeetCode_208_196.py b/Week 06/id_196/LeetCode_208_196.py new file mode 100644 index 000000000..1e830e4f6 --- /dev/null +++ b/Week 06/id_196/LeetCode_208_196.py @@ -0,0 +1,78 @@ +#实现一个 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 设计 字典树 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Trie: + def __init__(self): + """ + Initialize your data structure here. + """ + self.lookup = {} + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + tree[a] = {} + tree = tree[a] + # 单词结束标志 + tree["#"] = "#" + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + return False + tree = tree[a] + if "#" in tree: + return True + return False + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + tree = self.lookup + for a in prefix: + if a not in tree: + return False + tree = tree[a] + return True + + + + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_196/LeetCode_212_196.py b/Week 06/id_196/LeetCode_212_196.py new file mode 100644 index 000000000..88d8a01ad --- /dev/null +++ b/Week 06/id_196/LeetCode_212_196.py @@ -0,0 +1,72 @@ +#给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +# +# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 +# +# 示例: +# +# 输入: +#words = ["oath","pea","eat","rain"] and board = +#[ +# ['o','a','a','n'], +# ['e','t','a','e'], +# ['i','h','k','r'], +# ['i','f','l','v'] +#] +# +#输出: ["eat","oath"] +# +# 说明: +#你可以假设所有输入都由小写字母 a-z 组成。 +# +# 提示: +# +# +# 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +# 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 +# +# Related Topics 字典树 回溯算法 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + trie = {} + for word in words: + t = trie + for w in word: + t = t.setdefault(w, {}) + t["end"] = 1 + # print(trie) + res = [] + row = len(board) + col = len(board[0]) + + def dfs(i, j, trie, s): + # print(i, j, trie, s) + c = board[i][j] + if c not in trie: return + trie = trie[c] + if "end" in trie and trie["end"] == 1: + res.append(s + c) + trie["end"] = 0 # 防止重复数组加入 + board[i][j] = "#" + for x, y in [[-1, 0], [1, 0], [0, 1], [0, -1]]: + tmp_i = x + i + tmp_j = y + j + if 0 <= tmp_i < row and 0 <= tmp_j < col and board[tmp_i][tmp_j] != "#": + dfs(tmp_i, tmp_j, trie, s + c) + board[i][j] = c + + for i in range(row): + for j in range(col): + dfs(i, j, trie, "") + return res + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_196/LeetCode_773_196.py b/Week 06/id_196/LeetCode_773_196.py new file mode 100644 index 000000000..bbcddbcd6 --- /dev/null +++ b/Week 06/id_196/LeetCode_773_196.py @@ -0,0 +1,73 @@ +#在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示. +# +# 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换. +# +# 最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。 +# +# 给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。 +# +# 示例: +# +# +#输入:board = [[1,2,3],[4,0,5]] +#输出:1 +#解释:交换 0 和 5 ,1 步完成 +# +# +# +#输入:board = [[1,2,3],[5,4,0]] +#输出:-1 +#解释:没有办法完成谜板 +# +# +# +#输入:board = [[4,1,2],[5,0,3]] +#输出:5 +#解释: +#最少完成谜板的最少移动次数是 5 , +#一种移动路径: +#尚未移动: [[4,1,2],[5,0,3]] +#移动 1 次: [[4,1,2],[0,5,3]] +#移动 2 次: [[0,1,2],[4,5,3]] +#移动 3 次: [[1,0,2],[4,5,3]] +#移动 4 次: [[1,2,0],[4,5,3]] +#移动 5 次: [[1,2,3],[4,5,0]] +# +# +# +#输入:board = [[3,2,4],[1,5,0]] +#输出:14 +# +# +# 提示: +# +# +# board 是一个如上所述的 2 x 3 的数组. +# board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列. +# +# Related Topics 广度优先搜索 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def slidingPuzzle(self, board): + """ + :type board: List[List[int]] + :rtype: int + """ + queue = collections.deque([(start, 0)]) + seen = {start} + while queue: + node, depth = queue.popleft() + if node == target: return depth + for nei in neighbors(node): + if nei not in seen: + seen.add(nei) + queue.append((nei, depth + 1)) + + + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_201/LeetCode_208_Trie b/Week 06/id_201/LeetCode_208_Trie new file mode 100644 index 000000000..9a2eeeabc --- /dev/null +++ b/Week 06/id_201/LeetCode_208_Trie @@ -0,0 +1,48 @@ + + +public class LeetCode_208_Trie { + private TrieNode root; + + public LeetCode_208_Trie() { + root = new TrieNode(); + } + + public void insert(String word) { + char ch; + TrieNode current = root; + for (int i = 0; i < word.length(); ++i) { + ch = word.charAt(i); + if (!current.containsKey(word.charAt(i))) { + current.put(ch, new TrieNode()); + } + current = current.get(ch); + } + current.setEnd(); + } + + public boolean search(String word) { + char ch; + TrieNode current = root; + for (int i = 0; i < word.length(); ++i) { + ch = word.charAt(i); + if (!current.containsKey(word.charAt(i))) { + return false; + } + current = current.get(ch); + } + return current.isEnd(); + } + + public boolean startsWith(String prefix) { + char ch; + TrieNode current = root; + for (int i = 0; i < prefix.length(); ++i) { + ch = prefix.charAt(i); + if (!current.containsKey(prefix.charAt(i))) { + return false; + } + current = current.get(ch); + } + return true; + } +} diff --git a/Week 06/id_201/LeetCode_212_FindWords b/Week 06/id_201/LeetCode_212_FindWords new file mode 100644 index 000000000..b23fe9d60 --- /dev/null +++ b/Week 06/id_201/LeetCode_212_FindWords @@ -0,0 +1,45 @@ + +import com.sun.xml.internal.ws.encoding.HasEncoding; + +import java.util.*; + +public class LeetCode_212_FindWords { + + /** + * 回溯 DFS + * @param board + * @param words + * @return + */ + public List findWords(char[][] board, String[] words) { + List wordList = new ArrayList(); + HashSet wordSet = new HashSet(); + boolean[][] visited = new boolean[board.length][board[0].length]; + int maxLen = 0; + for (String word: words) { + wordSet.add(word); + if (word.length() > maxLen) + maxLen = word.length(); + } + for (int i = 0; i < board.length; ++i) { + for (int j = 0; j < board[0].length; ++j) { + searchWord("", i, j, board, wordSet, wordList, visited, maxLen); + } + } + return wordList; + } + + public void searchWord(String s, int ir, int ic, char[][] board, HashSet wordSet, List wordList, boolean[][] visited, int maxLen) { + if (ir < 0 || ir >= board.length || ic < 0 || ic > board[0].length - 1 || visited[ir][ic] || s.length() > maxLen) + return; + String str = new StringBuffer(s).append(board[ir][ic]).toString(); + if (wordSet.contains(str)) + wordList.add(str); + visited[ir][ic] = true; + int[][] direction = {{0, 0, 1, -1}, {1, -1, 0, 0}}; + for (int i = 0; i < direction[0].length; ++i) { + searchWord(str, ir + direction[0][i], ic + direction[1][i] , board , wordSet, wordList, visited, maxLen); + } + visited[ir][ic] = false; + } +} diff --git a/Week 06/id_216/Week06.java b/Week 06/id_216/Week06.java new file mode 100644 index 000000000..7d733170b --- /dev/null +++ b/Week 06/id_216/Week06.java @@ -0,0 +1,125 @@ +import java.util.Arrays; + +public class Week06 { + + public Week06() { + + } + + //547 + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } + + //200 + public int numIslands(char[][] grid) { + + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + IslandFind islandFind = new IslandFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r - 1][c] == '1') { + islandFind.union(r * nc + c, (r - 1) * nc + c); + } + if (r + 1 < nr && grid[r + 1][c] == '1') { + islandFind.union(r * nc + c, (r + 1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c - 1] == '1') { + islandFind.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c + 1] == '1') { + islandFind.union(r * nc + c, r * nc + c + 1); + } + } + } + } + + return islandFind.getCount(); + } + + class IslandFind { + int count; // # of connected components + int[] parent; + int[] rank; + + public IslandFind(char[][] grid) { // for problem 200 + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { // path compression + if (parent[i] != i) parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { // union with rank + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; + rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + + +} diff --git a/Week 06/id_241/LeetCode_127_241.java b/Week 06/id_241/LeetCode_127_241.java new file mode 100644 index 000000000..6ac86dbcb --- /dev/null +++ b/Week 06/id_241/LeetCode_127_241.java @@ -0,0 +1,143 @@ +import java.util.*; +/** + * 单词接龙 + */ +class Solution { + + /** + * 单词接龙(228ms)BFS + */ + public int ladderLength2(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord) || beginWord.equals(endWord)) return 0; + wordList.add(beginWord); + LinkedList queue = new LinkedList<>(); + queue.addLast(endWord); + int level = 1, listSize = wordList.size(); + while (!queue.isEmpty()) { + level++; + int size = queue.size(); + for (int i = 0; i < size; i++) { + String pop = queue.pollFirst(); + for (int j = 0; j < listSize; j++) { + String str = wordList.get(j); + if (!str.equals("") && isOneDiff(str, pop)) { + if (str.equals(beginWord)) return level; + queue.addLast(str); + wordList.set(j, ""); + } + } + } + } + return 0; + } + + private boolean isOneDiff(String a, String b) { + int count = 0; + for (int i = 0; i < a.length(); i++) { + if (a.charAt(i) != b.charAt(i)) count++; + if (count > 1) return false; + } + return true; + } + + /** + * 单词接龙(48ms)BFS + * 空间换时间 + */ + public int ladderLength3(String beginWord, String endWord, List wordList) { + int len = beginWord.length(); + HashMap> map = new HashMap<>(); + wordList.forEach(word -> { + for (int i = 0; i < len; i++) { + String newWord = word.substring(0, i) + "*" + word.substring(i + 1); + if (map.containsKey(newWord)) map.get(newWord).add(word); + else { + List l = new ArrayList<>(); + l.add(word); + map.put(newWord, l); + } + } + }); + LinkedList queue = new LinkedList<>(); + HashSet set = new HashSet<>(); + int level = 1; + queue.addLast(beginWord); + while (!queue.isEmpty()) { + level++; + int size = queue.size(); + for (int i = 0; i < size; i++) { + String word = queue.removeFirst(); + for (int j = 0; j < len; j++) { + String newWord = word.substring(0, j) + "*" + word.substring(j + 1); + for (String str : map.getOrDefault(newWord, new ArrayList<>())) { + if (str.equals(endWord)) return level; + if (!set.contains(str)) { + queue.addLast(str); + set.add(str); + } + } + } + } + } + return 0; + } + + /** + * 单词接龙(30ms) 双向BFS + * 空间换时间 + */ + private HashMap> hp = new HashMap<>(); + + public int ladderLength4(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; + int len = beginWord.length(); + wordList.forEach(word -> { + for (int i = 0; i < len; i++) { + String newWord = word.substring(0, i) + "*" + word.substring(i + 1); + if (hp.containsKey(newWord)) hp.get(newWord).add(word); + else { + List l = new ArrayList<>(); + l.add(word); + hp.put(newWord, l); + } + } + }); + LinkedList> beginQueue = new LinkedList<>(); + LinkedList> endQueue = new LinkedList<>(); + beginQueue.addLast(new Pair<>(beginWord, 1)); + endQueue.addLast(new Pair<>(endWord, 1)); + + HashMap beginSet = new HashMap<>(); + HashMap endSet = new HashMap<>(); + beginSet.put(beginWord, 1); + endSet.put(endWord, 1); + + while (!beginQueue.isEmpty() && !endQueue.isEmpty()) { + int r1 = ladderLength4Helper(beginQueue, beginSet, endSet, len); + if (r1 > -1) return r1; + int r2 = ladderLength4Helper(endQueue, endSet, beginSet, len); + if (r2 > -1) return r2; + } + return 0; + } + + private int ladderLength4Helper(LinkedList> queue, + HashMap set, + HashMap otherSet, + int len) { + Pair pair = queue.removeFirst(); + String word = pair.getKey(); + int level = pair.getValue(); + for (int j = 0; j < len; j++) { + String newWord = word.substring(0, j) + "*" + word.substring(j + 1); + for (String str : hp.getOrDefault(newWord, new ArrayList<>())) { + if (otherSet.containsKey(str)) return level + otherSet.get(str); + if (!set.containsKey(str)) { + queue.addLast(new Pair<>(str, level + 1)); + set.put(str, level + 1); + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week 06/id_241/LeetCode_208_241.java b/Week 06/id_241/LeetCode_208_241.java new file mode 100644 index 000000000..e21b16591 --- /dev/null +++ b/Week 06/id_241/LeetCode_208_241.java @@ -0,0 +1,41 @@ +import java.util.*; +/** + * 实现 Trie (前缀树) + */ +class Trie { + + private Trie[] node; + private boolean isEnd; + + public Trie() { + this.node = new Trie[26]; + } + + public void insert(String word) { + Trie curr = this; + for (char w : word.toCharArray()) { + if (curr.node[w - 'a'] == null) curr.node[w - 'a'] = new Trie(); + curr = curr.node[w - 'a']; + } + curr.isEnd = true; + } + + public boolean search(String word) { + Trie curr = searchPrefix(word); + return curr != null && curr.isEnd; + } + + public boolean startsWith(String prefix) { + return searchPrefix(prefix) != null; + } + + private Trie searchPrefix(String word) { + char[] arr = word.toCharArray(); + Trie curr = this; + for (char w : arr) { + if (curr == null) break; + curr = curr.node[w - 'a']; + } + return curr; + } +} \ No newline at end of file diff --git a/Week 06/id_241/LeetCode_212_241.java b/Week 06/id_241/LeetCode_212_241.java new file mode 100644 index 000000000..62086b625 --- /dev/null +++ b/Week 06/id_241/LeetCode_212_241.java @@ -0,0 +1,51 @@ +import java.util.*; +/** + * 单词搜索 II + */ +class Solution { + public List findWords(char[][] board, String[] words) { + HashSet result = new HashSet<>(); + Trie trie = new Trie(); + for (String word : words) trie.insert(word); + int m = board.length, n = board[0].length; + for (int i = 0; i < m; i++) + for (int j = 0; j < n; j++) + findWordsHelper(i, j, trie, result, "", board, m, n); + return new ArrayList<>(result); + } + + private void findWordsHelper(int i, int j, Trie trie, HashSet result, String s, char[][] board, int ml, int nl) { + if (i < 0 || i > ml - 1 || j < 0 || j > nl - 1 || board[i][j] == '#') return; + s += board[i][j]; + trie = trie.node[board[i][j] - 'a']; + if (trie == null) return; + if (trie.isEnd) result.add(s); + int[] m = new int[]{-1, 1, 0, 0}, n = new int[]{0, 0, -1, 1}; + for (int c = 0; c < 4; c++) { + char tmp = board[i][j]; + board[i][j] = '#'; + findWordsHelper(i + m[c], j + n[c], trie, result, s, board, ml, nl); + board[i][j] = tmp; + } + } + + static class Trie { + + private Trie[] node; + private boolean isEnd; + + public Trie() { + this.node = new Trie[26]; + } + + public void insert(String word) { + Trie curr = this; + for (char w : word.toCharArray()) { + if (curr.node[w - 'a'] == null) curr.node[w - 'a'] = new Trie(); + curr = curr.node[w - 'a']; + } + curr.isEnd = true; + } + + } +} \ No newline at end of file diff --git a/Week 06/id_241/LeetCode_36_241.java b/Week 06/id_241/LeetCode_36_241.java new file mode 100644 index 000000000..9e7d60f3a --- /dev/null +++ b/Week 06/id_241/LeetCode_36_241.java @@ -0,0 +1,27 @@ +import java.util.*; +/** + * 有效的数独 + */ +class Solution { + public boolean isValidSudoku(char[][] board) { + Character[][] column = new Character[9][9]; + Character[][] sub = new Character[9][9]; + Character[] row = new Character[9]; + int m = board.length, n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + char num = board[i][j]; + if (num == '.') continue; + if (row[num - 49] == null) row[num - 49] = num; + else return false; + if (column[j][num - 49] == null) column[j][num - 49] = num; + else return false; + int subNum = (i / 3) * 3 + j / 3; + if (sub[subNum][num - 49] == null) sub[subNum][num - 49] = num; + else return false; + } + row = new Character[9]; + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_241/LeetCode_37_241.java b/Week 06/id_241/LeetCode_37_241.java new file mode 100644 index 000000000..b4a8670c5 --- /dev/null +++ b/Week 06/id_241/LeetCode_37_241.java @@ -0,0 +1,52 @@ +import java.util.*; +/** + * 解数独 + */ +class Solution { + private Character[][] column = new Character[9][9]; + private Character[][] sub = new Character[9][9]; + private Character[][] row = new Character[9][9]; + + public void solveSudoku(char[][] board) { + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + int subNum = (i / 3) * 3 + j / 3; + if (num != '.') { + row[i][num - 49] = num; + column[j][num - 49] = num; + sub[subNum][num - 49] = num; + } + } + } + solveSudokuHelper(board); + } + + private boolean solveSudokuHelper(char[][] board) { + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + if (num == '.') { + int subNum = (i / 3) * 3 + j / 3; + for (char k = '1'; k <= '9'; k++) { + if (row[i][k - 49] != null || column[j][k - 49] != null || sub[subNum][k - 49] != null) + continue; + board[i][j] = k; + row[i][k - 49] = k; + column[j][k - 49] = k; + sub[subNum][k - 49] = k; + if (solveSudokuHelper(board)) return true; + else { + row[i][k - 49] = null; + column[j][k - 49] = null; + sub[subNum][k - 49] = null; + board[i][j] = '.'; + } + } + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_241/LeetCode_547_241.java b/Week 06/id_241/LeetCode_547_241.java new file mode 100644 index 000000000..0023b7a34 --- /dev/null +++ b/Week 06/id_241/LeetCode_547_241.java @@ -0,0 +1,50 @@ +import java.util.*; +/** + * 朋友圈 + */ +class Solution { + + public int findCircleNum(int[][] M) { + int len = M.length; + UnionFind unionFind = new UnionFind(len); + for (int i = 0; i < len - 1; i++) { + for (int j = i + 1; j < len; j++) { + if (M[i][j] == 1) unionFind.union(i, j); + } + } + return unionFind.count; + } + + /** + * 并查集实现 + */ + static class UnionFind { + + private int count; + private int[] arr; + + UnionFind(int n) { + this.count = n; + this.arr = new int[n]; + while (--n >= 0) arr[n] = n; + } + + int find(int p) { + /*while (p != arr[p]) { + arr[p] = arr[arr[p]]; + p = arr[p]; + }*/ + return arr[p]; + } + + void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + arr[rootP] = rootQ; + count--; + for (int i = 0; i < arr.length; i++) + if (arr[i] == rootP) arr[i] = rootQ; + } + } +} \ No newline at end of file diff --git a/Week 06/id_246/LeetCode_200_246.py b/Week 06/id_246/LeetCode_200_246.py new file mode 100644 index 000000000..d90753546 --- /dev/null +++ b/Week 06/id_246/LeetCode_200_246.py @@ -0,0 +1,100 @@ +''' +number-of-islands_200 + +给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + +示例 1: + +输入: +11110 +11010 +11000 +00000 + +输出: 1 +''' + +#并查集 + +def numIslands_1(grid): + f = {} + + def find(x): + f.setdefault(x,x) + if f[x] != x: + f[x] = find(f[x]) + return f[x] + + def union(x,y): + f[find(x)] = find(y) + + if not grid: return 0 + row = len(grid) + col = len(grid[0]) + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + for x, y in [[-1,0], [0,-1]]: + tmp_i = i + x + tmp_j = j + y + if 0 <= tmp_i < row and 0 <= tmp_j < col and \ + grid[tmp_i][tmp_j] == '1': + union(tmp_i*row+tmp_j, i*row+j) + res = set() + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + res.add(find((i*row + j))) + +#dfs +def numIslands_2(grid): + if not grid: return 0 + row = len(grid) + col = len(grid[0]) + cnt = 0 + + def dfs(i,j): + grid[i][j] = '0' + for x, y in [[-1,0], [1,0], [0,-1],[0,1]]: + tmp_i = i + x + tmp_j = j + y + if 0 <= tmp_i < row and 0 <= tmp_j < col and \ + grid[tmp_i][tmp_j] == '1': + dfs(tmp_i, tmp_j) + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + dfs(i,j) + cnt += 1 + return cnt + +#bfs +def numIslands_3(grid): + from collections import deque + if not grid: return 0 + row = len(grid) + col = len(grid[0]) + cnt = 0 + + def bfs(i,j): + queue = deque() + queue.appendleft((i,j)) + grid[i][j] = "0" + while queue: + i, j = queue.pop() + for x, y in [[-1,0], [1,0], [0,-1],[0,1]]: + tmp_i = i + x + tmp_j = j + y + if 0 <= tmp_i < row and 0 <= tmp_j < col and \ + grid[tmp_i][tmp_j] == '1': + grid[tmp_i][tmp_j] = '0' + queue.appendleft((tmp_i, tmp_j)) + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + bfs(i,j) + cnt += 1 + return cnt \ No newline at end of file diff --git a/Week 06/id_246/LeetCode_208_246.py b/Week 06/id_246/LeetCode_208_246.py new file mode 100644 index 000000000..3c3ec8bac --- /dev/null +++ b/Week 06/id_246/LeetCode_208_246.py @@ -0,0 +1,74 @@ +''' +implement-trie-prefix-tree_208 + +实现一个 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 构成的。 +保证所有输入均为非空字符串。 +''' + +#1 +class Trie(object): + def __init__(self): + self.root = {} + + def insert(self, word): + node = self.root + for char in word: + if char in node.keys(): + node = node[char] + else: + node[char] = {} + node = node[char] + node['is_word'] = True + + def search(self, word): + node = self.root + for char in word: + if char in node.keys(): + node = node[char] + else: + return False + if 'is_word' in node.keys(): + return True + else: + return False + + def startsWith(self, prefix): + node = self.root + for char in prefix: + if char in node.keys(): + node = node[char] + else: + return False + return True + + #2 +from functools import reduce +import collections + +class Trie(object): + def __init__(self): + T = lambda: collections.defaultdict(T) + self.root = T() + + def insert(self, word): + reduce(dict.__getitem__, word, self.root)['#'] = True + + def search(self, word): + return '#' in reduce(lambda cur, c: cur.get(c, {}), word, self.root) + + def startsWith(self, prefix): + return bool(reduce(lambda cur, c: cur.get(c, {}), prefix, self.root)) \ No newline at end of file diff --git a/Week 06/id_246/LeetCode_212_246.py b/Week 06/id_246/LeetCode_212_246.py new file mode 100644 index 000000000..785051463 --- /dev/null +++ b/Week 06/id_246/LeetCode_212_246.py @@ -0,0 +1,71 @@ +''' +word-search-ii_212 + +给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 + +单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 + +示例: + +输入: +words = ["oath","pea","eat","rain"] and board = +[ + ['o','a','a','n'], + ['e','t','a','e'], + ['i','h','k','r'], + ['i','f','l','v'] +] + +输出: ["eat","oath"] +说明: +你可以假设所有输入都由小写字母 a-z 组成。 + +提示: + +你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 + +''' + +#1 +dx = [-1,1,0,0] +dy = [0,0,-1,1] +END_OF_WORD = "#" + +class Solution(object): + + def findWords(self, board, words): + if not board or not board[0]: return [] + if not words: return [] + self.result = set() + + #构建trie + root = collections.defaultdict() + for word in words: + node = root + for char in word: + node = node.setdefault(char, collections.defaultdict()) + node[END_OF_WORD] = END_OF_WORD + + self.m, self.n = len(board), len(board[0]) + for i in range(self.m): + for j in range(self.n): + if board[i][j] in root: + self._dfs(board, i, j, "", root) + return list(self.result) + + + def _dfs(self, board, i, j, cur_word, cur_dict): + cur_word += board[i][j] + cur_dict = cur_dict[board[i][j]] + if END_OF_WORD in cur_dict: + self.result.add(cur_word) + tmp, board[i][j] = board[i][j], '@' + for k in range(4): + x, y = i + dx[k], j + dy[k] + if 0 <= x < self.m and 0 <= y < self.n \ + and board[x][y] != '@' and board[x][y] in cur_dict: + self._dfs(board, x, y, cur_word, cur_dict) + board[i][j] = tmp + + diff --git a/Week 06/id_246/LeetCode_22_246.py b/Week 06/id_246/LeetCode_22_246.py new file mode 100644 index 000000000..ee65194ba --- /dev/null +++ b/Week 06/id_246/LeetCode_22_246.py @@ -0,0 +1,29 @@ +''' +generate-parentheses_22 + +给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + +例如,给出 n = 3,生成结果为: + +[ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" +] +''' + +def generateParenthesis(N): + ans = [] + def backtrack(S='', left=0, right=0): + if len(S) == 2*N: + ans.append(S) + return + if left < N: + backtrack(S+'(', left+1, right) + if right < left: + backtrack(S+')', left, right+1) + + backtrack() + return ans \ No newline at end of file diff --git a/Week 06/id_246/LeetCode_36_246.py b/Week 06/id_246/LeetCode_36_246.py new file mode 100644 index 000000000..7ddcec758 --- /dev/null +++ b/Week 06/id_246/LeetCode_36_246.py @@ -0,0 +1,52 @@ +''' +valid-sudoku_36 + +判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 + +数字 1-9 在每一行只能出现一次。 +数字 1-9 在每一列只能出现一次。 +数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + +示例: +输入: +[ + ["5","3",".",".","7",".",".",".","."], + ["6",".",".","1","9","5",".",".","."], + [".","9","8",".",".",".",".","6","."], + ["8",".",".",".","6",".",".",".","3"], + ["4",".",".","8",".","3",".",".","1"], + ["7",".",".",".","2",".",".",".","6"], + [".","6",".",".",".",".","2","8","."], + [".",".",".","4","1","9",".",".","5"], + [".",".",".",".","8",".",".","7","9"] +] +输出: true + +说明: + +一个有效的数独(部分已被填充)不一定是可解的。 +只需要根据以上规则,验证已经填入的数字是否有效即可。 +给定数独序列只包含数字 1-9 和字符 '.' 。 +给定数独永远是 9x9 形式的。 +''' + +#哈希 +def isValidSudoku(board): + rows = [{} for i in range(9)] + columns = [{} for i in range(9)] + boxes = [{} for i in range(9)] + + for i in range(9): + for j in range(9): + num = board[i][j] + if num != '.': + num = int(num) + box_index = (i//3)*3 + j//3 + + rows[i][num] = rows[i].get(num, 0) + 1 + columns[j][num] = columns[j].get(num, 0) + 1 + boxes[box_index][num] = boxes[box_index].get(num, 0) + 1 + + if rows[i][num]>1 or columns[j][num]>1 or boxes[box_index][num]>1: + return False + return True \ No newline at end of file diff --git a/Week 06/id_246/LeetCode_51_246.py b/Week 06/id_246/LeetCode_51_246.py new file mode 100644 index 000000000..8c10556a9 --- /dev/null +++ b/Week 06/id_246/LeetCode_51_246.py @@ -0,0 +1,22 @@ +''' +n-queens_51 + +给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + +每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + +''' + +def solveNQueens(n): + def DFS(queens, xy_dif, xy_sum): + p = len(queens) + if p == n: + result.append(queens) + return None + for q in range(n): + if q not in queend and p-q not in xy_dif and p+q not in xy_sum: + DFS(queens+[q], xy_dif+[p-q], xy_sum+[p+q]) + + result = [] + DFS([],[],[]) + return [['.'*i + 'Q' + '.'*(n-i-1) for i in sol] for sol in result] diff --git a/Week 06/id_246/LeetCode_547_246.py b/Week 06/id_246/LeetCode_547_246.py new file mode 100644 index 000000000..cf3a631ea --- /dev/null +++ b/Week 06/id_246/LeetCode_547_246.py @@ -0,0 +1,96 @@ +''' +friend-circles_547 + +班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + +给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + +示例 1: + +输入: +[[1,1,0], + [1,1,0], + [0,0,1]] +输出: 2 +说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 +第2个学生自己在一个朋友圈。所以返回2。 +示例 2: + +输入: +[[1,1,0], + [1,1,1], + [0,1,1]] +输出: 1 +说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 +注意: + +N 在[1,200]的范围内。 +对于所有学生,有M[i][i] = 1。 +如果有M[i][j] = 1,则有M[j][i] = 1。 +''' + + +#1 +class Solution(object): + def findCircleNum_1(self, M): + parent = [-1]*len(M) + # 为各个集合的深度排序 + rank = dict() + # 只遍历左下部分 + for i in range(len(M)): + for j in range(i): + if M[i][j] == 1: + self.union(i,j,parent,rank) + ans = 0 + for i in parent: + if i == -1: + ans += 1 + return ans + + def findRoot(self, num, parent): + while parent[num] != -1: + num = parent[num] + return num + + def union(self, x, y, parent, rank): + if x == y: + return + x = self.findRoot(x, parent) + y = self.findRoot(y, parent) + rank_x = rank[x] if x in rank else 0 # 查询集合目前深度 + rank_y = rank[y] if y in rank else 0 + if x == y: + return + if rank_x > rank_y: + parent[y] = x + elif rank_x < rank_y: + parent[x] = y + else: + parent[x] = y + rank[y] = 1 + +#2 +import numpy as np + +def findCircleNum_2(M): + return len(set(map(tuple, (np.matrix(M, dtype='bool')**len(M)).A))) + + +#3 +def findCircleNum_3(M): + + n = len(M) + circles = {x: x for x in range(n)} + num = n + + def find(node): + if circles[node] == node: return node + root = find(circles[node]) + circles[node] = root + return root + + for i in range(n): + for j in range(i, n): + if i != j and M[i][j] == 1 and find(i) != find(j): + circles[find(i)] = find(j) + return len([x for x in circles if circles[x] == x]) \ No newline at end of file diff --git a/Week 06/id_246/NOTE.md b/Week 06/id_246/NOTE.md index a6321d6e2..166136c44 100644 --- a/Week 06/id_246/NOTE.md +++ b/Week 06/id_246/NOTE.md @@ -1,4 +1,26 @@ # NOTE - +【字典树】 +1. 优点:最大限度地减少无谓的字符串比较,查询效率比哈希表高。 +2. 核心思想: 空间换时间。 + +【并查集】 + +1. makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合。 +2. unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在的集合不相交,如果相交则不合并。 +3. find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元 +素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。 + +【高级搜索】 + +1. 剪枝 +2. 双向BFS +3. A* + +【高级树】 + +1. 平衡二叉搜索树 +2. 每个结点存 balance factor = {-1, 0, 1} +3. 四种旋转操作 +4. 不足:结点需要存储额外信息、且调整次数频繁 \ No newline at end of file diff --git a/Week 06/id_251/LeetCode_102_251.py b/Week 06/id_251/LeetCode_102_251.py new file mode 100644 index 000000000..0a44809a9 --- /dev/null +++ b/Week 06/id_251/LeetCode_102_251.py @@ -0,0 +1,98 @@ +# 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 +# +# 例如: +# 给定二叉树: [3,9,20,null,null,15,7], +# +# 3 +# / \ +# 9 20 +# / \ +# 15 7 +# +# +# 返回其层次遍历结果: +# +# [ +# [3], +# [9,20], +# [15,7] +# ] +# +# Related Topics 树 广度优先搜索 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +""" +1、 BFS 队列实现 +2、 递归实现 +""" + + +class Solution(object): + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + if not root: + return [] + res = [] + queue = [root] + while queue: + level_vals = [] + for _ in range(len(queue)): + node = queue.pop(0) + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + level_vals.append(node.val) + res.append(level_vals) + return res + + +# bfs简洁写法 +class Solution2(object): + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + res, level = [], [root] + while root and level: + res.append([node.val for node in level]) + level = [kid for n in level for kid in (n.left, n.right) if kid] + return res + + +class Solution3(object): + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + levels = [] + if not root: + return levels + + def helper(node, level): + # level层数下表从0开始,不需要加一层的情况下level = len(levels) - 1 + if len(levels) == level: + levels.append([]) + + levels[level].append(node.val) + + if node.left: + helper(node.left, level + 1) + if node.right: + helper(node.right, level + 1) + + helper(root, 0) + return levels diff --git a/Week 06/id_251/LeetCode_208_251.py b/Week 06/id_251/LeetCode_208_251.py new file mode 100644 index 000000000..05125be9d --- /dev/null +++ b/Week 06/id_251/LeetCode_208_251.py @@ -0,0 +1,86 @@ +# 实现一个 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 设计 字典树 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Trie(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.end_of_word = '#' + + def insert(self, word): + """ + Inserts a word into the trie. + :type word: str + :rtype: None + """ + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + + def search(self, word): + """ + Returns if the word is in the trie. + :type word: str + :rtype: bool + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix): + """ + Returns if there is any word in the trie that starts with the given prefix. + :type prefix: str + :rtype: bool + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + +if __name__ == '__main__': + t = Trie() + typ = { + 'Trie': t, + 'insert': t.insert, + 'search': t.search, + 'startsWith': t.startsWith + } + funcs = ["Trie", "insert", "search", "search", "startsWith", "insert", "search"] + args = [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]] + correct_res = [None, None, True, False, True, None, True] + # res = [] + # for func, arg in zip(funcs, args): + # res.append(typ[func](arg[0]) if arg else None) + res = [typ[func](arg[0]) if arg else None for func, arg in zip(funcs, args)] + print(res == correct_res) diff --git a/Week 06/id_251/LeetCode_212_251.py b/Week 06/id_251/LeetCode_212_251.py new file mode 100644 index 000000000..f3102046b --- /dev/null +++ b/Week 06/id_251/LeetCode_212_251.py @@ -0,0 +1,116 @@ +# 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +# +# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 +# +# 示例: +# +# 输入: +# words = ["oath","pea","eat","rain"] and board = +# [ +# ['o','a','a','n'], +# ['e','t','a','e'], +# ['i','h','k','r'], +# ['i','f','l','v'] +# ] +# +# 输出: ["eat","oath"] +# +# 说明: +# 你可以假设所有输入都由小写字母 a-z 组成。 +# +# 提示: +# +# +# 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +# 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 +# +# Related Topics 字典树 回溯算法 + +""" +1. words 遍历 --> board search + O(N*m*n*4^k) +2. trie +a. all words --> Trie 构建起 prefix +b board, DFS +O(N*k + m*n*4^k) = O(m*n*4^k) +""" + +# leetcode submit region begin(Prohibit modification and deletion) + +from collections import defaultdict + +# 四联通构建 +dx = [-1, 1, 0, 0] +dy = [0, 0, -1, 1] +END_FO_WORD = "#" + + +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + if not board or not board[0]: return [] + if not words: return [] + self.result = set() + + # 构建trie + root = defaultdict() + for word in words: + node = root + for char in word: + node = node.setdefault(char, defaultdict()) + node[END_FO_WORD] = END_FO_WORD + + self.m, self.n = len(board), len(board[0]) + for i in range(self.m): + for j in range(self.n): + if board[i][j] in root: + self._dfs(board, i, j, '', root) + return list(self.result) + + def _dfs(self, board, i, j, cur_word, cur_dict): + cur_word += board[i][j] + cur_dict = cur_dict[board[i][j]] + if END_FO_WORD in cur_dict: + self.result.add(cur_word) + tmp, board[i][j] = board[i][j], '@' + for k in range(4): + x, y = i + dx[k], j + dy[k] + if 0 <= x < self.m and 0 <= y < self.n \ + and board[x][y] != '@' and board[x][y] in cur_dict: + self._dfs(board, x, y, cur_word, cur_dict) + board[i][j] = tmp + + +# trie 优秀题解 +class Solution2(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + trie = {} + for word in words: + node = trie + for char in word: + node = node.setdefault(char, {}) + node['#'] = True + + def bfs(i, j, node, cur_word, visited): + if '#' in node: # 已有字典树结束 + res.add(cur_word) + for di, dj in ((-1, 0), (1, 0), (0, -1), (0, 1)): + x, y = i + di, j + dj + if -1 < x < m and -1 < y < n and board[x][y] in node and (x, y) not in visited: + bfs(x, y, node[board[x][y]], cur_word + board[x][y], visited | {(x, y)}) + + res, m, n = set(), len(board), len(board[0]) + for i in range(m): + for j in range(n): + if board[i][j] in trie: + bfs(i, j, trie[board[i][j]], board[i][j], {(i, j)}) + return list(res) diff --git a/Week 02/id_251/LeetCode_22_251.py b/Week 06/id_251/LeetCode_22_251.py similarity index 76% rename from Week 02/id_251/LeetCode_22_251.py rename to Week 06/id_251/LeetCode_22_251.py index 939b0b7cc..0ee4ad214 100644 --- a/Week 02/id_251/LeetCode_22_251.py +++ b/Week 06/id_251/LeetCode_22_251.py @@ -13,8 +13,9 @@ # Related Topics 字符串 回溯算法 """ -1 暴力递归 -2 回溯递归 +1 暴力回溯递归 +2 回溯递归 剪枝 +3、 dp """ @@ -62,7 +63,8 @@ def generateParenthesis2(self, n): def _generate(self, left, right, n, s, res): # terminator - if left == right == n: + # left == right == n; left == n; right == n; len(s) == 2 * n 都可以 + if len(s) == 2 * n: res.append(s) return @@ -77,6 +79,21 @@ def _generate(self, left, right, n, s, res): # reverse states +class Solution3(object): + # 1 暴力递归 + def generateParenthesis(self, n): + """ + :type n: int + :rtype: List[str] + """ + dp = [[] for _ in range(n + 1)] + dp[0] = [''] + for i in range(n + 1): + for j in range(i): + dp[i] += ['({}){}'.format(x, y) for x in dp[j] for y in dp[i - j - 1]] + return dp[n] + + if __name__ == '__main__': n = 3 s = Solution() diff --git a/Week 06/id_251/LeetCode_36_251.py b/Week 06/id_251/LeetCode_36_251.py new file mode 100644 index 000000000..b5a3259e3 --- /dev/null +++ b/Week 06/id_251/LeetCode_36_251.py @@ -0,0 +1,84 @@ +# 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 +# +# +# 数字 1-9 在每一行只能出现一次。 +# 数字 1-9 在每一列只能出现一次。 +# 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 +# +# +# +# +# 上图是一个部分填充的有效的数独。 +# +# 数独部分空格内已填入了数字,空白格用 '.' 表示。 +# +# 示例 1: +# +# 输入: +# [ +# ["5","3",".",".","7",".",".",".","."], +# ["6",".",".","1","9","5",".",".","."], +# [".","9","8",".",".",".",".","6","."], +# ["8",".",".",".","6",".",".",".","3"], +# ["4",".",".","8",".","3",".",".","1"], +# ["7",".",".",".","2",".",".",".","6"], +# [".","6",".",".",".",".","2","8","."], +# [".",".",".","4","1","9",".",".","5"], +# [".",".",".",".","8",".",".","7","9"] +# ] +# 输出: true +# +# +# 示例 2: +# +# 输入: +# [ +#   ["8","3",".",".","7",".",".",".","."], +#   ["6",".",".","1","9","5",".",".","."], +#   [".","9","8",".",".",".",".","6","."], +#   ["8",".",".",".","6",".",".",".","3"], +#   ["4",".",".","8",".","3",".",".","1"], +#   ["7",".",".",".","2",".",".",".","6"], +#   [".","6",".",".",".",".","2","8","."], +#   [".",".",".","4","1","9",".",".","5"], +#   [".",".",".",".","8",".",".","7","9"] +# ] +# 输出: false +# 解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 +# 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 +# +# 说明: +# +# +# 一个有效的数独(部分已被填充)不一定是可解的。 +# 只需要根据以上规则,验证已经填入的数字是否有效即可。 +# 给定数独序列只包含数字 1-9 和字符 '.' 。 +# 给定数独永远是 9x9 形式的。 +# +# Related Topics 哈希表 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isValidSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: bool + """ + rows = [{} for _ in range(9)] + columns = [{} for _ in range(9)] + boxes = [{} for _ in range(9)] + + for i in range(9): + for j in range(9): + num = board[i][j] + if num != '.': + box_index = (i // 3) * 3 + j // 3 + + rows[i][num] = rows[i].get(num, 0) + 1 + columns[j][num] = columns[j].get(num, 0) + 1 + boxes[box_index][num] = boxes[box_index].get(num, 0) + 1 + + if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1: + return False + return True diff --git a/Week 06/id_251/LeetCode_51_251.py b/Week 06/id_251/LeetCode_51_251.py new file mode 100644 index 000000000..be21cd91e --- /dev/null +++ b/Week 06/id_251/LeetCode_51_251.py @@ -0,0 +1,96 @@ +# n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +# +# +# +# 上图为 8 皇后问题的一种解法。 +# +# 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 +# +# 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 +# +# 示例: +# +# 输入: 4 +# 输出: [ +# [".Q..", // 解法 1 +# "...Q", +# "Q...", +# "..Q."], +# +# ["..Q.", // 解法 2 +# "Q...", +# "...Q", +# ".Q.."] +# ] +# 解释: 4 皇后问题存在两个不同的解法。 +# +# Related Topics 回溯算法 +""" +1 回溯法 剪枝 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def solveNQueens(self, n): + """ + :type n: int + :rtype: List[List[str]] + """ + if n < 1: return [] + + self.result = [] + self.cols, self.pie, self.na = set(), set(), set() + self.DFS(n, 0, []) + return self._generate_result(n) + + def DFS(self, n, row, cur_state): + # recursion terminator + if row >= n: + self.result.append(cur_state) + return + + # current level! Do it ! + for col in range(n): + if col in self.cols or row + col in self.pie or row - col in self.na: + # go die! + continue + + # update the flags + self.cols.add(col) + self.pie.add(row + col) + self.na.add(row - col) + + self.DFS(n, row + 1, cur_state + [col]) + + # reverse states + self.cols.remove(col) + self.pie.remove(row + col) + self.na.remove(row - col) + + def _generate_result(self, n): + board = [] + for res in self.result: + for i in res: + board.append('.' * i + 'Q' + '.' * (n - i - 1)) + return [board[i: i + n] for i in range(0, len(board), n)] + + +# 回溯法优化写法 +class Solution1(object): + def solveNQueens(self, n): + """ + :type n: int + :rtype: List[List[str]] + """ + result = [] + self.dfs([], [], [], n, result) + return [['.' * i + 'Q' + '.' * (n - i - 1) for i in sol] for sol in result] + + def dfs(self, queens, xy_dif, xy_sum, n, result): + p = len(queens) + if p == n: + result.append(queens) + for q in range(n): + if q not in queens and p - q not in xy_dif and p + q not in xy_sum: + self.dfs(queens + [q], xy_dif + [p - q], xy_sum + [p + q], n, result) diff --git a/Week 06/id_251/LeetCode_547_251.py b/Week 06/id_251/LeetCode_547_251.py new file mode 100644 index 000000000..1d2db3168 --- /dev/null +++ b/Week 06/id_251/LeetCode_547_251.py @@ -0,0 +1,116 @@ +# 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 +# +# 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 +# +# 示例 1: +# +# +# 输入: +# [[1,1,0], +# [1,1,0], +# [0,0,1]] +# 输出: 2 +# 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 +# 第2个学生自己在一个朋友圈。所以返回2。 +# +# +# 示例 2: +# +# +# 输入: +# [[1,1,0], +# [1,1,1], +# [0,1,1]] +# 输出: 1 +# 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 +# +# +# 注意: +# +# +# N 在[1,200]的范围内。 +# 对于所有学生,有M[i][i] = 1。 +# 如果有M[i][j] = 1,则有M[j][i] = 1。 +# +# Related Topics 深度优先搜索 并查集 + +""" +1、DFS +2、BFS +3、UnionFind 并查集 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + N, visited, res = len(M), set(), 0 + for i in range(N): + if i not in visited: + self.dfs(M, visited, i) + res += 1 + return res + + def dfs(self, M, visited, node): + for i, num in enumerate(M[node]): + if num and i not in visited: + visited.add(i) + self.dfs(M, visited, i) + + +# bfs +class Solution2(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + N, visited, res = len(M), set(), 0 + for i in range(N): + if i not in visited: + queue = [i] + while queue: + p = queue.pop(0) + if p not in visited: + visited.add(p) + queue += [k for k, num in enumerate(M[p]) if num and k not in visited] + res += 1 + return res + + +# 并查集 +class UnionFind: + def __init__(self, n): + self.u = list(range(n)) + + def union(self, i, j): + p1, p2 = self.find(i), self.find(j) + self.u[p1] = p2 + + def find(self, i): + root = i + while self.u[root] != root: + root = self.u[root] + while self.u[i] != i: + self.u[i], i = root, self.u[i] + return root + + +class Solution3(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + N = len(M) + uf = UnionFind(N) + + for i in range(N): + for j in range(N): + if M[i][j] == 1: + uf.union(i, j) + return len(set([uf.find(i) for i in range(N)])) diff --git "a/Week 06/id_251/\345\271\266\346\237\245\351\233\206\344\273\243\347\240\201\346\250\241\346\235\277.py" "b/Week 06/id_251/\345\271\266\346\237\245\351\233\206\344\273\243\347\240\201\346\250\241\346\235\277.py" new file mode 100644 index 000000000..013da3e0c --- /dev/null +++ "b/Week 06/id_251/\345\271\266\346\237\245\351\233\206\344\273\243\347\240\201\346\250\241\346\235\277.py" @@ -0,0 +1,30 @@ +class UnionFind: + def __init__(self, n): + self.u = list(range(n)) + + def union(self, i, j): + p1 = self.find(i) + p2 = self.find(j) + self.u[p1] = p2 + + def find(self, i): + root = i + while self.u[root] != root: + root = self.u[root] + while self.u[i] != i: + self.u[i], i = root, self.u[i] + return root + + +if __name__ == '__main__': + uf = UnionFind(6) + uf.union(3, 0) + print(uf.u) + uf.union(4, 2) + print(uf.u) + uf.union(2, 1) + print(uf.u) + uf.union(4, 0) + print(uf.u) + uf.union(4, 0) + print(uf.u) diff --git a/Week 06/id_256/LeetCode_122_256.js b/Week 06/id_256/LeetCode_122_256.js new file mode 100644 index 000000000..cab9764e5 --- /dev/null +++ b/Week 06/id_256/LeetCode_122_256.js @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=122 lang=javascript + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + // 暴力法 似乎会超时 + // let valley = 0; //谷 + // let peak = 0; //峰 + // let maxprofit = 0; //最大利润 + // let i = 0; + // while(i < prices.length) { + // while(i < prices.length && prices[i] >= prices[i+1]) + // i++; + // valley = prices[i]; + // while(i < prices.length && prices[i] <= prices[i + 1]) + // i++; + // peak = prices[i]; + // maxprofit += (peak - valley); + // } + // return maxprofit; + // 方法二 + let maxprofit = 0; + for (let i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) + maxprofit += prices[i] - prices[i - 1]; + } + return maxprofit; + +}; +// @lc code=end + diff --git a/Week 06/id_256/LeetCode_126_256.js b/Week 06/id_256/LeetCode_126_256.js new file mode 100644 index 000000000..f0fd57ea5 --- /dev/null +++ b/Week 06/id_256/LeetCode_126_256.js @@ -0,0 +1,58 @@ +/* + * @lc app=leetcode.cn id=126 lang=javascript + * + * [126] 单词接龙 II + */ + +// @lc code=start +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {string[][]} + */ +var findLadders = function(beginWord, endWord, wordList) { + // 方案一 递归 + let res = []; + let temp = [beginWord]; + if(wordList.indexOf(endWord) < 0) return []; + findLadderHelper(beginWord, endWord, wordList, res, temp); + return res; + }; + let min = 10000; + let findLadderHelper = function(beginWord, endWord, wordList, res, temp) { + if(beginWord == endWord) { + if(min > temp.length) { + res.length = 0; + min = temp.length; + res.push([...temp]); + } else if(min == temp.length) { + res.push([...temp]); + } + return; + } + if(temp.length >= min){ + return; + } + for(let i = 0; i < wordList.length; i++) { + let currWord = wordList[i]; + if(temp.indexOf(currWord) >= 0) continue; + if(onlyOneDiff(currWord, beginWord)) { + temp.push(currWord); + findLadderHelper(currWord, endWord, wordList, res, temp); + temp.pop(); + } + } + } + let onlyOneDiff = function(word1, word2) { + let count = 0; + for (let i = 0; i < word1.length; i++) { + if (word1[i] != word2[i]) { + count++; + } + if (count > 1) break; + } + return count == 1; + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 06/id_256/LeetCode_200_256.js b/Week 06/id_256/LeetCode_200_256.js new file mode 100644 index 000000000..4fbcad8d4 --- /dev/null +++ b/Week 06/id_256/LeetCode_200_256.js @@ -0,0 +1,93 @@ +/* + * @lc app=leetcode.cn id=200 lang=javascript + * + * [200] 岛屿数量 + */ + +// @lc code=start +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + // 方案一:DFS + // if(!grid) return 0; + // let count = 0; + // let m = grid.length; + // if(m == 0) return 0; + // let n = grid[0].length; + // if(n == 0) return 0; + // for(let i = 0; i < grid.length; i++) { + // for(let j = 0; j < grid[i].length; j++) { + // if(grid[i][j] == "1") { + // count++; + // lankfill(i, j, grid); + // } + // } + // } + // return count; + // 方法二: 并查集 + let m = grid.length; + if(m == 0) return 0; + let n = grid[0].length; + if(n == 0) return 0; + let count = 0; + let parent = []; + let rank = []; + let find = (p) => { + if(p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + let union = (p, q) => { + let rootp = find(p); + let rootq = find(q); + if(rootp == rootq) return; + if(rank[rootp] > rank[rootq]) { + parent[rootq] = rootp; + }else if(rank[rootq] > rank[rootp]) { + parent[rootp] = rootq; + }else{ + parent[rootp] = rootq; + rank[rootq]++; + } + count --; + } + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] == 1) { + parent[i * n + j] = i * n + j; + count ++; + } + rank[i * n + j] = 0; + } + } + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] == 1) { + grid[i][j] = 0; + i-1>=0 && grid[i-1][j] == 1 && union(i*n + j,(i-1)*n + j); + j-1>=0 && grid[i][j-1] == 1 && union(i*n + j,i*n + j-1); + i+1= 0 && grid[i-1][j] == "1") lankfill(i-1, j, grid); +// if(j-1 >= 0 && grid[i][j-1] == "1") lankfill(i, j-1, grid); +// return; +// } +// @lc code=end + diff --git a/Week 06/id_256/LeetCode_208_256.js b/Week 06/id_256/LeetCode_208_256.js new file mode 100644 index 000000000..8e8de64a5 --- /dev/null +++ b/Week 06/id_256/LeetCode_208_256.js @@ -0,0 +1,75 @@ +/* + * @lc app=leetcode.cn id=208 lang=javascript + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +/** + * Initialize your data structure here. + */ +class TrieNode{ + constructor(){ + this.END = false; + this.children = {}; + } +} +let root = null; +var Trie = function() { + root = new TrieNode(); +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + let currNode = root; + for(let i = 0; i < word.length; i++) { + if(currNode.children[word[i]] == undefined) { + currNode.children[word[i]] = new TrieNode(); + } + currNode = currNode.children[word[i]] + } + currNode.END = true; +}; +let searchPrefix = (word) => { + let currNode = root; + for (let i = 0; i < word.length; i++) { + if(currNode.children[word[i]] != undefined) { + currNode = currNode.children[word[i]]; + }else{ + return null; + } + } + return currNode; +} +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let node = searchPrefix(word); + return node != null && node.END; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + return searchPrefix(prefix) != null; +}; + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ +// @lc code=end + diff --git a/Week 06/id_256/LeetCode_212_256.js b/Week 06/id_256/LeetCode_212_256.js new file mode 100644 index 000000000..412c6ff8c --- /dev/null +++ b/Week 06/id_256/LeetCode_212_256.js @@ -0,0 +1,93 @@ +/* + * @lc app=leetcode.cn id=212 lang=javascript + * + * [212] 单词搜索 II + */ + +// @lc code=start +class TrieNode{ + constructor(){ + this.END = false; + this.children = {}; + } +} +let root = null; +var Trie = function() { + root = new TrieNode(); +}; +Trie.prototype.insert = function(word) { + let currNode = root; + for(let i = 0; i < word.length; i++) { + if(currNode.children[word[i]] == undefined) { + currNode.children[word[i]] = new TrieNode(); + } + currNode = currNode.children[word[i]] + } + currNode.END = true; +}; +let searchPrefix = (word) => { + let currNode = root; + for (let i = 0; i < word.length; i++) { + if(currNode.children[word[i]] != undefined) { + currNode = currNode.children[word[i]]; + }else{ + return null; + } + } + return currNode; +} +Trie.prototype.search = function(word) { + let node = searchPrefix(word); + return node != null && node.END; +}; +Trie.prototype.startsWith = function(prefix) { + return searchPrefix(prefix) != null; +}; +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +var findWords = function(board, words) { + let trie = new Trie(); + //构建字典树 root + for(let i = 0; i < words.length; i++) { + trie.insert(words[i]); + } + let m = board.length; + if(m == 0) return []; + let n = board[0].length; + if(n == 0) return []; + let dx = [-1,1,0,0]; + let dy = [0,0,-1,1]; + let result = []; + let dfs = function(i, j, currStr) { + let str = board[i][j]; + currStr += str; + if(trie.search(currStr) && result.indexOf(currStr) < 0) { + result.push(currStr); + } + if(!trie.startsWith(currStr)){ + return; + } + board[i][j] = '@'; + for(let k = 0; k < 4; k++) { + let tem_i = dx[k] + i; + let tem_j = dy[k] + j; + if(tem_i >= 0 && tem_i < m && tem_j >= 0 && tem_j < n && board[tem_i][tem_j] != '@') { + dfs(tem_i, tem_j, currStr); + } + } + //回溯 + board[i][j] = str; + } + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + dfs(i, j, ''); + } + } + return result; +}; + +// @lc code=end + diff --git a/Week 06/id_256/LeetCode_322_256.js b/Week 06/id_256/LeetCode_322_256.js new file mode 100644 index 000000000..22c319f2a --- /dev/null +++ b/Week 06/id_256/LeetCode_322_256.js @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=322 lang=javascript + * + * [322] 零钱兑换 + */ + +// @lc code=start +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +var coinChange = function(coins, amount) { + if(amount < 1) return 0; + var dp = new Array(amount+1).fill(amount+1); + dp[0] = 0; + for(let i = 0; i <= amount; i++) { + for(let r = 0; r < coins.length; r++) { + if(coins[r] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[r]] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; +} +// @lc code=end + diff --git a/Week 06/id_256/LeetCode_547_256.js b/Week 06/id_256/LeetCode_547_256.js new file mode 100644 index 000000000..69deb7b1c --- /dev/null +++ b/Week 06/id_256/LeetCode_547_256.js @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode.cn id=547 lang=javascript + * + * [547] 朋友圈 + */ + +// @lc code=start +/** + * @param {number[][]} M + * @return {number} + */ +var findCircleNum = function(M) { + let n = M.length; + if(n == 0){ + return 0; + } + let count = n; + // 查找 + let find = (p) => { + while( p != parent[p]){ + // 路径压缩 + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + let union = (p,q) => { + let rootP = find(p); + let rootQ = find(q); + // 集合相交则不合并 + if(rootP == rootQ){ + return; + } + // 查找合并 + parent[rootP] = rootQ; + // 求连通分量,每合并两个集合,即整体减少一个独立集合 + count--; + } + let parent = new Array(n); + for(let i = 0;i < n;i++){ + parent[i] = i; + } + for(let i = 0;i < n;i++){ + for(let j = 0; j < n;j++){ + if(M[i][j] == 1){ + union(i,j); + } + } + } + return count; +}; + diff --git a/Week 06/id_261/leetcode_208_261.go b/Week 06/id_261/leetcode_208_261.go new file mode 100644 index 000000000..430005d04 --- /dev/null +++ b/Week 06/id_261/leetcode_208_261.go @@ -0,0 +1,67 @@ +// leetcode : https://leetcode-cn.com/problems/implement-trie-prefix-tree + +type Trie struct { + node map[rune]*Trie + isEnd bool +} + + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{node: map[rune]*Trie{}} +} + + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + t := this + for i, c := range word { + if _, ok := t.node[c]; !ok { + trie := Constructor() + t.node[c] = &trie + } + t = t.node[c] + if i == len(word) - 1 { + t.isEnd = true + } + } +} + + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + t := this + for i, c := range word { + if _, ok := t.node[c]; !ok { + return false + } else { + if i == len(word) - 1 { + return t.node[c].isEnd + } + } + t = t.node[c] + } + return false +} + + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + t := this + for _, c := range prefix { + if _, ok := t.node[c]; !ok { + return false + } + t = t.node[c] + } + return true +} + + +/** + * Your Trie object will be instantiated and called as such: + * obj := Constructor(); + * obj.Insert(word); + * param_2 := obj.Search(word); + * param_3 := obj.StartsWith(prefix); + */ \ No newline at end of file diff --git a/Week 06/id_261/leetcode_212_261.go b/Week 06/id_261/leetcode_212_261.go new file mode 100644 index 000000000..eec00c8d5 --- /dev/null +++ b/Week 06/id_261/leetcode_212_261.go @@ -0,0 +1,66 @@ +// leetcode : https://leetcode-cn.com/problems/word-search-ii + +type Trie struct { + node map[rune]*Trie + word string +} + +func (this *Trie) Insert(word string) { + t := this + for _, c := range word { + if _, ok := t.node[c]; !ok { + t.node[c] = &Trie{node: map[rune]*Trie{}} + } + t = t.node[c] + } + t.word = word +} + + + +var result map[string]bool + +func findWords(board [][]byte, words []string) []string { + result = make(map[string]bool) + trie := &Trie{node: map[rune]*Trie{}} + for _, word := range words { + trie.Insert(word) + } + for i := 0; i < len(board); i++ { + for j := 0; j < len(board[i]); j++ { + dfs(board, i, j, "", trie) + if len(result) >= len(words) { + return words + } + } + } + r := make([]string, len(result)) + i := 0 + for k, _ := range result { + r[i] = k + i++ + } + return r +} + +func dfs(board [][]byte, x, y int, str string, trie *Trie) { + if x < 0 || y < 0 || x >= len(board) || y >= len(board[0]) { + return + } + c := rune(board[x][y]) + if v, ok := trie.node[c]; !ok { + return + } else { + trie = v + if trie.word != "" { + result[trie.word] = true + } + } + tmp := board[x][y] + board[x][y] = '$' + dfs(board, x + 1, y, str, trie) + dfs(board, x, y + 1, str, trie) + dfs(board, x - 1, y, str, trie) + dfs(board, x, y - 1, str, trie) + board[x][y] = tmp +} \ No newline at end of file diff --git a/Week 06/id_261/leetcode_547_261.go b/Week 06/id_261/leetcode_547_261.go new file mode 100644 index 000000000..eba26b883 --- /dev/null +++ b/Week 06/id_261/leetcode_547_261.go @@ -0,0 +1,43 @@ +// leetcode : https://leetcode-cn.com/problems/friend-circles/ + +type FriendCircle struct { + parents []int + count int +} + +func NewFriendCircle(n int) FriendCircle { + f := FriendCircle{ parents: make([]int, n) } + f.count = n + for i, _ := range f.parents { + f.parents[i] = i + } + return f +} + +func (f *FriendCircle)parent(i int) int { + for f.parents[i] != i { + f.parents[i] = f.parents[f.parents[i]] + i = f.parents[i] + } + return i +} + +func (f *FriendCircle)union(i, j int) { + pi, pj := f.parent(i), f.parent(j) + if pi == pj { + return + } + f.parents[pi] = pj + f.count-- +} +func findCircleNum(M [][]int) int { + f := NewFriendCircle(len(M)) + for i := 0; i < len(M); i++ { + for j := i+1; j < len(M[i]); j++ { + if M[i][j] == 1 { + f.union(i, j) + } + } + } + return f.count +} \ No newline at end of file diff --git a/Week 06/id_276/Leetcode_208.java b/Week 06/id_276/Leetcode_208.java new file mode 100644 index 000000000..7ab3ca802 --- /dev/null +++ b/Week 06/id_276/Leetcode_208.java @@ -0,0 +1,42 @@ +class TrieNode { + char val; + boolean isWord; + TrieNode[] chirld = new TrieNode[26]; + TrieNode(){} + TrieNode(char c) { + TrieNode node = new TrieNode(); + node.val = c; + } +} +public class Trie { + public TrieNode root; + public Trie() { + root = new TrieNode(); + } + public void insert(String word) { + TrieNode next = root; + for (char c : word.toCharArray()) { + if (next.chirld[c-'a'] == null) { + next.chirld[c-'a'] = new TrieNode(c); + } + next = next.chirld[c-'a']; + } + next.isWord = true; + } + public boolean search(String word) { + TrieNode next = root; + for (char c : word.toCharArray()) { + if (next.chirld[c-'a'] == null) return false; + else next = next.chirld[c-'a']; + } + return next.isWord; + } + public boolean startsWith(String prefix) { + TrieNode next = root; + for (char c : prefix.toCharArray()) { + if (next.chirld[c-'a'] == null) return false; + else next = next.chirld[c-'a']; + } + return true; + } +} diff --git a/Week 06/id_276/Leetcode_212.java b/Week 06/id_276/Leetcode_212.java new file mode 100644 index 000000000..543ae1079 --- /dev/null +++ b/Week 06/id_276/Leetcode_212.java @@ -0,0 +1,69 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class Leetcode_212 { + public List finidWords(char[][] board, String[] words) { + Trie wordTrie = new Trie(); + for (String s : words) wordTrie.insert(s); + TrieNode root = wordTrie.root; + Set result = new HashSet<>(); + int m = board.length; + int n = board[0].length; + boolean[][] marked = new boolean[m][n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + find(board, marked, i, j, m, n, root, result); + } + } + return new LinkedList(result); + } + + private void find(char[][] board, + boolean[][] marked, + int i, int j, + int m, int n, + TrieNode cur, + Set res) { + //termination + if (i < 0 || i == m || j < 0 || j == n || marked[i][j]) return; + //proccess + cur = cur.child[board[i][j] - 'a']; + marked[i][j] = true; + if (cur == null) { + marked[i][j] = false; + return; + } + if (cur.isWord) res.add(new String(cur.val)); + //drill down + find(board, marked, i + 1, j, m, n, cur, res); + find(board, marked, i - 1, j, m, n, cur, res); + find(board, marked, i, j + 1, m, n, cur, res); + find(board, marked, i, j - 1, m, n, cur, res); + //reverse + marked[i][j] = false; + } + + //字典树 + class Trie { + public TrieNode root; + public Trie() { root = new TrieNode(); } + public void insert(String s) { + TrieNode cur = root; + for (char c : s.toCharArray()) { + if (cur.child[c - 'a'] == null) cur.child[c - 'a'] = new TrieNode(); + cur = cur.child[c - 'a']; + } + cur.isWord = true; + cur.val = s; + } + } + + //字典树结点 + class TrieNode { + public String val; + public TrieNode[] child = new TrieNode[26]; + public boolean isWord = false; + } +} diff --git a/Week 06/id_281/LeetCode_208_281.java b/Week 06/id_281/LeetCode_208_281.java new file mode 100644 index 000000000..f58d67635 --- /dev/null +++ b/Week 06/id_281/LeetCode_208_281.java @@ -0,0 +1,72 @@ +class Trie { + + class TrieNode { + private int v; + boolean end; + TrieNode[] next = new TrieNode[26]; + + TrieNode(char ch) { + v = 1 << (ch - 'a'); + } + + TrieNode add(char ch) { + int k = ch - 'a'; + if (next[k] != null) { + next[k].v |= 1 << k; + } else { + next[k] = new TrieNode((ch)); + } + return next[k]; + } + + TrieNode get(char ch) { + return next[ch - 'a']; + } + } + + TrieNode root = new TrieNode('a'); + + /** + * Initialize your data structure here. + */ + public Trie() {} + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode p = root; + for (char c : word.toCharArray()) { + p = p.add(c); + } + p.end = true; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode p = root; + for (char c : word.toCharArray()) { + p = p.get(c); + if (p == null) { + return false; + } + } + return p.end; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode p = root; + for (char c : prefix.toCharArray()) { + p = p.get(c); + if (p == null) { + return false; + } + } + return true; + } +} diff --git a/Week 06/id_281/LeetCode_212_281.java b/Week 06/id_281/LeetCode_212_281.java new file mode 100644 index 000000000..24a374e56 --- /dev/null +++ b/Week 06/id_281/LeetCode_212_281.java @@ -0,0 +1,61 @@ +class Solution { + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + for (String word: words) + trie.insert(word); + + int m = board.length; + int n = board[0].length; + boolean[][] visited = new boolean[m][n]; + Set resultSet = new HashSet(); + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) + search(board, visited, i, j, m, n, trie.root, resultSet); + } + + return new LinkedList(resultSet); + } + + + private void search(char[][] board, boolean[][] visited, int i, int j, int m, int n, TrieNode node, Set result) { + if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j]) + return; + + node = node.children[board[i][j] - 'a']; + if (node == null) + return; + + if (node.word != null) + result.add(node.word); + + visited[i][j] = true; + search(board, visited, i-1, j, m, n, node, result); + search(board, visited, i+1, j, m, n, node, result); + search(board, visited, i, j-1, m, n, node, result); + search(board, visited, i, j+1, m, n, node, result); + visited[i][j] = false; + } +} + +class Trie { + public TrieNode root = new TrieNode(); + + public void insert(String word) { + TrieNode node = root; + int n = word.length(); + int charNo; + for (int i = 0; i < n; ++i) { + charNo = word.charAt(i) - 'a'; + if (node.children[charNo] == null) + node.children[charNo] = new TrieNode(); + node = node.children[charNo]; + } + node.word = word; + } +} + +class TrieNode { + public TrieNode[] children = new TrieNode[26]; + public String word = null; +} diff --git a/Week 06/id_296/LeetCode_130_296.java b/Week 06/id_296/LeetCode_130_296.java new file mode 100644 index 000000000..9ff41f6ac --- /dev/null +++ b/Week 06/id_296/LeetCode_130_296.java @@ -0,0 +1,49 @@ +/* + * @lc app=leetcode.cn id=130 lang=java + * + * [130] 被围绕的区域 + */ + +// @lc code=start +class Solution { + public void solve(char[][] board) { + if (board == null || board.length == 0) + return; + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 从边缘o开始搜索 + boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1; + if (isEdge && board[i][j] == 'O') { + dfs(board, i, j); + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + if (board[i][j] == '#') { + board[i][j] = 'O'; + } + } + } + } + + public void dfs(char[][] board, int i, int j) { + if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') { + // board[i][j] == '#' 说明已经搜索过了. + return; + } + board[i][j] = '#'; + dfs(board, i - 1, j); // 上 + dfs(board, i + 1, j); // 下 + dfs(board, i, j - 1); // 左 + dfs(board, i, j + 1); // 右 + } +} +// @lc code=end + diff --git a/Week 06/id_296/LeetCode_36_296.java b/Week 06/id_296/LeetCode_36_296.java new file mode 100644 index 000000000..e00048a5e --- /dev/null +++ b/Week 06/id_296/LeetCode_36_296.java @@ -0,0 +1,60 @@ +/* + * @lc app=leetcode.cn id=36 lang=java + * + * [36] 有效的数独 + */ + +// @lc code=start +class Solution { + public boolean isValidSudoku(char[][] board) { + int[] hash_row = new int[9]; + int[] hash_col = new int[9]; + int[] hash = new int[9]; + for(int i = 0;i < board.length;i++){ + hash_row = new int[9]; + hash_col = new int[9]; + for(int j = 0;j < board[0].length;j++){ + //检测行 + if(board[i][j] != '.'){ + if(hash_row[board[i][j] - '1'] == 0){ + hash_row[board[i][j] - '1'] = 1; + }else{ + return false; + } + } + + + //检测列 + if(board[j][i] != '.'){ + if(hash_col[board[j][i] - '1'] == 0){ + hash_col[board[j][i] - '1'] = 1; + }else{ + return false; + } + } + } + } + + //检测3*3 + for(int i = 0;i < board.length;i+=3){ + for(int j = 0; j < board[0].length;j+=3){ + hash = new int[9]; + for(int m = 0; m < 3;m++){ + for(int n = 0;n < 3;n++){ + if(board[i+m][j+n] != '.'){ + if(hash[board[i+m][j+n] - '1'] == 0){ + hash[board[i+m][j+n] - '1'] = 1; + }else { + return false; + } + } + } + } + } + } + + return true; + } +} +// @lc code=end + diff --git a/Week 06/id_301/LeetCode_208_301.go b/Week 06/id_301/LeetCode_208_301.go new file mode 100644 index 000000000..a000d08f6 --- /dev/null +++ b/Week 06/id_301/LeetCode_208_301.go @@ -0,0 +1,70 @@ +package id_301 + +type Node struct { + isWord bool + next map[string]*Node +} + +func NewNode() *Node { + return &Node{next: make(map[string]*Node)} +} + +type Trie struct { + root *Node +} + +func Constructor() Trie { + return Trie{root: NewNode()} +} + +func (t *Trie) Insert(word string) { + add(t.root, word, 0) +} + +func add(node *Node, word string, index int) { + if index == len(word) { + if !node.isWord { + node.isWord = true + } + return + } + + c := string([]rune(word)[index]) + if node.next[c] == nil { + node.next[c] = NewNode() + } + add(node.next[c], word, index+1) +} + +func (t *Trie) Search(word string) bool { + return contains(t.root, word, 0) +} + +func contains(node *Node, word string, index int) bool { + if index == len(word) { + return node.isWord + } + + c := string([]rune(word)[index]) + if node.next[c] == nil { + return false + } + return contains(node.next[c], word, index+1) +} + +func (t *Trie) StartsWith(prefix string) bool { + return isPrefix(t.root, prefix, 0) +} + +func isPrefix(node *Node, prefix string, index int) bool { + if index == len(prefix) { + return true + } + + c := string([]rune(prefix)[index]) + if node.next[c] == nil { + return false + } + + return isPrefix(node.next[c], prefix, index+1) +} diff --git a/Week 06/id_301/LeetCode_51_301.go b/Week 06/id_301/LeetCode_51_301.go new file mode 100644 index 000000000..d1bf4e134 --- /dev/null +++ b/Week 06/id_301/LeetCode_51_301.go @@ -0,0 +1,60 @@ +package id_301 + +func solveNQueens(n int) [][]string { + if n == 0 { + return nil + } + res := make([][]int, 0) + //存放列,撇,捺 + cols := make(map[int]bool, n) + pies := make(map[int]bool, n) + nas := make(map[int]bool, n) + dfs([]int{}, n, cols, pies, nas, &res) + return generateResult(res, n) +} + +func dfs(rows []int, n int, cols, pies, nas map[int]bool, res *[][]int) { + //出递归的条件 + row := len(rows) + if row == n { + tmp := make([]int, len(rows)) + copy(tmp, rows) + (*res) = append((*res), tmp) + return + } + //对于每一层就遍历所有的列 + for col := 0; col < n; col++ { + //当列,撇,捺中都不存在对应的值时,将其加入 + if !cols[col] && !pies[row+col] && !nas[row-col] { + //开始更新列撇捺的值 + cols[col] = true + pies[row+col] = true + nas[row-col] = true + //递归执行下一层操作 + dfs(append(rows, col), n, cols, pies, nas, res) + //每一次递归完成后将原有的标志位清空,以方便下一层搜索 + cols[col] = false + pies[row+col] = false + nas[row-col] = false + } + } +} + +func generateResult(res [][]int, n int) (result [][]string) { + for _, v := range res { + var s []string + for _, val := range v { + str := "" + for i := 0; i < n; i++ { + if i == val { + str += "Q" + } else { + str += "." + } + } + s = append(s, str) + } + result = append(result, s) + } + return +} diff --git a/Week 06/id_306/FriendCircles.java b/Week 06/id_306/FriendCircles.java new file mode 100644 index 000000000..c9c83d988 --- /dev/null +++ b/Week 06/id_306/FriendCircles.java @@ -0,0 +1,85 @@ +package sf.week6; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/friend-circles/ + */ +public class FriendCircles { + /** + * 并查集 + * @param M + * @return + */ + public int findCircleNum(int[][] M) { + int len = M.length; + UnionFind uf = new UnionFind(len); + for (int i = 0; i < len; i++) { + for (int j = 0; j < i; j++) { + if (M[i][j] == 1) { + uf.union(i, j); + } + } + } + return uf.getCount(); + } +} + +class UnionFind { + /** + * 连通分量的个数 + */ + private int count; + private int[] parent; + /** + * 以索引为 i 的元素为根结点的树的深度(最深的那个深度) + */ + private int[] rank; + + public UnionFind(int n) { + this.count = n; + this.parent = new int[n]; + this.rank = new int[n]; + for (int i = 0; i < n; i++) { + this.parent[i] = i; + // 初始化时,所有的元素只包含它自己,只有一个元素,所以 rank[i] = 1 + this.rank[i] = 1; + } + } + + public int getCount() { + return this.count; + } + + public int find(int p) { + // 在 find 的时候执行路径压缩 + while (p != this.parent[p]) { + // 两步一跳完成路径压缩 + this.parent[p] = this.parent[this.parent[p]]; + p = this.parent[p]; + } + return p; + } + + public boolean isConnected(int p, int q) { + return find(p) == find(q); + } + + public void union(int p, int q) { + int pRoot = find(p); + int qRoot = find(q); + if (pRoot == qRoot) { + return; + } + + if (rank[pRoot] > rank[qRoot]) { + parent[qRoot] = pRoot; + } else if (rank[pRoot] < rank[qRoot]) { + parent[pRoot] = qRoot; + } else { + parent[qRoot] = pRoot; + rank[pRoot]++; + } + // 每次 union 以后,连通分量减 1 + count--; + } +} diff --git a/Week 06/id_306/NQueens.java b/Week 06/id_306/NQueens.java new file mode 100644 index 000000000..cdb8853d2 --- /dev/null +++ b/Week 06/id_306/NQueens.java @@ -0,0 +1,48 @@ +package sf.week6; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/n-queens + */ +public class NQueens { + private List> results = new ArrayList<>(); // 结果集 + public List> solveNQueens(int n) { + int[] result = new int[n]; // 记录每一行皇后放置的 列坐标 + backtracking(result, 0); + return results; + } + private void backtracking(int[] result,int n){ + if (n == result.length) { // 已放置完,每一行皇后都符合要求 + List temp = new ArrayList<>(); + for (int i = 0; i < result.length; i++) { + char[] str = new char[n]; + Arrays.fill(str, '.'); + str[result[i]] = 'Q'; + temp.add(new String(str)); // 根据每一行出现皇后的位置填充解 + } + results.add(temp); // 加入当前解 + } + for (int i = 0; i < result.length; i++) { + if (isValidation(result, n, i)) { // 验证是否合法 + result[n] = i; // 记录放置坐标 + backtracking(result, n + 1); // 放置下一行皇后 + } + } + } + // 验证,无同行/同列棋子 + // 对角线无棋子 + private boolean isValidation(int[] result, int row, int col) { + for (int i = 0; i < row; i++) { // 第一行可以放任意位置 + int sub = row - i; // 行数差 + // 避免同列、对角线出现皇后 + if (result[i]==col||result[i]==col-sub||result[i]==col+sub) { + return false; + } + } + return true; + } +} diff --git a/Week 06/id_306/NQueensOtherMethod.java b/Week 06/id_306/NQueensOtherMethod.java new file mode 100644 index 000000000..96b3e5a8e --- /dev/null +++ b/Week 06/id_306/NQueensOtherMethod.java @@ -0,0 +1,45 @@ +package sf.week6; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LynnSun on 2019/11/23. + * https://leetcode-cn.com/problems/n-queens/solution/javahui-su-fa-si-lu-jian-dan-qing-xi-qing-kan-dai-/ + */ +public class NQueensOtherMethod { + // 思路清晰借鉴一下 + List> lists = new ArrayList<>();//返回集合 + List ans = new ArrayList<>();//n皇后的解 + public List> solveNQueens(int n) { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < n; i++){//...... + sb.append("."); + } + //列的大小为n,主对角线和次对角线的大小为2n-1 + queens(n, new boolean[n], new boolean[2 * n - 1], new boolean[2 * n - 1], sb,0); + return lists; + } + void queens(int n,boolean[] y,boolean[] w,boolean[] wc,StringBuilder sb,int i){ + if(ans.size() == n){//递归结束条件,即n皇后已放置所有的行中 + lists.add(new ArrayList<>(ans)); + return; + } + for(int j = 0; j < n; j++){ + //判断当前位置是否可用,即列、主对角线、次对角线是否被使用 + if(y[j] || w[n - 1 - i + j] || wc[i + j]) continue; + //如果可用,先标记该列、主对角线、次对角线已被使用 + y[j] = true; + w[n - 1 - i + j] = true; + wc[i + j] = true; + ans.add(new StringBuilder(sb).replace(j,j+1,"Q").toString()); + //递归下一行是否可以放置皇后,直到所有皇后都放到对应的位置或者该行无法放置皇后则结束 + queens(n,y,w,wc,sb,i+1); + //递归完成之后,恢复现场 + ans.remove(i); + y[j] = false; + wc[i + j] = false; + w[n - 1 - i + j] = false; + } + } +} diff --git a/Week 06/id_306/NumberOfIslands.java b/Week 06/id_306/NumberOfIslands.java new file mode 100644 index 000000000..d0ac357c6 --- /dev/null +++ b/Week 06/id_306/NumberOfIslands.java @@ -0,0 +1,82 @@ +package sf.week6; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/number-of-islands/ + */ +public class NumberOfIslands { + class Union{ + private int[] union; + int count = 0; + Union(char[][] grid){ + int len1 = grid.length, len2 = grid[0].length; + union = new int[len1 * len2]; + // 初始化并查集 + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len2; j++) { + if (grid[i][j] == '1') { + int index = i * len2 + j; + union[index] = index; // 初始化指向自己 + count++; + } + } + } + } + // 找到终点 + int find(int index) { + if (union[index] == index) { + return index; + } + int end = find(union[index]);// 递归查找 + while (union[index] != end) { // 优化并查集合并 + int temp = index; + index = union[index]; + union[temp] = end; + } + return end; + } + // 合并并查集 + void union(int index1,int index2){ + int end1 = find(index1); + int end2 = find(index2); + if (end1 != end2) { // 不是同一终点 + union[end2] = end1; // 合并 + count--; // 岛屿数 -1 + } + } + + } + private int[] moveX = {-1, 1, 0, 0},moveY = {0, 0, -1, 1}; + + /** + * 并查集方式 + * @param grid + * @return + */ + public int numIslands(char[][] grid) { + if (grid == null || grid.length < 1) { + return 0; + } + Union union = new Union(grid); + int len1 = grid.length; + for (int i = 0; i < len1; i++) { + int len2 = grid[0].length; + for (int j = 0; j < len2; j++) { + if (grid[i][j] == '1') { // 将上下左右的 1 合并在一起 + for (int k = 0; k < moveX.length; k++) { + int x = i + moveX[k], y = j + moveY[k]; + if (isValid(grid, len1, len2, x, y)) { + union.union(i * len2 + j, x * len2 + y); + } + } + } + } + } + return union.count; + } + + + private boolean isValid(char[][] grid,int len1,int len2, int x, int y) { + return x >= 0 && x < len1 && y >= 0 && y < len2 && grid[x][y] == '1'; + } +} diff --git a/Week 06/id_306/PrefixTree.java b/Week 06/id_306/PrefixTree.java new file mode 100644 index 000000000..2d2a18e92 --- /dev/null +++ b/Week 06/id_306/PrefixTree.java @@ -0,0 +1,69 @@ +package sf.week6; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/implement-trie-prefix-tree + */ +public class PrefixTree { + private TrieNode root; + /** Initialize your data structure here. */ + public PrefixTree() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + /** + * 插入 + * @param word + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + // Returns if the word is in the trie. + + /** + * 查找 + * @param word + * @return + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + /** + * 查找前缀 + * @param prefix + * @return + */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + +} + + diff --git a/Week 06/id_306/ShortestPathBinaryMatrix.java b/Week 06/id_306/ShortestPathBinaryMatrix.java new file mode 100644 index 000000000..cdba361fd --- /dev/null +++ b/Week 06/id_306/ShortestPathBinaryMatrix.java @@ -0,0 +1,58 @@ +package sf.week6; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Created by LynnSun on 2019/11/24. + * 力扣题目地址:https://leetcode-cn.com/problems/shortest-path-in-binary-matrix + */ +public class ShortestPathBinaryMatrix { + + /** + * 注释好理解版 + * @param grid + * @return + */ + public int shortestPathBinaryMatrix(int[][] grid) { + int m = grid.length, n = grid[0].length; + // 当矩阵第一个元素为1或者最后一个元素为1时,直接返回-1 + if(grid[0][0]==1 || grid[grid.length-1][grid[0].length-1]==1) return -1; + grid[0][0] = 1; + // 创建队列用于保存每一格可以走的步 + Queue q=new LinkedList<>(); + q.add(new int[]{0, 0}); + // 队列长度,c要和队列做对比,知道何时到达队列长度 + int len = q.size(); + int c = 0; + // 定义八个方向 + int[][] dir = {{1, 0}, {1, 1}, {1,-1}, {0, 1}, {0, -1}, {-1, 0},{-1, -1}, {-1, 1}}; + // 定义最短路径长度 + int path = 1; + while(!q.isEmpty()){ + int[] data = q.poll(); + // x、y代表当前的坐标(x,y) + int x = data[0]; + int y = data[1]; + // 如果走到最后一格,返回 + if(x == m - 1 && y == n - 1) return path; + // 此处填充队列,将可走的步添加进队列 + for(int[] d : dir){ + // x1,y1代表当前坐标移动后的坐标(x1,y1) + int x1 = x + d[0]; + int y1 = y + d[1]; + if(x1 >= 0 && y1 >= 0 && x1 < m && y1 < n && grid[x1][y1] == 0){ + q.add(new int[]{x1, y1}); + grid[x1][y1] = 1; + } + } + c++; + if(c == len){ + c = 0; + path++; + len = q.size(); + } + } + return -1; + } +} diff --git a/Week 06/id_306/ShortestPathBinaryMatrixOther.java b/Week 06/id_306/ShortestPathBinaryMatrixOther.java new file mode 100644 index 000000000..032e6fc6c --- /dev/null +++ b/Week 06/id_306/ShortestPathBinaryMatrixOther.java @@ -0,0 +1,101 @@ +package sf.week6; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LynnSun on 2019/11/24. + * 更优版 + */ +public class ShortestPathBinaryMatrixOther { + private class State { + int i; + int j; + + public State(int i, int j) { + this.i = i; + this.j = j; + } + } + + static final int[][] direc = new int[][]{{1,0},{-1,0},{1,1},{-1,1}, {0,1},{1,-1},{-1,-1},{0,-1}}; + + public int shortestPathBinaryMatrix(int[][] grid) { + if (grid.length == 0) { + return -1; + } + + if (grid.length == 1) { + return grid[0][0] == 0 ? 1 : -1; + } + + final int N = grid.length; + + if ((grid[0][0] == 1) || (grid[N-1][N-1] == 1)) { + return -1; + } + + List startSta = new ArrayList<>(N*N); + List endSta = new ArrayList<>(N*N); + startSta.add(new State(0, 0)); + endSta.add(new State(N-1, N-1)); + + boolean[][] visited = new boolean[N][N]; + visited[0][0] = true; + visited[N-1][N-1] = true; + + boolean[][] startVisited = new boolean[N][N]; + boolean[][] endVisited = new boolean[N][N]; + startVisited[0][0] = true; + endVisited[N-1][N-1] = true; + + int len = 1; + + while (!startSta.isEmpty() && !endSta.isEmpty()) { + + if (startSta.size() > endSta.size()) { + List tmp = startSta; startSta = endSta; endSta = tmp; + boolean[][] tmpA = startVisited; startVisited = endVisited; endVisited = tmpA; + } + + List newStaSet = new ArrayList<>(); + for (State curSta : startSta) { + int i = curSta.i, j = curSta.j; + for (int[] pos : direc) { + int new_i = i + pos[0], new_j = j + pos[1]; + if (new_i >= 0 && new_i < N && new_j >= 0 && new_j < N && grid[new_i][new_j] == 0) { + State newSta = new State(new_i, new_j); + + if (endVisited[newSta.i][newSta.j]) { + return len + 1; + } + + if (visited[newSta.i][newSta.j]) { + continue; + } + + newStaSet.add(newSta); + visited[newSta.i][newSta.j] = true; + startVisited[newSta.i][newSta.j] = true; + } + } + } + + startSta = newStaSet; + len++; + } + + return -1; + } + + public static void main(String[] args) { + System.out.println(new ShortestPathBinaryMatrixOther().shortestPathBinaryMatrix(new int[][] + {{0,0,1,0,0,0,0}, + {0,1,0,0,0,0,1}, + {0,0,1,0,1,0,0}, + {0,0,0,1,1,1,0}, + {1,0,0,1,1,0,0}, + {1,1,1,1,1,0,1}, + {0,0,1,0,0,0,0}})); + } +} diff --git a/Week 06/id_306/SlidingPuzzle.java b/Week 06/id_306/SlidingPuzzle.java new file mode 100644 index 000000000..b91d5e5ba --- /dev/null +++ b/Week 06/id_306/SlidingPuzzle.java @@ -0,0 +1,139 @@ +package sf.week6; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +/** + * Created by LynnSun on 2019/11/24. + * 力扣题目地址:https://leetcode-cn.com/problems/sliding-puzzle + * A * LeetCode国际站大佬的题解 + */ +public class SlidingPuzzle { + /*思路:基于普通的广度优先遍历解法, 将普通队列改为使用优先队列, + 每次队列poll时都先通过compareTo选择一个"曼哈顿距离最短", + 也就是距离最终结果需要交换次数最小的一个分支进行计算。 + 像这样每次队列都择优poll, BFS算法就能够更快速的到达终点。 + + 关于曼哈顿距离:二维坐标中, 一个点(x1, y1)到另一个点(x2, y2)的曼哈顿距离 = |x1 - x2| + |y1 - y2| + + 由于优先队列默认队列头元素是最小元素,故我们可以拿来作为小根堆使用, + 故这个A* 算法的主要思想就是每次都poll一个交换次数 + 曼哈顿距离最短的节点, 从而达到枝减的效果*/ + + public int slidingPuzzle(int[][] board) { + //find index of zero in board + int[] index = findIndexOfZero(board); + if (index == null || index.length == 0) return -1; + //create start State + State start = new State(board, 0, index[0], index[1]); + //PQ + PriorityQueue pq = new PriorityQueue<>(); + pq.add(start); + //Set + Set visited = new HashSet<>(); + visited.add(start); + //moves + int[][] moves = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + + while (!pq.isEmpty()) { + State currState = pq.poll();//poll State by priority + if (currState.isGoal()) return currState.taken; + for (int[] move : moves) { + int x = currState.zeroSetX + move[0]; + int y = currState.zeroSetY + move[1]; + if (x < 0 || y < 0 || x >= board.length || y >= board[0].length) continue; + State newState = currState.swap(x, y); + if (newState != null && visited.add(newState)) pq.offer(newState); + } + } + return -1; + } + + class State implements Comparable{ + int[][] stateBoard; + int taken; + int zeroSetX; + int zeroSetY; + + public State(int[][] stateBoard, int taken, int zeroSetX, int zeroSetY) { + //这里新建数组的原因是:直接赋地址的话, 若通过当前State的stateBoard创建了一个NewState, 修改NewState.stateBoard的同时也会修改this.stateBoard + this.stateBoard = new int[2][3]; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + this.stateBoard[i][j] = stateBoard[i][j]; + } + } + this.taken = taken; + this.zeroSetX = zeroSetX; + this.zeroSetY = zeroSetY; + } + + /** + * swap board where x = zeroX, y = zeroY + * + * @param x + * @param y + * @return State + */ + public State swap(int x, int y) { + State res = new State(stateBoard, taken + 1, x, y); + int temp = res.stateBoard[x][y]; + res.stateBoard[x][y] = res.stateBoard[zeroSetX][zeroSetY]; + res.stateBoard[zeroSetX][zeroSetY] = temp; + return res; + } + + /** + * priority distance + * @return + */ + public int distance() { + int result = 0; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + if (stateBoard[i][j] == 0) continue; + //二维坐标曼哈顿距离计算:res = |x - i| + |y - j| + int val = stateBoard[i][j] - 1; + int x = val/3; + int y = val%3; + result += Math.abs(x - i) + Math.abs(y - j); + } + } + return result; + } + + public boolean isGoal() { + return distance() == 0; + } + + /** + * compare all states in PQ while poll or remove + * @param that + * @return + */ + @Override + public int compareTo(State that) { + return this.distance() + this.taken - that.distance() - that.taken; + } + + @Override + public boolean equals(Object obj) { + return Arrays.deepEquals(((State) obj).stateBoard, this.stateBoard); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(stateBoard); + } + } + + private int[] findIndexOfZero(int[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == 0) return new int[]{i, j}; + } + } + return null; + } +} diff --git a/Week 06/id_306/SudokuSolver.java b/Week 06/id_306/SudokuSolver.java new file mode 100644 index 000000000..6037f62cf --- /dev/null +++ b/Week 06/id_306/SudokuSolver.java @@ -0,0 +1,67 @@ +package sf.week6; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/sudoku-solver + */ +public class SudokuSolver { + /** + * 逻辑清晰 学习了 + * @param board + */ + public void solveSudoku(char[][] board) { + // 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过 + boolean[][] rowUsed = new boolean[9][10]; + boolean[][] colUsed = new boolean[9][10]; + boolean[][][] boxUsed = new boolean[3][3][10]; + // 初始化 + for(int row = 0; row < board.length; row++){ + for(int col = 0; col < board[0].length; col++) { + int num = board[row][col] - '0'; + if(1 <= num && num <= 9){ + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row/3][col/3][num] = true; + } + } + } + // 递归尝试填充数组 + recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, 0, 0); + } + + private boolean recusiveSolveSudoku(char[][]board, boolean[][]rowUsed, boolean[][]colUsed, boolean[][][]boxUsed, int row, int col){ + // 边界校验, 如果已经填充完成, 返回true, 表示一切结束 + if(col == board[0].length){ + col = 0; + row++; + if(row == board.length){ + return true; + } + } + // 是空则尝试填充, 否则跳过继续尝试填充下一个位置 + if(board[row][col] == '.') { + // 尝试填充1~9 + for(int num = 1; num <= 9; num++){ + boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || boxUsed[row/3][col/3][num]); + if(canUsed){ + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row/3][col/3][num] = true; + + board[row][col] = (char)('0' + num); + if(recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1)){ + return true; + } + board[row][col] = '.'; + + rowUsed[row][num] = false; + colUsed[col][num] = false; + boxUsed[row/3][col/3][num] = false; + } + } + } else { + return recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1); + } + return false; + } +} diff --git a/Week 06/id_306/TrieNode.java b/Week 06/id_306/TrieNode.java new file mode 100644 index 000000000..a31172234 --- /dev/null +++ b/Week 06/id_306/TrieNode.java @@ -0,0 +1,33 @@ +package sf.week6; + +/** + * Created by LynnSun on 2019/11/23. + */ +public class TrieNode { + // R links to node children + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } +} diff --git a/Week 06/id_306/WordLadder.java b/Week 06/id_306/WordLadder.java new file mode 100644 index 000000000..7e5992a85 --- /dev/null +++ b/Week 06/id_306/WordLadder.java @@ -0,0 +1,103 @@ +package sf.week6; + +import java.util.*; + +/** + * Created by LynnSun on 2019/11/24. + * 力扣题目地址:https://leetcode-cn.com/problems/word-ladder + */ +public class WordLadder { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; // O(n),可先放入HashSet--O(1) + if (beginWord.equals(endWord)) return 2; + + // 预处理 双端广度优先 避免重复访问 递归 总是从少找向多 + // 预处理 + Map> patternMap = this._getPatternMap(wordList); + + // 双端广度优先 + Set beginSet = new HashSet<>(), endSet = new HashSet<>(); + beginSet.add(beginWord); + endSet.add(endWord); + + Set visited = new HashSet<>(); + + // 递归 + return this._search(1, beginSet, endSet, visited, patternMap); + } + + // BFS starts here + private int _search(int level, Set beginSet, Set endSet, + Set visited, Map> patternMap) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; // 双端都找不到了 + + // process + visited.addAll(beginSet); + level++; + Set nextLevelSet = new HashSet<>(); + + // 遍历beginSet + for (String beginWord : beginSet) { + Set neighbors = this._getNeighbors(beginWord, patternMap); + // 遍历所有相邻词 + for (String neighbor : neighbors) { + if (visited.contains(neighbor)) continue; // 避免重复访问 + if (endSet.contains(neighbor)) return level; // 已找到 + // 未找到,把相邻词记入下一层 + nextLevelSet.add(neighbor); + } + // 不能再此处 nextLevelSet.addAll(neighbors); 因为不能将 visited.contains(neighbor) 的节点放入 nextLevelSet + } + + // drill down + // 总是从少找向多 + if (nextLevelSet.size() <= endSet.size()) { + beginSet = nextLevelSet; + } else { + beginSet = endSet; + endSet = nextLevelSet; + } + + return this._search(level, beginSet, endSet, visited, patternMap); + + // reverse state + } + + // 返回给定单词表的所有匹映射,key为带*的匹配键,value为该匹配键可对应的单词集合 + private Map> _getPatternMap(List wordList) { + Map> map = new HashMap<>(); + for (String word : wordList) { + Set keys = this._getPatterns(word); + for (String key : keys) { + if (!map.containsKey(key)) map.put(key, new HashSet<>()); + map.get(key).add(word); + } + } + return map; + } + + // 返回给定单词的所有可能的带*匹配键 + private Set _getPatterns(String word) { + Set res = new HashSet<>(); + char[] arr = word.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char temp = arr[i]; + arr[i] = '*'; + res.add(String.valueOf(arr)); + arr[i] = temp; + } + return res; + } + + // 返回给定单词、在给定匹配映射中的所有可能的相邻单词 + private Set _getNeighbors(String word, Map> patternMap) { + Set res = new HashSet<>(); + Set patterns = this._getPatterns(word); + for (String pattern : patterns) { + if (!patternMap.containsKey(pattern)) continue; + res.addAll(patternMap.get(pattern)); + } + return res; + } +} diff --git a/Week 06/id_306/WordLadderOther.java b/Week 06/id_306/WordLadderOther.java new file mode 100644 index 000000000..5c6876d3d --- /dev/null +++ b/Week 06/id_306/WordLadderOther.java @@ -0,0 +1,63 @@ +package sf.week6; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by LynnSun on 2019/11/24. + */ +public class WordLadderOther { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; + if (beginWord.equals(endWord)) return 2; + + // 可能遇见的节点集 + Set meets = new HashSet<>(wordList); // O(n) + + Set beginSet = new HashSet<>(Collections.singleton(beginWord)); + Set endSet = new HashSet<>(Collections.singleton(endWord)); + + return this._search(1, beginSet, endSet, meets); + } + + private int _search(int level, Set beginSet, Set endSet, Set meets) { + // terminator + if (beginSet.size() == 0 || endSet.size() == 0) return 0; + + // process + meets.removeAll(beginSet); + level++; + Set nextLevelSet = new HashSet<>(); + // iter every begin word + for (String beginWord : beginSet) { + char[] chars = beginWord.toCharArray(); + // iter for every char + for (int i = 0; i < chars.length; i++) { + char temp = chars[i]; + // replace every letter + for (char ch = 'a'; ch < 'z'; ch++) { + chars[i] = ch; + String newWord = String.valueOf(chars); + if (!meets.contains(newWord)) continue; + if (endSet.contains(newWord)) return level; + nextLevelSet.add(newWord); + } + // reverse + chars[i] = temp; + } + } + + // drill down + // always from less to more + if (nextLevelSet.size() <= endSet.size()) { + beginSet = nextLevelSet; + } else { + beginSet = endSet; + endSet = nextLevelSet; + } + + return this._search(level, beginSet, endSet, meets); + } +} diff --git a/Week 06/id_306/WordSearchSec.java b/Week 06/id_306/WordSearchSec.java new file mode 100644 index 000000000..fca0bd9a4 --- /dev/null +++ b/Week 06/id_306/WordSearchSec.java @@ -0,0 +1,78 @@ +package sf.week6; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * Created by LynnSun on 2019/11/23. + * 力扣题目地址:https://leetcode-cn.com/problems/word-search-ii/ + */ +public class WordSearchSec { + + /** + * 字典树方式 DFS + * @param board + * @param words + * @return + */ + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + for (String word: words) + trie.insert(word); + + int m = board.length; + int n = board[0].length; + boolean[][] visited = new boolean[m][n]; + Set resultSet = new HashSet(); + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) + search(board, visited, i, j, m, n, trie.root, resultSet); + } + + return new LinkedList(resultSet); + } + + private void search(char[][] board, boolean[][] visited, int i, int j, int m, int n, TrieNoded node, Set result) { + if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j]) + return; + + node = node.children[board[i][j] - 'a']; + if (node == null) + return; + + if (node.word != null) + result.add(node.word); + + visited[i][j] = true; + search(board, visited, i-1, j, m, n, node, result); + search(board, visited, i+1, j, m, n, node, result); + search(board, visited, i, j-1, m, n, node, result); + search(board, visited, i, j+1, m, n, node, result); + visited[i][j] = false; + } +} + +class Trie { + public TrieNoded root = new TrieNoded(); + + public void insert(String word) { + TrieNoded node = root; + int n = word.length(); + int charNo; + for (int i = 0; i < n; ++i) { + charNo = word.charAt(i) - 'a'; + if (node.children[charNo] == null) + node.children[charNo] = new TrieNoded(); + node = node.children[charNo]; + } + node.word = word; + } +} + +class TrieNoded { + public TrieNoded[] children = new TrieNoded[26]; + public String word = null; +} \ No newline at end of file diff --git a/Week 06/id_311/LeetCode_208_Solution.java b/Week 06/id_311/LeetCode_208_Solution.java new file mode 100644 index 000000000..c3649c433 --- /dev/null +++ b/Week 06/id_311/LeetCode_208_Solution.java @@ -0,0 +1,82 @@ +class TrieNode{ + private TrieNode[] linked; + private int R = 26; + private boolean isEnd; + public TrieNode(){ + linked = new TrieNode[R]; + } + public boolean containsKey(char ch){ + return linked[ch - 'a'] != null; + } + public void put(char ch){ + linked[ch - 'a'] = new TrieNode(); + } + public TrieNode get(char ch){ + return linked[ch - 'a']; + } + public void setEnd(){ + this.isEnd = true; + } + public boolean getEnd(){ + return isEnd; + } + +} +class Trie { + private TrieNode rootNode; + /** Initialize your data structure here. */ + public Trie() { + rootNode = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = rootNode; + for(int i = 0; i < word.length(); i++){ + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)){ + node.put(currentChar); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = rootNode; + for(int i = 0; i < word.length(); i++){ + char currentChar = word.charAt(i); + if (node.containsKey(currentChar)){ + node = node.get(currentChar); + }else{ + node = null; + break; + } + } + return node != null && node.getEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = rootNode; + for(int i = 0; i < prefix.length(); i++){ + char currentChar = prefix.charAt(i); + if (node.containsKey(currentChar)){ + node = node.get(currentChar); + }else{ + node = null; + break; + } + } + return node != null; + } +} + +/** + * 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/Week 06/id_311/LeetCode_212_Solution.java b/Week 06/id_311/LeetCode_212_Solution.java new file mode 100644 index 000000000..ed38d5aab --- /dev/null +++ b/Week 06/id_311/LeetCode_212_Solution.java @@ -0,0 +1,59 @@ +class Solution { + public List findWords(char[][] board, String[] words) { + WorkTried workTried = new WorkTried(); + for(String word : words){ + workTried.insert(word); + } + int n = board.length; + int m = board[0].length; + boolean[][] visit = new boolean[n][m]; + HashSet result = new HashSet<>(); + for(int i = 0; i < board.length; i++){ + for(int j = 0; j < board[0].length; j++){ + search(i, j, n, m, visit, board, workTried.root, result); + } + } + return new ArrayList(result); + } + public void search(int i, int j, int n, int m, boolean[][] visit, char[][] board, TriedNode root, HashSet result){ + if(i >= n || j >= m || i < 0 || j < 0 || visit[i][j]){ + return; + } + visit[i][j] = true; + root = root.child[ board[i][j] - 'a']; + if(root == null){ + visit[i][j] = false; + return; + } + if(root.isLeaf){ + result.add(root.val); + } + search(i + 1, j, n, m, visit, board, root, result); + search(i, j + 1, n, m, visit, board, root, result); + search(i, j - 1, n, m, visit, board, root, result); + search(i - 1, j, n, m, visit, board, root, result); + visit[i][j] = false; + + } +} +class WorkTried{ + TriedNode root = new TriedNode(); + public void insert(String s){ + TriedNode cur = root; + for(int i = 0; i < s.length(); i++){ + if(cur.child[s.charAt(i) - 'a'] == null){ + cur.child[s.charAt(i) - 'a'] = new TriedNode(); + cur = cur.child[s.charAt(i) - 'a']; + } else { + cur = cur.child[s.charAt(i) - 'a']; + } + } + cur.isLeaf = true; + cur.val = s; + } +} +class TriedNode{ + String val; + boolean isLeaf; + TriedNode[] child = new TriedNode[26]; +} \ No newline at end of file diff --git a/Week 06/id_321/LeetCode_200_321.java b/Week 06/id_321/LeetCode_200_321.java new file mode 100644 index 000000000..aab8b20cc --- /dev/null +++ b/Week 06/id_321/LeetCode_200_321.java @@ -0,0 +1,85 @@ +package week06; + +public class NumIslands200 { + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r - 1][c] == '1') { + uf.union(r * nc + c, (r - 1) * nc + c); + } + if (r + 1 < nr && grid[r + 1][c] == '1') { + uf.union(r * nc + c, (r + 1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c - 1] == '1') { + uf.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c + 1] == '1') { + uf.union(r * nc + c, r * nc + c + 1); + } + } + } + } + + return uf.getCount(); + } +} + +class UnionFind { + int count; + int[] parent; + int[] rank; + + public UnionFind(char[][] grid) { + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { + if (parent[i] != i) + parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; + rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } +} diff --git a/Week 06/id_321/LeetCode_208_321.java b/Week 06/id_321/LeetCode_208_321.java new file mode 100644 index 000000000..17ad29d1c --- /dev/null +++ b/Week 06/id_321/LeetCode_208_321.java @@ -0,0 +1,75 @@ +package week06; + +class TrieNode { + private TrieNode[] links; + private final int R = 26; + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containskey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} + +public class Trie208 { + + private TrieNode root; + + public Trie208() { + root = new TrieNode(); + } + + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containskey(ch)) { + node.put(ch, new TrieNode()); + } + node = node.get(ch); + } + node.setEnd(); + } + + public boolean search(String word) { + TrieNode node = searchprefix(word); + return node != null && node.isEnd(); + } + + private TrieNode searchprefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (node.containskey(ch)) { + node = node.get(ch); + } else { + return null; + } + } + return node; + } + + public boolean startwith(String prefix) { + TrieNode node = searchprefix(prefix); + return node != null; + } +} diff --git a/Week 06/id_321/LeetCode_212_321.java b/Week 06/id_321/LeetCode_212_321.java new file mode 100644 index 000000000..e6f5a992c --- /dev/null +++ b/Week 06/id_321/LeetCode_212_321.java @@ -0,0 +1,83 @@ +package week06; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class FindWords212 { + + public List findWords(char[][] board, String[] words) { + + WordTrie myTrie = new WordTrie(); + TrieNode212 root = myTrie.root; + for (String s : words) { + myTrie.insert(s); + } + Set result = new HashSet<>(); + int m = board.length; + int n = board[0].length; + boolean[][] visited = new boolean[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + find(board, visited, i, j, m, n, result, root); + } + } + System.out.println(result); + return new LinkedList(result); + } + + private void find(char[][] board, boolean[][] visited, int i, int j, int m, int n, Set result, + TrieNode212 node) { + + if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j]) { + return; + } + node = node.child[board[i][j] - 'a']; + visited[i][j] = true; + if (node == null) { + visited[i][j] = false; + return; + } + if (node.isEnd) { + result.add(node.val); + } + find(board, visited, i + 1, j, m, n, result, node); + find(board, visited, i, j + 1, m, n, result, node); + find(board, visited, i, j - 1, m, n, result, node); + find(board, visited, i - 1, j, m, n, result, node); + + visited[i][j] = false; + + } +} + +class WordTrie { + public TrieNode212 root = new TrieNode212(); + + public void insert(String word) { + TrieNode212 node = root; + for (char ch : word.toCharArray()) { + if (node.child[ch - 'a'] == null) { + node.child[ch - 'a'] = new TrieNode212(); + node = node.child[ch - 'a']; + } else { + node = node.child[ch - 'a']; + } + } + node.isEnd = true; + node.val = word; + } +} + +class TrieNode212 { + + public String val; + public TrieNode212[] child = new TrieNode212[26]; + public boolean isEnd = false; + + public TrieNode212() { + + } + +} diff --git a/Week 06/id_321/LeetCode_547(2)_321.java b/Week 06/id_321/LeetCode_547(2)_321.java new file mode 100644 index 000000000..077025c3b --- /dev/null +++ b/Week 06/id_321/LeetCode_547(2)_321.java @@ -0,0 +1,53 @@ +package week06; + +public class FindCircleNum547two { + + public int findCircleNum1(int[][] M) { + int n = M.length; + Unionimpl un = new Unionimpl(n); + for (int i = 0; i < M.length - 1; i++) { + for (int j = i + 1; j < M.length; j++) { + if (M[i][j] == 1) { + un.union(i, j); + } + } + } + return un.count(); + } +} + +class Unionimpl { + private int count = 0; + private int[] parent; + + public Unionimpl(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int count() { + + return count; + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) { + return; + } + parent[rootP] = rootQ; + count--; + } +} \ No newline at end of file diff --git a/Week 06/id_321/LeetCode_547_321.java b/Week 06/id_321/LeetCode_547_321.java new file mode 100644 index 000000000..92aef51cf --- /dev/null +++ b/Week 06/id_321/LeetCode_547_321.java @@ -0,0 +1,54 @@ +package week06; + +import java.util.LinkedList; +import java.util.Queue; + +public class FindCircleNum547 { + + // bfs + public int findCircleNum1(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + Queue queue = new LinkedList<>(); + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + queue.add(i); + while (!queue.isEmpty()) { + int s = queue.remove(); + visited[s] = 1; + for (int j = 0; j < M.length; j++) { + if (M[s][j] == 1 && visited[j] == 0) + queue.add(j); + } + } + count++; + } + } + return count; + } + + // dfs + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + public int findCircleNum2(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + + // 鼯 + +} diff --git a/Week 06/id_336/LeetCode_336_208.js b/Week 06/id_336/LeetCode_336_208.js new file mode 100644 index 000000000..e9ea25872 --- /dev/null +++ b/Week 06/id_336/LeetCode_336_208.js @@ -0,0 +1,83 @@ +class TreeNode{ + constructor(){ + this.END = false; + this.links = new Array(26); + } + containsKey(letter) { + return this.links[letter.charCodeAt()-97] != undefined; + } + getCh(letter){ + return this.links[letter.charCodeAt()-97]; + } + putCh(letter,newTrieNode){ + this.links[letter.charCodeAt()-97] = newTrieNode; + } + setEnd(){ + this.END = true; + } + isEnd(){ + return this.END; + } +} +let root = null; +/** + * Initialize your data structure here. + */ +var Trie = function() { + root = new TreeNode(); +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +let searchPrefix = (word) => { + let currNode = root; + for(let i = 0;i < word.length;i++){ + if(currNode.containsKey(word[i])){ + currNode = currNode.getCh(word[i]); + }else{ + return null; + } + } + return currNode; +} +Trie.prototype.insert = function(word) { + let currNode = root; + for(let i = 0;i < word.length;i++){ + if(!currNode.containsKey(word[i])){ + currNode.putCh(word[i],new TreeNode()); + } + currNode = currNode.getCh(word[i]); + } + currNode.setEnd(); +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let currNode = searchPrefix(word); + return currNode != null && currNode.isEnd(); +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + let currNode = searchPrefix(prefix); + return currNode != null; +}; + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ \ No newline at end of file diff --git a/Week 06/id_336/LeetCode_336_212.js b/Week 06/id_336/LeetCode_336_212.js new file mode 100644 index 000000000..c78ed0e0a --- /dev/null +++ b/Week 06/id_336/LeetCode_336_212.js @@ -0,0 +1,95 @@ +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +var findWords = function(board, words) { + class TrieNode{ + constructor(){ + this.END = false; + this.children = new Array(26); + } + containsKey(letter){ + return this.children[letter.charCodeAt() - 97] != undefined; + } + put(letter,newTrieNode){ + this.children[letter.charCodeAt() - 97] = newTrieNode; + } + getNext(letter){ + return this.children[letter.charCodeAt() - 97]; + } + setEnd(){ + this.END = true; + } + isEnd(){ + return this.END; + } + } + let root = null; + let Trie = function(){ + root = new TrieNode(); + } + Trie.prototype.insert = (word) => { + let currNode = root; + for(let i = 0;i < word.length;i++){ + if(!currNode.containsKey(word[i])){ + currNode.put(word[i],new TrieNode()); + } + currNode = currNode.getNext(word[i]); + } + currNode.setEnd(); + } + let searchPrefix = (word) => { + let currNode = root; + for(let i = 0;i < word.length;i++){ + if(currNode.containsKey(word[i])){ + currNode = currNode.getNext(word[i]); + }else{ + return null; + } + } + return currNode; + } + Trie.prototype.search = (word) => { + let currNode = searchPrefix(word); + return currNode != null && currNode.isEnd(); + } + Trie.prototype.startsWith = (prefix) => { + let currNode = searchPrefix(prefix); + return currNode != null; + } + let m = board.length; + let n = board[0].length; + let wordsTrie = new Trie(); + for(let i = 0;i < words.length;i++){ + wordsTrie.insert(words[i]); + } + let dx = [-1,1,0,0]; + let dy = [0,0,-1,1]; + let boardDFS = (i,j,curStr) => { + let restore = board[i][j]; + curStr += restore; + if(wordsTrie.search(curStr) && result.indexOf(curStr) == -1){ + result.push(curStr); + } + if(!wordsTrie.startsWith(curStr)){ + return; + } + board[i][j] = '#'; + for(let r = 0; r < 4;r++){ + let tmp_i = dx[r] + i; + let tmp_j = dy[r] + j; + if(tmp_i >= 0 && tmp_i < m && tmp_j >= 0 && tmp_j < n && board[tmp_i][tmp_j] != '#'){ + boardDFS(tmp_i,tmp_j,curStr); + } + } + board[i][j] = restore; + } + let result = []; + for(let i = 0;i < m;i++){ + for(let j = 0;j < n;j++){ + boardDFS(i,j,''); + } + } + return result; +}; \ No newline at end of file diff --git a/Week 06/id_346/LeetCode_130_346.java b/Week 06/id_346/LeetCode_130_346.java new file mode 100644 index 000000000..ec9e55880 --- /dev/null +++ b/Week 06/id_346/LeetCode_130_346.java @@ -0,0 +1,60 @@ +package suanfa; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @auther: TKQ + * @Title: LeetCode_130_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-11-24 20:48 + */ +public class LeetCode_130_346 { + + public static void solve(char[][] board) { + if (board == null || board.length == 0) + return; + int rows = board.length, columns = board[0].length; + int[][] direction = { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } }; + for (int i = 0; i < rows; i++) + for (int j = 0; j < columns; j++) { + if ((i == 0 || i == rows - 1 || j == 0 || j == columns - 1) && board[i][j] == 'O') { + Queue queue = new LinkedList<>(); + board[i][j] = 'B'; + queue.offer(new Point(i, j)); + while (!queue.isEmpty()) { + Point point = queue.poll(); + for (int k = 0; k < 4; k++) { + int x = direction[k][0] + point.x; + int y = direction[k][1] + point.y; + if (x >= 0 && x < rows && y >= 0 && y < columns && board[x][y] == 'O') { + board[x][y] = 'B'; + queue.offer(new Point(x, y)); + } + } + } + } + } + for (int i = 0; i < rows; i++) + for (int j = 0; j < columns; j++) { + if (board[i][j] == 'B') + board[i][j] = 'O'; + else if (board[i][j] == 'O') + board[i][j] = 'X'; + } + + } + + + static class Point { + int x; + int y; + + Point(int x, int y) { + this.x = x; + this.y = y; + } + } +} diff --git a/Week 06/id_346/LeetCode_212_346.java b/Week 06/id_346/LeetCode_212_346.java new file mode 100644 index 000000000..ade3d09b4 --- /dev/null +++ b/Week 06/id_346/LeetCode_212_346.java @@ -0,0 +1,95 @@ +package suanfa; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * @auther: TKQ + * @Title: LeetCode_212_346 + * @Copyright: Copyright (c) 2019 + * @Description: 自己写不出来,抄了一遍>_<. + * @Company: + * @Created: 2019-11-24 20:37 + */ +public class LeetCode_212_346 { + + public List findWords(char[][] board, String[] words) { + //构建字典树 + wordTrie myTrie=new wordTrie(); + trieNode root=myTrie.root; + for(String s:words) + myTrie.insert(s); + + //使用set防止重复 + Set result =new HashSet<>(); + int m=board.length; + int n=board[0].length; + boolean [][]visited=new boolean[m][n]; + //遍历整个二维数组 + for(int i=0;i(result); + } + private void find(char [] [] board, boolean [][]visited,int i,int j,int m,int n,Set result,trieNode cur){ + //边界以及是否已经访问判断 + if(i<0||i>=m||j<0||j>=n||visited[i][j]) + return; + cur=cur.child[board[i][j]-'a']; + visited[i][j]=true; + if(cur==null) + { + //如果单词不匹配,回退 + visited[i][j]=false; + return; + } + //找到单词加入 + if(cur.isLeaf) + { + result.add(cur.val); + //找到单词后不能回退,因为可能是“ad” “addd”这样的单词得继续回溯 +// visited[i][j]=false; +// return; + } + find(board,visited,i+1,j,m,n,result,cur); + find(board,visited,i,j+1,m,n,result,cur); + find(board,visited,i,j-1,m,n,result,cur); + find(board,visited,i-1,j,m,n,result,cur); + //最后要回退,因为下一个起点可能会用到上一个起点的字符 + visited[i][j]=false; + } + + +} + +//字典树 +class wordTrie{ + public trieNode root=new trieNode(); + public void insert(String s){ + trieNode cur=root; + for(char c:s.toCharArray()){ + if(cur.child[c-'a']==null){ + cur.child [c-'a'] = new trieNode(); + cur=cur.child[c-'a']; + }else + cur=cur.child [c-'a']; + } + cur.isLeaf=true; + cur.val=s; + } +} +//字典树结点 +class trieNode{ + public String val; + public trieNode[] child=new trieNode[26]; + public boolean isLeaf=false; + + trieNode(){ + + } +} diff --git a/Week 06/id_361/NOTE.md b/Week 06/id_361/NOTE.md index a6321d6e2..88a6246a3 100644 --- a/Week 06/id_361/NOTE.md +++ b/Week 06/id_361/NOTE.md @@ -1,4 +1,59 @@ -# NOTE +#### 字典树和并查集 - +利用Trie树算法统计单词出现的次数的时间复杂度如下: +用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平均长度) + +爬楼梯、硬币问题 、兔子繁育->斐波拉契数列 + + +朋友圈:解法 + +1.DFS + +2.BFS + +3.并查集(Disjoint set) + +a.N-->各自独立集合 + +b.遍历好友关系矩阵M[i][j]=>合并 + +c.看有多少孤立的集合 + + + +#### 高级搜索 + +- 剪枝 +- 双向BFS +- 启发式搜索 + + +初级搜索 +1.朴素搜索 +2.优化方式:不重复(fibonacci)、剪枝(生成括号问题) +3.搜索方向:BFS、DFS + +- 回溯法 + +[双向BFS](https://leetcode-cn.com/problems/word-ladder/solution/dan-ci-jie-long-by-leetcode/) +算法 + +算法与之前描述的标准广搜方法相类似。 + +唯一的不同是我们从两个节点同时开始搜索,同时搜索的结束条件也有所变化。 + +我们现在有两个访问数组,分别记录从对应的起点是否已经访问了该节点。 + +如果我们发现一个节点被两个搜索同时访问,就结束搜索过程。因为我们找到了双向搜索的交点。过程如同从中间相遇而不是沿着搜索路径一直走。 + +双向搜索的结束条件是找到一个单词被两边搜索都访问过了。 + +最短变换序列的长度就是中间节点在两边的层次之和。因此,我们可以在访问数组中记录节点的层次。 + +#### AVL树和红黑树的实现和特性 + + +- AVL Tree 平衡二叉搜索树 +- Red Black Tree 近似平衡的二叉搜索树 diff --git a/Week 06/id_361/leetCode_200_361.js b/Week 06/id_361/leetCode_200_361.js new file mode 100644 index 000000000..81130455c --- /dev/null +++ b/Week 06/id_361/leetCode_200_361.js @@ -0,0 +1,104 @@ +//leetCode 200. 岛屿数量 + + +/** + * 解法1:DFS flood fill + * 时间复杂度 :O(M×N),其中 MM 和 NN 分别为行数和列数。 + * 空间复杂度 :O(M×N),此时整个网格均为陆地,深度优先搜索的深度达到 M×N + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function (grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + var nr = grid.length; + var nc = grid[0].length; + var num_islands = 0; + for (var r = 0; r < nr; ++r) { + for (var c = 0; c < nc; ++c) { + if ('1' === grid[r][c]) { //if 1 begin dfs + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; +} + +/** + * 解法2-dfs算法 + * @param grid + * @param r + * @param c + */ +function dfs(grid, r, c) { + var nr = grid.length; + var nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + grid[r][c] = '0'; // flood fill + //4 directions + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); +} + +//////////////////////////////////////////////////////////////////////////// +/** + * 解法3:DFS + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + if(!grid || grid.length == 0){ + return 0; + } + var len = grid.length; + var size = grid[0].length; + var island = 0; + // 从右到左 队列 + var queue = []; + // 方向向量 + var dx = [-1,1,0,0]; + var dy = [0,0,-1,1]; + // dfs 推平 + function sink(i,j){ + // terminator + if(grid[i][j] == '0'){ + return 0; + } + // process + grid[i][j] = '0'; + // drill down + for(var k = 0;k< dx.length;k++){ + var x = i + dx[k]; + var y = j + dy[k]; + if(x >= 0 && x < grid.length && y >=0 && y0){ + var tmpIsland = queue.shift(); + sink(tmpIsland[0],tmpIsland[1]); + } + } + } + } + return island; +}; + diff --git a/Week 06/id_361/leetCode_200_361.py b/Week 06/id_361/leetCode_200_361.py new file mode 100644 index 000000000..55081a739 --- /dev/null +++ b/Week 06/id_361/leetCode_200_361.py @@ -0,0 +1,82 @@ +from typing import List + + +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + + class UnionFind: + + def __init__(self, n): + self.count = n + self.parent = [i for i in range(n)] + self.rank = [1 for _ in range(n)] + + def get_count(self): + return self.count + + def find(self, p): + while p != self.parent[p]: + self.parent[p] = self.parent[self.parent[p]] + p = self.parent[p] + return p + + def is_connected(self, p, q): + return self.find(p) == self.find(q) + + def union(self, p, q): + p_root = self.find(p) + q_root = self.find(q) + if p_root == q_root: + return + + if self.rank[p_root] > self.rank[q_root]: + self.parent[q_root] = p_root + elif self.rank[p_root] < self.rank[q_root]: + self.parent[p_root] = q_root + else: + self.parent[q_root] = p_root + self.rank[p_root] += 1 + + self.count -= 1 + + row = len(grid) + # 特判 + if row == 0: + return 0 + col = len(grid[0]) + + def get_index(x, y): + return x * col + y + + # 注意:我们不用像 DFS 和 BFS 一样,4 个方向都要尝试,只要看一看右边和下面就可以了 + directions = [(1, 0), (0, 1)] + # 多开一个空间,把水域 "0" 都归到这个虚拟的老大上 + dummy_node = row * col + + # 多开的一个空间就是那个虚拟的空间 + uf = UnionFind(dummy_node + 1) + for i in range(row): + for j in range(col): + # 如果是水域,都连到那个虚拟的空间去 + if grid[i][j] == '0': + uf.union(get_index(i, j), dummy_node) + if grid[i][j] == '1': + # 向下向右如果都是陆地,即 "1",就要合并一下 + for direction in directions: + new_x = i + direction[0] + new_y = j + direction[1] + if new_x < row and new_y < col and grid[new_x][new_y] == '1': + uf.union(get_index(i, j), get_index(new_x, new_y)) + # 不要忘记把那个虚拟结点减掉 + return uf.get_count() - 1 + + +if __name__ == '__main__': + grid = [['1', '1', '1', '1', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '0']] + solution = Solution() + result = solution.numIslands(grid) + print(result) + diff --git a/Week 06/id_361/leetCode_433_361.js b/Week 06/id_361/leetCode_433_361.js new file mode 100644 index 000000000..75db41675 --- /dev/null +++ b/Week 06/id_361/leetCode_433_361.js @@ -0,0 +1,85 @@ +// 433. 最小基因变化 + +/** + * BFS + /** + * @param {string} start + * @param {string} end + * @param {string[]} bank + * @return {number} + */ +var minMutation = function(start, end, bank) { + if(start == end){ + return 0; + } + var bankSet = new Map(); + for(var i = 0;i 1){ + break; + } + } + } + if(diff == 1 && !visited.has(tmpBank)){ + visited.set(tmpBank,true); + recurse(tmpBank,level+1); + visited.delete(tmpBank); + } + } + } + recurse(start,level); + return (minLevel ^ Number.MAX_SAFE_INTEGER) == 0 ? -1 : minLevel; +}; + diff --git a/Week 06/id_366/Leetcode_208_366.java b/Week 06/id_366/Leetcode_208_366.java new file mode 100644 index 000000000..5217b59f3 --- /dev/null +++ b/Week 06/id_366/Leetcode_208_366.java @@ -0,0 +1,71 @@ +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class TrieNode { + public char val; + public boolean isWord; + public TrieNode[] children = new TrieNode[26]; + public TrieNode() {} + TrieNode(char c){ + TrieNode node = new TrieNode(); + node.val = c; + } +} +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + root.val = ' '; + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode ws = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(ws.children[c - 'a'] == null){ + ws.children[c - 'a'] = new TrieNode(c); + } + ws = ws.children[c - 'a']; + } + ws.isWord = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode ws = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return ws.isWord; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode ws = root; + for(int i = 0; i < prefix.length(); i++){ + char c = prefix.charAt(i); + if(ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return true; + } +} + +/** + * 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); + */ +// @lc code=end + diff --git a/Week 06/id_366/Leetcode_547_366.java b/Week 06/id_366/Leetcode_547_366.java new file mode 100644 index 000000000..1e4cbe52f --- /dev/null +++ b/Week 06/id_366/Leetcode_547_366.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + */ + +// @lc code=start +//抄的国际站大神的代码 嗯 打算先背下来 +class Solution { + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } +} +// @lc code=end + diff --git a/Week 06/id_371/Leetcode_1091_371.java b/Week 06/id_371/Leetcode_1091_371.java new file mode 100644 index 000000000..20b3f6dc7 --- /dev/null +++ b/Week 06/id_371/Leetcode_1091_371.java @@ -0,0 +1,65 @@ +import java.util.LinkedList; +import java.util.Queue; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-21 04:50 + **/ + +public class Leetcode_1091_371 { + + + /** + * 仿解2:双向 BFS + * @author Shaobo.Qian + * @date 2019/11/21 + * @link https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/solution/java-shuang-xiang-bfs-ji-bai-100-by-hao-shou-bu-ju/ + */ + public int shortestPathBinaryMatrix2(int[][] grid) { + return -1; + } + /** + * 仿解1:BFS + * + * @author Shaobo.Qian + * @date 2019/11/21 + * @link https://leetcode.com/problems/shortest-path-in-binary-matrix/discuss/312706/JAVA-BFS + */ + + public int shortestPathBinaryMatrix1(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + if (grid[0][0] == 1 || grid[m - 1][n - 1] == 1) return -1; + + //1.定义二维数组表示在二维坐标系上八连通方向上各前进一步 + int[][] dir = new int[][]{{0, 1}, {0, -1}, {-1, 0}, {1, 0}, {1, -1}, {1, 1}, {-1, -1}, {-1, 1}}; + //2.定义二维数组标记每个单元格是否走过 + boolean[][] visited = new boolean[m][n]; + //3.创建容器 + Queue queue = new LinkedList<>(); + visited[0][0] = true; + queue.add(new int[]{0, 0}); + int step = 0; + //4.循环当前容器中所有的元素,判断是否找到目标 + while (!queue.isEmpty()) { + step++; + int size = queue.size(); + for (int i = 0; i < size; i++) { + int[] pop = queue.remove(); + if (pop[0] == m - 1 && pop[1] == n - 1) return step; + //5.八连通方向上各前进一步,找到新的节点,放入容器 + for (int k = 0; k < 8; k++) { + int nextX = dir[k][0] + pop[0]; + int nextY = dir[k][1] + pop[1]; + if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n && !visited[nextX][nextY] && grid[nextX][nextY] == 0) { + queue.add(new int[]{nextX, nextY}); + visited[nextX][nextY] = true; + } + } + } + } + return -1; + } +} diff --git a/Week 06/id_371/Leetcode_127_371.java b/Week 06/id_371/Leetcode_127_371.java new file mode 100644 index 000000000..47b635926 --- /dev/null +++ b/Week 06/id_371/Leetcode_127_371.java @@ -0,0 +1,9 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-20 05:47 + **/ +public class Leetcode_127_371 { + +} diff --git a/Week 06/id_371/Leetcode_130_371.java b/Week 06/id_371/Leetcode_130_371.java new file mode 100644 index 000000000..e2ca2adc2 --- /dev/null +++ b/Week 06/id_371/Leetcode_130_371.java @@ -0,0 +1,116 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-19 18:58 + **/ + +/** + * 仿解:并查集 + * link:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/ + */ +public class Leetcode_130_371 { + class UnionFind { + int[] parents; + + /** + * 给所有节点设置标识(父节点的值) + * + * @param totalNodes + */ + public UnionFind(int totalNodes) { + parents = new int[totalNodes]; + for (int i = 0; i < totalNodes; i++) { + parents[i] = i; + } + } + + /** + * 合并两个节点 + * + * @param node1 + * @param node2 + */ + void union(int node1, int node2) { + int root1 = find(node1); + int root2 = find(node2); + if (root1 == root2) return; + parents[root2] = root1; + } + + /** + * 查找根节点 + * + * @param node + * @return + */ + int find(int node) { + while (parents[node] != node) {//路径压缩,如果当前节点不是根节点,下一次直接查看爷爷结点是不是根节点 + parents[node] = parents[parents[node]]; + node = parents[node]; + } + return node; + } + + boolean isConnected(int node1, int node2) { + return find(node1) == find(node2); + } + } + + public void solve(char[][] board) { + int rows = board.length; + //1.边界判断 + if (board == null || rows == 0) return; + int cols = board[0].length; + //2.初始化:初始化所有节点, 即父节点的值是自身==>即当前节点就是根节点(parents[i]=i) + UnionFind uf = new UnionFind(rows * cols + 1); + int dummyNode = rows * cols;//该节点是一个虚拟结点,board中不存在 + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') { + int currIndex = nodeIndex(i, j, cols); + //3.遇到边界上的O的结点,和dummyNode结点进行合并,形成一个连通区 + if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) { + uf.union(currIndex, dummyNode); + } else { + //4.和上下左右存在的'0'结点合并成一个联通区 + if (i > 0 && board[i - 1][j] == 'O') { + uf.union(currIndex, nodeIndex(i - 1, j, cols)); + } + if (i < rows - 1 && board[i + 1][j] == 'O') { + uf.union(currIndex, nodeIndex(i + 1, j, cols)); + } + if (j > 0 && board[i][j - 1] == 'O') { + uf.union(currIndex, nodeIndex(i, j - 1, cols)); + } + if (j < cols -1 && board[i][j + 1] == 'O') { + uf.union(currIndex, nodeIndex(i, j + 1, cols)); + } + } + + } + } + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (uf.isConnected(nodeIndex(i, j, cols), dummyNode)) { + board[i][j] = 'O'; + } else { + board[i][j] = 'X'; + } + } + } + + + } + + /** + * 将二维的坐标转化成一维的唯一标识 + */ + int nodeIndex(int i, int j, int cols) { + return i * cols + j; + } + +} diff --git a/Week 06/id_371/Leetcode_208_371.java b/Week 06/id_371/Leetcode_208_371.java new file mode 100644 index 000000000..3bb832358 --- /dev/null +++ b/Week 06/id_371/Leetcode_208_371.java @@ -0,0 +1,109 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-19 10:24 + **/ + +public class Leetcode_208_371 { + /** + * 仿解1:字典树 + * + * @author Shaobo.Qian + * @date 2019/11/19 + * @link: https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/ + */ + class Trie { + class TrieNode { + private TrieNode[] links;//索引结点数组(R links to node children) + private final int R = 26; + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(TrieNode node, char ch) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + + } + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + * 一层层往下插入 + */ + public void insert(String word) { + TrieNode node = root; + char[] chars = word.toCharArray(); + for (char currChar : chars) { + if (!node.containsKey(currChar)) { + node.put(new TrieNode(), currChar); + } + node = node.get(currChar); //得到下一层的节点 + } + node.setEnd(); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode node = root; + char[] chars = prefix.toCharArray(); + for (char currChar : chars) { + if (node.containsKey(currChar)) { + node = node.get(currChar); + } else { + return false; + } + } + return true; + } + public TrieNode searchPrefix(String prefix) { + TrieNode node = root; + char[] chars = prefix.toCharArray(); + for (char currChar : chars) { + if (node.containsKey(currChar)) { + node = node.get(currChar); + } else { + return null; + } + } + return node; + } + } +} diff --git a/Week 06/id_371/Leetcode_212_371.java b/Week 06/id_371/Leetcode_212_371.java new file mode 100644 index 000000000..01bd1422b --- /dev/null +++ b/Week 06/id_371/Leetcode_212_371.java @@ -0,0 +1,77 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-19 10:12 + **/ + +public class Leetcode_212_371 { + public static void main(String[] args) { + + } + class TrieNode { + private TrieNode[] children = new TrieNode[26]; + String word; + } + + /** + * 仿解1:字典树+回溯(剪枝) + * + * @author Shaobo.Qian + * @date 2019/11/19 + * @link https://leetcode.com/problems/word-search-ii/discuss/59784/My-simple-and-clean-Java-code-using-DFS-and-Trie + * @link https://leetcode.com/problems/word-search-ii/discuss/59780/Java-15ms-Easiest-Solution-(100.00) + */ + public List findWords(char[][] board, String[] words) { + List res = new ArrayList<>(); + TrieNode root = buildTrie(words); + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + dfs(board, i, j, root, res); + } + } + + return res; + } + + private void dfs(char[][] board, int i, int j, TrieNode currNode, List res) { + //1.terminator + if ( i < 0 || i < j || i >= board.length || j >= board[0].length) return; + //2.处理当前层逻辑 + char c = board[i][j]; + if(c == '#' || currNode.children[c - 'a'] == null) return; + currNode = currNode.children[c - 'a']; + if (currNode.word != null) { + res.add(currNode.word); + currNode.word = null;//since we have visited this leaf node, then set "word" null , make sure we do not visit it once again. + } + + board[i][j] = '#'; //将当前位置标记为已访问 + //3.drill down + dfs(board, i - 1, j, currNode, res); + dfs(board, i, j - 1, currNode, res); + dfs(board, i + 1, j, currNode, res); + dfs(board, i, j + 1, currNode, res); + + //4.还原状态 + board[i][j] = c; + + } + + public TrieNode buildTrie(String[] words) { + TrieNode root = new TrieNode(); + for (String word : words) { + TrieNode currNode = root; + for (char c : word.toCharArray()) { + int index = c - 'a'; + if (currNode.children[index] == null) currNode.children[index] = new TrieNode(); + currNode = currNode.children[index]; + } + currNode.word = word; + } + return root; + } +} diff --git a/Week 06/id_371/Leetcode_36_371.java b/Week 06/id_371/Leetcode_36_371.java new file mode 100644 index 000000000..72e1eb395 --- /dev/null +++ b/Week 06/id_371/Leetcode_36_371.java @@ -0,0 +1,75 @@ +import java.util.HashMap; +import java.util.HashSet; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-20 05:46 + **/ + +public class Leetcode_36_371 { + + /** + * + * @author Shaobo.Qian + * @date 2019/11/20 + */ + public boolean isValidSudoku1(char[][] board) { + HashSet[] rows = new HashSet[9]; + HashSet[] cols = new HashSet[9]; + HashSet[] boxes = new HashSet[9]; + + for (int i = 0; i < 9; i++) { + rows[i] = new HashSet(); + cols[i] = new HashSet(); + boxes[i] = new HashSet(); + } + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + int num = (int) board[i][j]; + if (board[i][j] != '.') { + int boxIndex = (i / 3) * 3 + j / 3; + if (rows[i].contains(num) || cols[j].contains(num) || boxes[boxIndex].contains(num)) return false; + rows[i].add(num); + cols[j].add(num); + boxes[boxIndex].add(num); + } + } + } + return true; + } + /** + * 仿解1:迭代(关键:对子数独的映射) + * + * @author Shaobo.Qian + * @date 2019/11/20 + * @link https://leetcode-cn.com/problems/valid-sudoku/solution/you-xiao-de-shu-du-by-leetcode/ + */ + public boolean isValidSudoku(char[][] board) { + HashMap[] rows = new HashMap[9]; + HashMap[] cols = new HashMap[9]; + HashMap[] boxes = new HashMap[9]; + + for (int i = 0; i < 9; i++) { + rows[i] = new HashMap(); + cols[i] = new HashMap(); + boxes[i] = new HashMap(); + } + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + int num = (int) board[i][j]; + if (board[i][j] != '.') { + int boxIndex = (i / 3) * 3 + j / 3; + if (rows[i].containsKey(num) || cols[j].containsKey(num) || boxes[boxIndex].containsKey(num)) return false; + rows[i].put(num, 1); + cols[j].put(num, 1); + boxes[boxIndex].put(num, 1); + } + } + } + return true; + } +} diff --git a/Week 06/id_371/Leetcode_37_371.java b/Week 06/id_371/Leetcode_37_371.java new file mode 100644 index 000000000..5a3cf2a13 --- /dev/null +++ b/Week 06/id_371/Leetcode_37_371.java @@ -0,0 +1,75 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-20 06:23 + **/ + +public class Leetcode_37_371 { + + /** + * 仿解1:回溯 + * + * @author Shaobo.Qian + * @date 2019/11/20 + * @link https://leetcode-cn.com/problems/sudoku-solver/solution/hui-su-fa-jie-shu-du-by-i_use_python/ + */ + public void solveSudoku(char[][] board) { + // 1.标记 行,列,小数独中的数字是否被使用过(用来剪枝) + boolean[][] rowUsed = new boolean[9][10]; + boolean[][] colUsed = new boolean[9][10]; + boolean[][][] boxUsed = new boolean[3][3][10]; + //2.初始化 + for (int row = 0; row < board.length; row++) { + for (int col = 0; col < board[0].length; col++) { + int num = board[row][col] - '0'; + if (num >= 1 && num <= 9) { + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row / 3][col / 3][num] = true; + } + } + } + //3.回溯 + backtrace(rowUsed, colUsed, boxUsed, board, 0, 0); + } + + private boolean backtrace(boolean[][] rowUsed, boolean[][] colUsed, boolean[][][] boxUsed, char[][] board, int row, int col) { + //1.terminator + if (col == board[0].length) { + col = 0; + row++; + if (row == board.length) { + return true; + } + } + + //2.current level + if (board[row][col] == '.') { + //尝试填充1-9 + for (int num = 1; num <= 9; num++) { + boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || boxUsed[row/3][col/3][num]); + if (canUsed) { + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row/3][col/3][num] = true; + //填充 + board[row][col] = (char) ('0' + num); + //3.drill down + if (backtrace(rowUsed, colUsed, boxUsed, board, row, col + 1)) { + return true; + } + //4.restore status + board[row][col] = '.'; + rowUsed[row][num] = false; + colUsed[col][num] = false; + boxUsed[row / 3][col / 3][num] = false; + + } + } + } else { + return backtrace(rowUsed, colUsed, boxUsed, board, row, col + 1); + } + return false; + } +} diff --git a/Week 06/id_371/Leetcode_547_371.java b/Week 06/id_371/Leetcode_547_371.java new file mode 100644 index 000000000..8a4e0f300 --- /dev/null +++ b/Week 06/id_371/Leetcode_547_371.java @@ -0,0 +1,55 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-19 15:39 + **/ + +public class Leetcode_547_371 { + + /** + * 查找元素 i 的根节点 + * @param i + * @param parent 所有元素的父节点 + * @return + */ + public int find(int i, int[] parent) { + if (parent[i] == -1) return i; + return find(parent[i], parent); + } + + public void union(int i, int j, int[] parent) { + int iRoot = find(i, parent); + int jRoot = find(j, parent); + if(iRoot == jRoot) return; + parent[iRoot] = jRoot; + } + + /** + * 仿解1:并查集 + * @param M + * @return + * @link https://leetcode-cn.com/problems/friend-circles/solution/peng-you-quan-by-leetcode/ + */ + public int findCircleNum(int[][] M) { + int len = M.length; + int[] parent = new int[len]; + Arrays.fill(parent, -1); + for (int i = 0; i < len; i++) { + for (int j = 0; j < len; j++) { + if (M[i][j] == 1 && i != j) { //i == j就是自己 + union(i, j, parent); + } + } + } + + int count = 0; + for (int i = 0; i < len; i++) { + if(parent[i] == -1) count++; + } + return count; + } + +} diff --git a/Week 06/id_371/Leetcode_773_371.java b/Week 06/id_371/Leetcode_773_371.java new file mode 100644 index 000000000..8c71d40e8 --- /dev/null +++ b/Week 06/id_371/Leetcode_773_371.java @@ -0,0 +1,67 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-21 06:02 + **/ + +public class Leetcode_773_371 { + public static void main(String[] args) { + int[][] board = new int[][]{{1, 2, 3}, {4, 0, 5}}; + int step = slidingPuzzle(board); + System.out.println("step = " + step); + } + /** + * 仿解1: BFS + * + * @author Shaobo.Qian + * @date 2019/11/21 + * @link https://leetcode.com/problems/sliding-puzzle/discuss/146652/Java-8ms-BFS-with-algorithm-explained + */ + public static int slidingPuzzle(int[][] board) { + String target = "123450"; + String start = ""; + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + start += board[i][j]; + } + } + //1.定义前进到下一步的方向(字符串中的索引位置<===二维坐标系) + int[][] dirs = new int[][]{{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}}; + Queue queue = new LinkedList<>(); + queue.add(start); + Set visited = new HashSet<>(); + visited.add(start); + int step = 0; + + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + String curr = queue.remove(); + if (curr.equals(target)) return step; + int zeroIndex = curr.indexOf('0'); + for (int nextIndex : dirs[zeroIndex]) { + String next = swap(zeroIndex, nextIndex, curr); + if (visited.contains(next)) continue; + queue.offer(next); + visited.add(next); + } + + } + step++; + } + return -1; + } + + private static String swap(int i, int j, String str) { + StringBuilder sb = new StringBuilder(str); + sb.setCharAt(i, str.charAt(j)); + sb.setCharAt(j, str.charAt(i)); + return sb.toString(); + } +} diff --git a/Week 06/id_381/leetcode-208.py b/Week 06/id_381/leetcode-208.py new file mode 100644 index 000000000..3a727a3b4 --- /dev/null +++ b/Week 06/id_381/leetcode-208.py @@ -0,0 +1,41 @@ +class Trie: + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.end_of_word = '#' + + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for w in word: + node = node.setdefault(w, {}) + node[self.end_of_word] = self.end_of_word + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for w in word: + if w not in node: + return False + node = node[w] + return self.end_of_word in node + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for w in prefix: + if w not in node: + return False + node = node[w] + return True diff --git a/Week 06/id_381/leetcode-212.py b/Week 06/id_381/leetcode-212.py new file mode 100644 index 000000000..d184ef5aa --- /dev/null +++ b/Week 06/id_381/leetcode-212.py @@ -0,0 +1,37 @@ +class Trie(object): + def __init__(self): + self.root = {} + self.end_word = '#' + + def insert(self, word): + node = self.root + for w in word: + node = node.setdefault(w, {}) + node[self.end_word] = self.end_word + + +class Solution: + def dfs(self, node, i, j, path): + if '#' in node and node['#']=='#': + self.result.append(path) + node['#'] = '##' + if i > len(self.board)-1 or i < 0 or j > len(self.board[0])-1 or j < 0: + return + char = self.board[i][j] + if char not in node: + return + self.board[i][j] = '*' + for ii, jj in [(i+1, j), (i-1, j), (i, j-1), (i, j+1)]: + self.dfs(node[char], ii, jj, path+char) + self.board[i][j] = char + + def findWords(self, board, words) -> list: + self.board = board + self.result = [] + trie = Trie() + for word in words: + trie.insert(word) + for i, tmp_i in enumerate(board): + for j, tmp_j in enumerate(tmp_i): + self.dfs(trie.root, i, j, '') + return self.result diff --git a/Week 06/id_386/LeetCode_200_386.java b/Week 06/id_386/LeetCode_200_386.java new file mode 100644 index 000000000..34b5ecfb7 --- /dev/null +++ b/Week 06/id_386/LeetCode_200_386.java @@ -0,0 +1,22 @@ +class Solution { + public int numIslands(char[][] grid) { + int count = 0; + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(grid[i][j] == '1'){ + dfs(grid, i, j); + count++; + } + } + } + return count; + } + private void dfs(char[][] grid, int i, int j){ + if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return; + grid[i][j] = '0'; + dfs(grid, i + 1, j); + dfs(grid, i, j + 1); + dfs(grid, i - 1, j); + dfs(grid, i, j - 1); + } +} diff --git a/Week 06/id_386/LeetCode_547_386.java b/Week 06/id_386/LeetCode_547_386.java new file mode 100644 index 000000000..293707937 --- /dev/null +++ b/Week 06/id_386/LeetCode_547_386.java @@ -0,0 +1,39 @@ +class Solution { + private int[] parent; + // 并查集 + public int findCircleNum(int[][] M) { + int N = M.length; + parent = new int[N]; + // 默认初始化-1自己为根 + Arrays.fill(parent, -1); + + for (int i = 0; i < N; i++) { + for (int j = i + 1; j < N; j++) { + if (M[i][j] == 1) { + union(i, j); + } + } + } + // 查找所有的根(值为-1)的个数即为集合的个数 + int cnt = 0; + for (int id : parent) { + if (id == -1) + cnt++; + } + return cnt; + } + + private void union(int x, int y) { + int xp = findRoot(x); + int yp = findRoot(y); + if (xp != yp) // 如果已经在同一个集合中则不必合并 + parent[yp] = xp; + } + + private int findRoot(int id) { + if (parent[id] == -1) + return id; + parent[id] = findRoot(parent[id]); // 路径压缩 + return parent[id]; + } +} diff --git a/Week 06/id_406/Leetcode_208_406.py b/Week 06/id_406/Leetcode_208_406.py new file mode 100644 index 000000000..cb62a7a97 --- /dev/null +++ b/Week 06/id_406/Leetcode_208_406.py @@ -0,0 +1,50 @@ +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.lookup = {} + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + tree[a] = {} + tree = tree[a] + tree["#"] = "#" + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + return False + tree = tree[a] + if "#" in tree: + return True + return False + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + tree = self.lookup + for a in prefix: + if a not in tree: + return False + tree = tree[a] + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) diff --git a/Week 06/id_406/Leetcode_36_406.py b/Week 06/id_406/Leetcode_36_406.py new file mode 100644 index 000000000..5b42750fe --- /dev/null +++ b/Week 06/id_406/Leetcode_36_406.py @@ -0,0 +1,23 @@ +class Solution: + def isValidSudoku(self, board: List[List[str]]) -> bool: + rows = [{} for i in range(9)] + columns = [{} for i in range(9)] + boxes = [{} for i in range(9)] + + # validate a board + for i in range(9): + for j in range(9): + num = board[i][j] + if num != '.': + num = int(num) + box_index = (i // 3 ) * 3 + j // 3 + + # keep the current cell value + rows[i][num] = rows[i].get(num, 0) + 1 + columns[j][num] = columns[j].get(num, 0) + 1 + boxes[box_index][num] = boxes[box_index].get(num, 0) + 1 + + # check if this value has been already seen before + if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1: + return False + return True diff --git a/Week 06/id_406/Leetcode_37_406.py b/Week 06/id_406/Leetcode_37_406.py new file mode 100644 index 000000000..4e05657f0 --- /dev/null +++ b/Week 06/id_406/Leetcode_37_406.py @@ -0,0 +1,37 @@ +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + row = [set(range(1, 10)) for _ in range(9)] + col = [set(range(1, 10)) for _ in range(9)] + block = [set(range(1, 10)) for _ in range(9)] + + empty = [] + for i in range(9): + for j in range(9): + if board[i][j] != '.': + val = int(board[i][j]) + row[i].remove(val) + col[j].remove(val) + block[(i // 3) * 3 + j // 3].remove(val) + else: + empty.append((i, j)) + + def backtrack(iter=0): + if iter == len(empty): + return True + i, j = empty[iter] + b = (i // 3)* 3 + j // 36 + for val in row[i] & col[j] & block[b]: + row[i].remove(val) + col[j].remove(val) + block[b].remove(val) + board[i][j] = str(val) + if backtrack(iter+1): + return True + row[i].add(val) + col[j].add(val) + block[b].add(val) + return False + backtrack() diff --git a/Week 06/id_416/LeetCode_200_416.java b/Week 06/id_416/LeetCode_200_416.java new file mode 100644 index 000000000..37bc50b7b --- /dev/null +++ b/Week 06/id_416/LeetCode_200_416.java @@ -0,0 +1,81 @@ + +public class LeetCode_208_416{ + class UnionFind { + int count; // # of connected components + int[] parent; + int[] rank; + + public UnionFind(char[][] grid) { // for problem 200 + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { // path compression + if (parent[i] != i) parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { // union with rank + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r-1][c] == '1') { + uf.union(r * nc + c, (r-1) * nc + c); + } + if (r + 1 < nr && grid[r+1][c] == '1') { + uf.union(r * nc + c, (r+1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c-1] == '1') { + uf.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c+1] == '1') { + uf.union(r * nc + c, r * nc + c + 1); + } + } + } + } + + return uf.getCount(); + } +} \ No newline at end of file diff --git a/Week 06/id_416/LeetCode_208_416.java b/Week 06/id_416/LeetCode_208_416.java new file mode 100644 index 000000000..9cf78dcef --- /dev/null +++ b/Week 06/id_416/LeetCode_208_416.java @@ -0,0 +1,46 @@ + +public class LeetCode_208_416{ + TrieNode root = new TrieNode(); + public class TrieNode{ + TrieNode[] child; + boolean is_end; + public TrieNode() { + child = new TrieNode[26]; + is_end = false; + } + } + + public void insert(String word) { + TrieNode cNode = root; + for(int i = 0;i < word.length();i++) { + char c = word.charAt(i); + if(cNode.child[c - 'a'] == null) { + cNode.child[c - 'a'] = new TrieNode(); + } + cNode = cNode.child[c - 'a']; + } + cNode.is_end = true; + } + public boolean search(String word) { + TrieNode cNode = root; + for(int i = 0;i < word.length();i++) { + char c = word.charAt(i); + if(cNode.child[c - 'a'] == null) { + return false; + } + cNode = cNode.child[c - 'a']; + } + return cNode.is_end; + } + public boolean startsWith(String prefix) { + TrieNode cNode = root; + for(int i = 0;i < word.length();i++) { + char c = word.charAt(i); + if(cNode.child[c - 'a'] == null) { + return false; + } + cNode = cNode.child[c - 'a']; + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_416/LeetCode_212_416.java b/Week 06/id_416/LeetCode_212_416.java new file mode 100644 index 000000000..aa8a608ff --- /dev/null +++ b/Week 06/id_416/LeetCode_212_416.java @@ -0,0 +1,52 @@ + +public class LeetCode_208_416{ + + public class TrieNode{ + TrieNode[] child = new TrieNode[26]; + String word; + } + public TrieNode insert(String[] words) { + TrieNode root = new TrieNode(); + for(String word : words) { + TrieNode p = root; + for(int i = 0;i < word.length();i++) { + char c = word.charAt(i); + if(p.child[c - 'a'] == null) { + p.child[c - 'a'] = new TrieNode(); + } + p = p.child[c - 'a']; + } + p.word = word; + } + return root; + } + public List findWords(char[][] board, String[] words) { + List res = new ArrayList(); + TrieNode root = insert(words); + for(int i = 0;i < board.length;i++) { + for(int j = 0; j res) { + //terminator + //current process logic + //drill down + char c = board[i][j]; + if(c == '#' || p.child[c - 'a'] == null) return; + p = p.child[c - 'a']; + if(p.word != null) { + res.add(p.word); + p.word = null; + } + board[i][j] = '#'; + if(i > 0 ) dfs(board,i - 1,j,p,res); + if(j > 0 ) dfs(board,i,j - 1,p,res); + if(i < board.length - 1) dfs(board,i + 1,j,p,res); + if(j < board[0].length - 1) dfs(board,i , j + 1,p,res); + board[i][j] = c; + } + +} \ No newline at end of file diff --git a/Week 06/id_416/LeetCode_547_416.java b/Week 06/id_416/LeetCode_547_416.java new file mode 100644 index 000000000..f060a1c36 --- /dev/null +++ b/Week 06/id_416/LeetCode_547_416.java @@ -0,0 +1,32 @@ + +public class LeetCode_208_416{ + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_416/NOTE.md b/Week 06/id_416/NOTE.md index a6321d6e2..36fb7fe08 100644 --- a/Week 06/id_416/NOTE.md +++ b/Week 06/id_416/NOTE.md @@ -1,4 +1,5 @@ # NOTE +test diff --git a/Week 06/id_431/LeetCode_130_431.java b/Week 06/id_431/LeetCode_130_431.java new file mode 100644 index 000000000..abafacaf5 --- /dev/null +++ b/Week 06/id_431/LeetCode_130_431.java @@ -0,0 +1,111 @@ +package medium; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/26 + */ +public class SurroundedRegions { + /** + * DFS + * @param board + */ +// public void solve(char[][] board) { +// if (board.length == 0) return; +// for (int i = 0; i < board.length; i++) { +// if (board[i][0] == 'O') _dfs(board, i, 0); +// if (board[i][board[0].length - 1] == 'O') _dfs(board, i, board[0].length - 1); +// } +// for (int j = 0; j < board[0].length; j++) { +// if (board[0][j] == 'O') _dfs(board, 0, j); +// if (board[board.length - 1][j] == 'O') _dfs(board, board.length - 1, j); +// } +// for (int i = 0; i < board.length; i++) { +// for (int j = 0; j < board[0].length; j++) { +// if (board[i][j] == 'O') board[i][j] = 'X'; +// else if (board[i][j] == '*') board[i][j] = 'O'; +// } +// } +// } +// +// private void _dfs(char[][] board, int i, int j){ +// if (i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1 +// || board[i][j] == 'X' || board[i][j] == '*') return; +// board[i][j] = '*'; +// _dfs(board, i + 1, j); +// _dfs(board, i - 1, j); +// _dfs(board, i, j + 1); +// _dfs(board, i, j - 1); +// } + + + /** + * 使用并查集 + * @param board + */ + public void solve(char[][] board) { + int row = board.length; + if (row == 0) return; + int col = board[0].length; + UnionFind uf = new UnionFind(board); + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (board[i][j] == 'O') { + int tmpBoard = i * col + j; + if (i == 0 || i == row - 1 || j == 0 || j == col - 1) + uf.unionSet(row * col, tmpBoard); + else { + if (board[i + 1][j] == 'O') uf.unionSet(tmpBoard, (i + 1) * col + j); + if (board[i - 1][j] == 'O') uf.unionSet(tmpBoard, (i - 1) * col + j); + if (board[i][j - 1] == 'O') uf.unionSet(tmpBoard, i * col + j - 1); + if (board[i][j + 1] == 'O') uf.unionSet(tmpBoard, i * col + j + 1); + } + } + } + } + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if ( board[i][j] == 'O' && uf.find(i * col + j) != uf.find( row * col)) { + board[i][j] = 'X'; + } + } + } + } + + class UnionFind { + int[] parent; + + UnionFind (char[][] board) { + int row = board.length; + int col = board[0].length; + parent = new int[row * col + 1]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (board[i][j] == 'O') { + int val = i * col + j; + parent[val] = val; + } + } + } + parent[row * col] = row * col; + } + + int find (int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + void unionSet(int p, int q) { + int rootp = find(p); + int rootq = find(q); + if (rootp != rootq) { + parent[rootq] = rootp; + } + } + } +} diff --git a/Week 06/id_431/LeetCode_200_431.java b/Week 06/id_431/LeetCode_200_431.java new file mode 100644 index 000000000..8a075592a --- /dev/null +++ b/Week 06/id_431/LeetCode_200_431.java @@ -0,0 +1,109 @@ +package medium; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/1 + */ +public class NumberOfIslands { + /** + * DFS + * @param grid + * @return + */ +// public int numIslands(char[][] grid) { +// if (grid.length <= 0) return 0; +// int num = 0; +//// Set visited = new HashSet<>(); +// int length = grid.length; +// int height = grid[0].length; +// for (int i = 0; i < length; i++) { +// for (int j = 0; j < height; j++) { +// if (grid[i][j] == '1') { +// DFS(grid, i, j, length, height); +// num++; +// } +// } +// } +// return num; +// } +// +// public void DFS(char[][] grid, int i, int j, int length, int height){ +// if (i < 0 || j < 0 || i > length - 1 || j > height - 1 || grid[i][j] == '0') return; +// grid[i][j] = '0'; +// DFS(grid, i - 1, j, length, height); +// DFS(grid, i + 1, j, length, height); +// DFS(grid, i, j - 1, length, height); +// DFS(grid, i, j + 1, length, height); +// } + + int[][] directions = new int[][] { + new int[]{1, 0}, new int[]{-1, 0}, new int[]{0, 1}, new int[]{0, -1} + }; + + /** + * 使用并查集进行解题 + * @param grid + * @return + */ + public int numIslands(char[][] grid) { + int row = grid.length; + if (row == 0) return 0; + int col = grid[0].length; + UnionFind uf = new UnionFind(grid); + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (grid[i][j] == '1') { + int id = i * col + j; + for (int x = 0; x < 4; x++) { + int tmpi = i + directions[x][0]; + int tmpj = j + directions[x][1]; + if (tmpi >= 0 && tmpi < row && tmpj >= 0 && tmpj < col && grid[tmpi][tmpj] == '1') { + uf.unionSet(id, tmpi * col + tmpj); + } + } + } + } + } + return uf.count; + } + + class UnionFind { + int count; + int[] parent; + + UnionFind (char[][] grid) { + int row = grid.length; + int col = grid[0].length; + parent = new int[row * col]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (grid[i][j] == '1') { + count++; + int id = i * col + j; + parent[id] = id; + } + } + } + } + + int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + void unionSet(int p, int q) { + int rootp = find(p); + int rootq = find(q); + if (rootp != rootq) { + parent[rootp] = rootq; + count--; + } + } + } +} diff --git a/Week 06/id_431/LeetCode_208_431.java b/Week 06/id_431/LeetCode_208_431.java new file mode 100644 index 000000000..8a7163d04 --- /dev/null +++ b/Week 06/id_431/LeetCode_208_431.java @@ -0,0 +1,75 @@ +package medium; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author 潘磊明 + * @date 2019/11/21 + */ +public class ImplementTrie { + TrieNode root; + + /** Initialize your data structure here. */ + public ImplementTrie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + char[] chars = word.toCharArray(); + TrieNode node = root; + for (int i = 0; i < chars.length; i++) { + if (!node.children.containsKey(chars[i])){ + node.children.put(chars[i], new TrieNode(chars[i])); + } + node = node.children.get(chars[i]); + // 设置结尾标志 + if (i == chars.length - 1) { + node.isEnd = true; + } + } + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + char[] chars = word.toCharArray(); + TrieNode node = root; + for (int i = 0; i < chars.length; i++) { + if (!node.children.containsKey(chars[i])) return false; + node = node.children.get(chars[i]); + if (i == chars.length - 1) { + return node.isEnd; + } + } + return false; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + char[] chars = prefix.toCharArray(); + TrieNode node = root; + for (int i = 0; i < chars.length; i++) { + if (!node.children.containsKey(chars[i])) return false; + node = node.children.get(chars[i]); + } + return true; + } + + private class TrieNode { + Map children; + Character val; + Boolean isEnd; + + TrieNode() { + isEnd = false; + children = new HashMap<>(); + } + + TrieNode(Character c) { + this.val = c; + isEnd = false; + children = new HashMap<>(); + } + } +} diff --git a/Week 06/id_431/LeetCode_212_431.java b/Week 06/id_431/LeetCode_212_431.java new file mode 100644 index 000000000..a4a2d4028 --- /dev/null +++ b/Week 06/id_431/LeetCode_212_431.java @@ -0,0 +1,81 @@ +package hard; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/22 + */ +public class WordSearchII { + + public List findWords(char[][] board, String[] words) { + List result = new ArrayList<>(); + int length = board.length; + int height = board[0].length; + TrieNode root = buildTrie(words); + for (int i = 0; i < length; i++) { + for (int j = 0; j < height; j++) { + dfs(result, board, root, i, j); + } + } + return result; + } + + /** + * dfs对源数据进行遍历 + * @param result + * @param board + * @param node + * @param i + * @param j + */ + private void dfs(List result, char[][] board, TrieNode node, int i, int j) { + int length = board.length; + int height = board[0].length; + char visited = '#'; + //超出边界或者已经访问过就直接返回 + if (i < 0 || i > length - 1 || j < 0 || j > height - 1 || board[i][j] == visited || node.children[board[i][j] - 'a'] == null) return; + char tmpChar = board[i][j]; + if (node.children[tmpChar - 'a'].word != null) { + result.add(node.children[tmpChar - 'a'].word); + node.children[tmpChar - 'a'].word = null; //去重 + } + board[i][j] = visited; + dfs(result, board, node.children[tmpChar - 'a'], i + 1, j); + dfs(result, board, node.children[tmpChar - 'a'], i - 1, j); + dfs(result, board, node.children[tmpChar - 'a'], i, j + 1); + dfs(result, board, node.children[tmpChar - 'a'], i, j - 1); + board[i][j] = tmpChar; + } + + /** + * 构建字典树 + * @param words + * @return + */ + private TrieNode buildTrie(String[] words) { + TrieNode root = new TrieNode(); + for (String str : words) { + TrieNode tmp = root; + for (char c : str.toCharArray()) { + if (tmp.children[c - 'a'] == null) tmp.children[c -'a'] = new TrieNode(); + tmp = tmp.children[c - 'a']; + } + tmp.word = str; + } + return root; + } + + /** + * 定义字典树 + */ + private class TrieNode { + private TrieNode[] children; + private String word; + + TrieNode() { + children = new TrieNode[26]; + } + } +} diff --git a/Week 06/id_431/LeetCode_36_431.java b/Week 06/id_431/LeetCode_36_431.java new file mode 100644 index 000000000..113cb5541 --- /dev/null +++ b/Week 06/id_431/LeetCode_36_431.java @@ -0,0 +1,29 @@ +package medium; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author 潘磊明 + * @date 2019/11/27 + */ +public class ValidSudoku { + public boolean isValidSudoku(char[][] board) { + Set set = new HashSet<>(); + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if(board[i][j] == '.') continue; + String row = "row_" + i + "_" + board[i][j]; + if (set.contains(row)) return false; + else set.add(row); + String col = "col_" + j + "_" + board[i][j]; + if (set.contains(col)) return false; + else set.add(col); + String cell = "cell_" + (i / 3) + "_" + (j / 3) + "_" + board[i][j]; + if (set.contains(cell)) return false; + else set.add(cell); + } + } + return true; + } +} diff --git a/Week 06/id_431/LeetCode_37_431.java b/Week 06/id_431/LeetCode_37_431.java new file mode 100644 index 000000000..493f82c57 --- /dev/null +++ b/Week 06/id_431/LeetCode_37_431.java @@ -0,0 +1,68 @@ +package hard; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/11/27 + */ +public class SudokuSolver { + public void solveSudoku(char[][] board) { + int[][] row = new int[9][10]; //当前行上已出现的数字 + int[][] col = new int[9][10]; //当前列上已出现的数字 + int[][] cell = new int[9][10]; //当前单元格中出现的数字 + List> empty = new ArrayList<>(); + //init初始化数据 + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] == '.') empty.add(Arrays.asList(i, j)); + else { + int value = board[i][j] - '0'; + row[i][value] = value; + col[j][value] = value; + cell[i / 3 * 3 + j / 3][value] = value; + } + } + } + dfs(board, empty, row, col, cell, 0); + } + + private boolean dfs(char[][] board, List> empty, int[][] row, int[][] col, int[][] cell, int i){ + if (i == empty.size()) return true; + int r = empty.get(i).get(0); + int c = empty.get(i).get(1); + for (char j = '1'; j <= '9'; j++) { + if (isValid(row, col, cell, j - '0', r, c)) { + board[r][c] = j; + int val = j - '0'; + row[r][val] = val; + col[c][val] = val; + cell[r / 3 * 3 + c / 3][val] = val; + boolean flag = dfs(board, empty, row, col, cell, i + 1); + if (flag) return true; + //进行状态恢复 + board[r][c] = '.'; + row[r][val] = 0; + col[c][val] = 0; + cell[r / 3 * 3 + c / 3][val] = 0; + } + } + return false; + } + + /** + * 验证数组是否合法 + * @param row + * @param col + * @param cell + * @param val + * @param i + * @param j + * @return + */ + private boolean isValid(int[][] row, int[][] col, int[][] cell, int val, int i, int j) { + return row[i][val] == 0 && col[j][val] == 0 && cell[i / 3 * 3 + j / 3][val] == 0; + } +} diff --git a/Week 06/id_431/LeetCode_547_431.java b/Week 06/id_431/LeetCode_547_431.java new file mode 100644 index 000000000..bae284254 --- /dev/null +++ b/Week 06/id_431/LeetCode_547_431.java @@ -0,0 +1,59 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/25 + */ +public class FriendCircles { + + /** + * 使用并查集 + * @param M + * @return + */ + public int findCircleNum(int[][] M) { + int len = M.length; + UnionFind uf = new UnionFind(len); + for (int i = 0; i < len; i++) { + for (int j = i + 1; j < len; j++) { + if (M[i][j] == 1) { + uf.union(i, j); + } + } + } + return uf.count; + } + + /** + * 并查集 + */ + private class UnionFind { + private int count; //数量 + private int[] parent; //父类集合 + + UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootQ] = rootP; + count--; + } + } + +} diff --git a/Week 06/id_431/NOTE.md b/Week 06/id_431/NOTE.md index a6321d6e2..ee715e274 100644 --- a/Week 06/id_431/NOTE.md +++ b/Week 06/id_431/NOTE.md @@ -1,4 +1,17 @@ # NOTE - +# 目录 +* 刷题时间表 + + + +# 第六周刷题时间表 + +题目名称|难易度|第一遍时间|第二遍时间|第三遍时间|第四遍时间|第五遍时间|地址 +:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-: +Implement Trie (Prefix Tree)|Medium|2019-11-21|||||https://leetcode.com/problems/implement-trie-prefix-tree/ +Word Search II|Hard|2019-11-25|||||https://leetcode.com/problems/word-search-ii/ +Friend Circles|Medium|2019-11-25|||||https://leetcode.com/problems/friend-circles/ +Surrounded Regions|Medium|2019-11-26|||||https://leetcode.com/problems/surrounded-regions/ +Number of Islands|Medium|2019-11-26|||||https://leetcode.com/problems/number-of-islands/ \ No newline at end of file diff --git a/Week 06/id_436/Leetcode_208_436.java b/Week 06/id_436/Leetcode_208_436.java new file mode 100644 index 000000000..db3f35f1e --- /dev/null +++ b/Week 06/id_436/Leetcode_208_436.java @@ -0,0 +1,58 @@ +class TrieNode { + public TrieNode[] children = new TrieNode[26]; + public boolean hasWord = false; +} +class Trie { + /** Initialize your data structure here. */ + private TrieNode root; + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode cur = root; + for (int i = 0; i < word.length(); ++i) { + int pos = word.charAt(i) - 'a'; + if (cur.children[pos] == null) { + cur.children[pos] = new TrieNode(); + } + cur = cur.children[pos]; + } + cur.hasWord = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode cur = root; + for (int i = 0; i < word.length(); ++i) { + int pos = word.charAt(i) - 'a'; + if (cur.children[pos] == null) { + return false; + } + cur = cur.children[pos]; + } + return cur.hasWord; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode cur = root; + for (int i = 0; i < prefix.length(); ++i) { + int pos = prefix.charAt(i) - 'a'; + if (cur.children[pos] == null) { + return false; + } + cur = cur.children[pos]; + } + return true; + } +} + +/** + * 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); + */ diff --git a/Week 06/id_436/Leetcode_547_436.java b/Week 06/id_436/Leetcode_547_436.java new file mode 100644 index 000000000..86ce36178 --- /dev/null +++ b/Week 06/id_436/Leetcode_547_436.java @@ -0,0 +1,57 @@ +class UnionfindSet { + public int[] parents; + public int[] ranks; + public int count; + + public UnionfindSet(int n){ + parents = new int[n]; + ranks = new int[n]; + count = n; + for (int i = 0; i < parents.length; ++i) { + parents[i] = i; + ranks[i] = 1; + } + } + + public int find(int u) { + if (parents[u] != u) { + parents[u] = find(parents[u]); + } + return parents[u]; + } + + public boolean Union(int u, int v) { + int pu = find(u); + int pv = find(v); + if (pu == pv) { + return false; + } + if (ranks[pu] > ranks[pv]) { + parents[pv] = pu; + } + else if (ranks[pu] < ranks[pv]) { + parents[pu] = pv; + } + else { + parents[pu] = pv; + ranks[pv]++; + } + count--; + return true; + } +} + +class Solution { + public int findCircleNum(int[][] M) { + int n = M.length; + UnionfindSet uf = new UnionfindSet(n); + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (M[i][j] == 1) { + uf.Union(i, j); + } + } + } + return uf.count; + } +} diff --git a/Week 06/id_446/LeetCode_208_446.cpp b/Week 06/id_446/LeetCode_208_446.cpp new file mode 100644 index 000000000..c836a59ca --- /dev/null +++ b/Week 06/id_446/LeetCode_208_446.cpp @@ -0,0 +1,73 @@ +```c++ +class TrieNode { +public: + // Initialize your data structure here. + TrieNode(const char c) : m_char(c),m_is_end(false){} + TrieNode():TrieNode(' '){} + TrieNode* find_child(const char c) const{ + for(TrieNode* child: m_children){ + if(child->m_char == c) return child; + } + return nullptr; + } + ~TrieNode(){ + for(TrieNode* child: m_children) delete child; + } + char m_char; + bool m_is_end; + vector m_children; +}; + +class Trie { +public: + Trie() { + root = new TrieNode(); + } + + // Inserts a word into the trie. + void insert(const string & word) { + TrieNode* curr = root; + for (auto ch : word) { + TrieNode* child = curr->find_child(ch); + if (child != nullptr) { + curr = child; + } else { + TrieNode *newNode = new TrieNode(ch); + curr->m_children.push_back(newNode); + curr = newNode; + } + } + curr->m_is_end = true;//means one word end here + } + + // Returns if the word is in the trie. + bool search(const string & word) const { + TrieNode* curr = find_root_node_with_prefix(word); + if(!curr) return false; + return curr->m_is_end == true;//one word end here or not + } + + // Returns if there is any word in the trie + // that starts with the given prefix. + bool startsWith(const string & prefix) const { + TrieNode* curr = find_root_node_with_prefix(prefix); + return curr == nullptr ? false : true; + } + //destructor + ~Trie() {delete root;} +protected: + // return the root node of a prefix + TrieNode* find_root_node_with_prefix(string prefix) const{ + TrieNode* curr = root; + for (auto ch : prefix) { + curr = curr->find_child(ch); + if (curr == nullptr) + return nullptr; + } + return curr; + } +private: + TrieNode* root; +}; +``` + diff --git a/Week 06/id_446/LeetCode_547_446.cpp b/Week 06/id_446/LeetCode_547_446.cpp new file mode 100644 index 000000000..079af8113 --- /dev/null +++ b/Week 06/id_446/LeetCode_547_446.cpp @@ -0,0 +1,25 @@ +``` +class Solution { +public: + int findCircleNum(vector>& M) { + if (M.empty()) return 0; + int n = M.size(); + vector visited(n, false); + int groups = 0; + for (int i = 0; i < visited.size(); i++) { + groups += !visited[i] ? dfs(i, M, visited), 1 : 0; + } + return groups; + } + +private: + void dfs(int i, vector>& M, vector& visited) { + visited[i] = true; + for (int j = 0; j < visited.size(); j++) { + if (i != j && M[i][j] && !visited[j]) { + dfs(j, M, visited); + } + } + } +}; +``` \ No newline at end of file diff --git a/Week 06/id_446/review.md b/Week 06/id_446/review.md new file mode 100644 index 000000000..7ccea3455 --- /dev/null +++ b/Week 06/id_446/review.md @@ -0,0 +1,71 @@ +# 【446-Week 06】学习总结 字典树 + +> Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起。 + +## Trie树操作 + +* 将字符串集合构造成Trie树--一个将字符串插入到Trie树的过程 + +* 在Trie树中查询一个字符串 + + *** + + +## 存储Trie树 + +* 借助散列表思想存储 + + 假设我们的字符串中只有从 a 到 z 这 26 个小写字母,我们在数组中下标为 0 的位置,存储指向子节点 a 的指针,下标为 1 的位置存储指向子节点 b 的指针,以此类推,下标为 25 的位置,存储的是指向的子节点 z 的指针。如果某个字符的子节点不存在,我们就在对应的下标的位置存储 null。 + + ```java + public 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 + } + + public class TrieNode { + public char data; + public TrieNode[] children = new TrieNode[26]; + public boolean isEndingChar = false; + public TrieNode(char data) { + this.data = data; + } + } + } + ``` + + + +* 耗内存,空间换时间 +* 尽管比较耗费内存,但是对内存不敏感或者内存消耗在接受范围内的情况下,在 Trie 树中做字符串匹配还是非常高效的,时间复杂度是 O(k),k 表示要匹配的字符串的长度。 + +## Trie树适用场景 + +* 散列表或者红黑树适合:动态集合数据的查找。 +* Trie 树适合:查找前缀匹配的字符串 \ No newline at end of file diff --git a/Week 06/id_451/LeetCode_200_451.go b/Week 06/id_451/LeetCode_200_451.go new file mode 100644 index 000000000..2f83f69c7 --- /dev/null +++ b/Week 06/id_451/LeetCode_200_451.go @@ -0,0 +1,78 @@ +package main + +type UnionFind struct { + v interface{} + parent *UnionFind +} + +func NewUnionFind(v interface{}) *UnionFind { + uf := new(UnionFind) + uf.v = v + uf.parent = uf + return uf +} + +func (uf *UnionFind) Find() *UnionFind { + t := uf + for { + if t.parent == t { + return t + } + t = t.parent + } +} +func (a *UnionFind) Union(b *UnionFind) { + pa := a.Find() + pb := b.Find() + pb.parent = pa +} + +func numIslands(grid [][]byte) int { + ruf := make(map[string]*UnionFind) + for i, row := range grid { + for j, v := range row { + if v == 1 || v == '1' { + + kv := fmt.Sprintf(`%v:%v`, i, j) + uf := NewUnionFind(kv) + ruf[kv] = uf + } + } + } + for i, row := range grid { + for j, v := range row { + if v == 1 || v == '1' { + kv := fmt.Sprintf(`%v:%v`, i, j) + uf := ruf[kv] + if i-1 >= 0 && grid[i-1][j] == '1' { + kv := fmt.Sprintf(`%v:%v`, i-1, j) + puf := ruf[kv] + + uf.Union(puf) + } + if j-1 >= 0 && grid[i][j-1] == '1' { + kv := fmt.Sprintf(`%v:%v`, i, j-1) + puf := ruf[kv] + uf.Union(puf) + } + if i+1 < len(grid) && grid[i+1][j] == '1' { + kv := fmt.Sprintf(`%v:%v`, i+1, j) + puf := ruf[kv] + uf.Union(puf) + } + if j+1 < len(row) && grid[i][j+1] == '1' { + kv := fmt.Sprintf(`%v:%v`, i, j+1) + puf := ruf[kv] + uf.Union(puf) + } + } + } + } + count := make(map[string]struct{}) + for _, uf := range ruf { + kv := uf.Find().v.(string) + // fmt.Println(kv) + count[kv] = struct{}{} + } + return len(count) +} diff --git a/Week 06/id_451/LeetCode_547_451.go b/Week 06/id_451/LeetCode_547_451.go new file mode 100644 index 000000000..0b30cff4c --- /dev/null +++ b/Week 06/id_451/LeetCode_547_451.go @@ -0,0 +1,54 @@ +func findCircleNum(grid [][]int) int { + ruf := make(map[string]*UnionFind) + for i, _ := range grid { + kv := fmt.Sprintf(`%v`, i) + uf := NewUnionFind(kv) + ruf[kv] = uf + } + for i, row := range grid { + for j, v := range row { + if v == 1 || v == '1' { + kva := fmt.Sprintf(`%v`, i) + uf := ruf[kva] + kvb := fmt.Sprintf(`%v`, j) + puf := ruf[kvb] + uf.Union(puf) + + } + } + } + count := make(map[string]struct{}) + for _, uf := range ruf { + kv := uf.Find().v.(string) + count[kv] = struct{}{} + } + return len(count) +} + +type UnionFind struct { + v interface{} + parent *UnionFind +} + +func NewUnionFind(v interface{}) *UnionFind { + uf := new(UnionFind) + uf.v = v + uf.parent = uf + return uf +} + +func (uf *UnionFind) Find() *UnionFind { + t := uf + for { + if t.parent == t { + return t + } + t = t.parent + } +} +func (a *UnionFind) Union(b *UnionFind) { + pa := a.Find() + pb := b.Find() + pb.parent = pa +} + diff --git a/Week 06/id_466/LeetCode_127_466.java b/Week 06/id_466/LeetCode_127_466.java new file mode 100644 index 000000000..5828504b0 --- /dev/null +++ b/Week 06/id_466/LeetCode_127_466.java @@ -0,0 +1,785 @@ +//给定两个单词(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 广度优先搜索 +package com.aseara.leetcode.editor.cn.a127; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 127.单词接龙
+ * Date: 2019/10/31
+ * + * @author qiujingde + */ +class WordLadder { + private Solution solution = new Solution(); + + @Test + void test1() { + String begin = "hit"; + String end = "cog"; + List dict = Arrays.asList("hot","dot","dog","lot","log","cog"); + assertEquals(5, solution.ladderLength(begin, end, dict)); + + begin = "hit"; + end = "cog"; + dict = Arrays.asList("hot","dot","dog","lot","log"); + assertEquals(0, solution.ladderLength(begin, end, dict)); + + begin = "hot"; + end = "dot"; + dict = Arrays.asList("hot", "dog", "dot"); + assertEquals(2, solution.ladderLength(begin, end, dict)); + } + +} + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public int ladderLength(String beginWord, String endWord, List wordList) { + return path10(beginWord, endWord, wordList); + } + + private int path1(String beginWord, String endWord, List wordList) { + LinkedList checkList = new LinkedList<>(); + for (String w : wordList) { + if (!w.equals(endWord)) { + checkList.add(w); + } + } + + if (checkList.size() == wordList.size()) { + return 0; + } + + LinkedList queue = new LinkedList<>(); + queue.add(beginWord); + + int step = 1; + while (!queue.isEmpty() && !wordList.isEmpty()) { + step ++; + int batch = queue.size(); + for (int i = 0; i < batch; i++) { + String crt = queue.poll(); + if (canGo(crt, endWord)) { + return step; + } + int checkSize = checkList.size(); + for (int j = 0; j < checkSize; j++) { + String next = checkList.poll(); + if (canGo(crt, next)) { + queue.add(next); + } else { + checkList.add(next); + } + } + } + } + + return 0; + } + + private boolean canGo(String a, String b) { + int diff = 0; + for (int i = 0; i < a.length(); i++) { + diff += a.charAt(i) == b.charAt(i) ? 0 : 1; + if (diff > 1) { + return false; + } + } + return diff == 1; + } + + private int path2(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillMap(map1, map2, word); + } + fillMap(map1, map2, beginWord); + + if (map1.get(endWord) == null) { + return 0; + } + + // endWord -> *bc, a*c, ab* + Set checkSet = new HashSet<>(map1.remove(endWord)); + + LinkedList queue = new LinkedList<>(); + queue.add(beginWord); + + int step = 1; + while (!queue.isEmpty() && !map1.isEmpty()) { + step++; + int batch = queue.size(); + for (int i = 0; i < batch; i++) { + String crt = queue.poll(); + List paths = map1.remove(crt); + if (paths == null) { + continue; + } + for (String path: paths) { + if (checkSet.contains(path)) { + return step; + } + for (String next : map2.get(path)) { + if (map1.containsKey(next)) { + queue.add(next); + } + } + } + } + } + return 0; + } + + private void fillMap(Map> map1, Map> map2, String word) { + for (int i = 0; i < word.length(); i++) { + String pathWord = word.substring(0, i) + '*' + word.substring(i + 1); + map1.computeIfAbsent(word, k -> new LinkedList<>()).add(pathWord); + map2.computeIfAbsent(pathWord, k -> new LinkedList<>()).add(word); + } + } + + // 双向BFS + private int path3(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + for (String path : map1.get(beginWord)) { + if (map2.get(path).size() > 1) { + beginSet.add(path); + } + } + Set endSet = new HashSet<>(map1.get(endWord)); + for (String path : map1.get(endWord)) { + if (map2.get(path).size() > 1) { + endSet.add(path); + } + } + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + for (String path : beginSet) { + if (endSet.contains(path)) { + return step; + } + Set nextWords = map2.get(path); + if (nextWords != null) { + for (String nextWord : nextWords) { + if (!visited.contains(nextWord)) { + visited.add(nextWord); + for (String nextPath : map1.get(nextWord)) { + if (map2.get(nextPath).size() > 1) { + tempSet.add(nextPath); + } + } + } + } + } + } + beginSet = endSet; + endSet = tempSet; + } + + return 0; + } + + // 双向BFS 超出时间限制 + private int path4(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for(String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + fillNextLevelSet(map1, map2, beginSet, beginWord); + Set endSet = new HashSet<>(); + fillNextLevelSet(map1, map2, endSet, endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + System.out.println(beginSet); + System.out.println(endSet); + System.out.println(); + + step ++; + Set tempSet = new HashSet<>(); + + for (String path : beginSet) { + if (endSet.contains(path)) { + return step; + } + + for (String word : map2.get(path)) { + for (String nextPath : map1.get(word)) { + if (!path.equals(nextPath)) { + tempSet.add(nextPath); + } + } + } + } + beginSet = endSet; + endSet = tempSet; + } + + return 0; + } + + private void fillNextLevelSet( + Map> map1, + Map> map2, + Set tempSet, String word) { + for (String nextPath : map1.get(word)) { + Set words = map2.get(nextPath); + tempSet.add(nextPath); + } + } + + // 双向BFS + private int path5(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + for (int i = 0; i < word.length(); i++) { + String path = word.substring(0, i) + '*' + word.substring(i + 1); + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + for (int i = 0; i < beginWord.length(); i++) { + String pathWord = beginWord.substring(0, i) + '*' + beginWord.substring(i + 1); + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp; + if (beginSet.size() < endSet.size()) { + temp = beginSet; + beginSet = endSet; + endSet = temp; + } + temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + endSet = temp; + } + + return 0; + } + + // 双向BFS 当前最优实现 33ms + private int path6(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + if (word.equals(beginWord)) { + continue; + } + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(beginWord); + visited.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp; + if (beginSet.size() < endSet.size()) { + temp = beginSet; + beginSet = endSet; + endSet = temp; + } + temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + endSet = temp; + } + + return 0; + } + + // 双向BFS 递归实现 + private int path7(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set visited = new HashSet<>(); + visited.add(endWord); + + return getStep(wordMap, beginSet, endSet, visited, 1); + } + + private int getStep(Map> wordMap, + Set beginSet, Set endSet, + Set visited, int step) { + + Set temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step + 1; + } + for (String nextWord : wordMap.get(word)) { + if (!visited.contains(nextWord)) { + temp.add(nextWord); + } + } + } + if (temp.isEmpty()) { + return 0; + } + + if (beginSet.size() < temp.size()) { + endSet = beginSet; + beginSet = temp; + } else { + endSet = temp; + } + + return getStep(wordMap, beginSet, endSet, visited, step + 1); + } + + // 双向BFS 使用 meets + private int path8(String beginWord, String endWord, List wordList) { + // abc -> *bc, a*c, ab* + Map> map1 = new HashMap<>(wordList.size()); + // *bc -> abc, bbc, cbc + Map> map2 = new HashMap<>(wordList.size() * 3); + + for (String word : wordList) { + fillSetMap(map1, map2, word); + } + fillSetMap(map1, map2, beginWord); + + if (!map1.containsKey(endWord)) { + return 0; + } + + Set meets = new HashSet<>(wordList); + + Set beginSet = new HashSet<>(); + beginSet.add(beginWord); + Set endSet = new HashSet<>(); + endSet.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + meets.removeAll(beginSet); + for (String word : beginSet) { + for (String path: map1.get(word)) { + for (String nextWord : map2.get(path)) { + if (meets.contains(nextWord)) { + if (endSet.contains(nextWord)) { + return step; + } + tempSet.add(nextWord); + } + } + } + } + if (endSet.size() < tempSet.size()) { + beginSet = tempSet; + } else { + beginSet = endSet; + endSet = tempSet; + } + } + + return 0; + } + + private void fillSetMap(Map> map1, Map> map2, String word) { + Set paths = map1.computeIfAbsent(word, k -> new HashSet<>()); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = String.valueOf(arr); + arr[i] = temp; + paths.add(pathWord); + map2.computeIfAbsent(pathWord, k -> new HashSet<>()).add(word); + } + } + + // 双向BFS 使用 meets 按字符遍历 + private int path9(String beginWord, String endWord, List wordList) { + Set meets = new HashSet<>(wordList); + if (!meets.contains(endWord)) { + return 0; + } + + int length = beginWord.length(); + + Set beginSet = new HashSet<>(); + beginSet.add(beginWord); + Set endSet = new HashSet<>(); + endSet.add(endWord); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set tempSet = new HashSet<>(); + meets.removeAll(beginSet); + for (String word : beginSet) { + char[] arr = word.toCharArray(); + for (int i = 0; i < length; i++) { + char temp = arr[i]; + for (char j = 'a'; j <= 'z'; j++) { + if (temp == j) { + continue; + } + arr[i] = j; + String nextWord = String.valueOf(arr); + if (meets.contains(nextWord)) { + if (endSet.contains(nextWord)) { + return step; + } + tempSet.add(nextWord); + } + } + arr[i] = temp; + } + } + if (endSet.size() < tempSet.size()) { + beginSet = tempSet; + } else { + beginSet = endSet; + endSet = tempSet; + } + } + + return 0; + } + + + + // 双向BFS + private int path10(String beginWord, String endWord, List wordList) { + Map> wordMap = new HashMap<>(); + Map> pathMap = new HashMap<>(); + + for(String word : wordList) { + Set words = new HashSet<>(); + wordMap.put(word, words); + char[] arr = word.toCharArray(); + for (int i = 0; i < word.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String path = new String(arr); + arr[i] = temp; + List pathWords = pathMap.get(path); + if (pathWords == null) { + pathWords = new LinkedList<>(); + pathMap.put(path, pathWords); + } else { + words.addAll(pathWords); + for (String nextWord : pathWords) { + wordMap.get(nextWord).add(word); + } + } + pathWords.add(word); + } + } + + if (!wordMap.containsKey(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + char[] arr = beginWord.toCharArray(); + for (int i = 0; i < beginWord.length(); i++) { + char temp = arr[i]; + arr[i] = '*'; + String pathWord = new String(arr); + arr[i] = temp; + List words; + if ((words = pathMap.get(pathWord)) != null) { + beginSet.addAll(words); + } + } + + Set endSet = new HashSet<>(); + endSet.add(endWord); + + Set meets = new HashSet<>(wordList); + + int step = 1; + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + step ++; + Set temp = new HashSet<>(); + for (String word : endSet) { + if (beginSet.contains(word)) { + return step; + } + meets.remove(word); + for (String nextWord : wordMap.get(word)) { + if (meets.contains(nextWord)) { + temp.add(nextWord); + } + } + } + + if (temp.size() > beginSet.size()) { + endSet = temp; + } else { + endSet = beginSet; + beginSet = temp; + } + } + + return 0; + } + + private int path11(String beginWord, String endWord, List wordList) { + if (wordList == null || wordList.size() == 0) return 0; + HashSet start = new HashSet<>(); + HashSet end = new HashSet<>(); + HashSet dic = new HashSet<>(wordList); + start.add(beginWord); + end.add(endWord); + if (!dic.contains(endWord)) return 0; + return bfs(start, end, dic, 2); + } + + private int bfs(HashSet st, HashSet ed, HashSet dic, int l) { + //双端查找的时候,若是有任意一段出现了“断裂”,也就是说明不存在能够连上的路径,则直接返回0 + if (st.size() == 0) return 0; + if (st.size() > ed.size()) {//双端查找,为了优化时间,永远用少的去找多的,比如开始的时候塞进了1000个,而结尾只有3个,则肯定是从少的那一端开始走比较好 + return bfs(ed, st, dic, l); + } + //BFS的标记行为,即使用过的不重复使用 + dic.removeAll(st); + //收集下一层临近点 + HashSet next = new HashSet<>(); + for (String s : st) { + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char tmp = arr[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (tmp == c) continue; + arr[i] = c ; + String nstr = new String(arr); + if (dic.contains(nstr)) { + if (ed.contains(nstr)) return l; + else next.add(nstr); + } + } + arr[i] = tmp; + } + } + return bfs(next, ed, dic, l + 1); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_130_466.java b/Week 06/id_466/LeetCode_130_466.java new file mode 100644 index 000000000..554e3851b --- /dev/null +++ b/Week 06/id_466/LeetCode_130_466.java @@ -0,0 +1,270 @@ +//给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。 +// +// 找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。 +// +// 示例: +// +// X X X X +//X O O X +//X X O X +//X O X X +// +// +// 运行你的函数后,矩阵变为: +// +// X X X X +//X X X X +//X X X X +//X O X X +// +// +// 解释: +// +// 被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。 +// Related Topics 深度优先搜索 广度优先搜索 并查集 +package com.aseara.leetcode.editor.cn.a130; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * desc: 130.被围绕的区域
+ * Date: 2019/11/20
+ * + * @author qiujingde + */ +class SurroundedRegions { + private Solution solution = new Solution(); + + @Test + void test1() { + char[][] board = { + {'X','X','X','X'}, + {'X','O','O','X'}, + {'X','X','O','X'}, + {'X','O','X','X'}}; + + char[][] expected = { + {'X','X','X','X'}, + {'X','X','X','X'}, + {'X','X','X','X'}, + {'X','O','X','X'}}; + solution.solve(board); + assertArrayEquals(expected, board); + + + char[][] board2 = { + {'O','X','X','O','X'}, + {'X','O','O','X','O'}, + {'X','O','X','O','X'}, + {'O','X','O','O','O'}, + {'X','X','O','X','O'}}; + + char[][] expected2 = { + {'O','X','X','O','X'}, + {'X','X','X','X','O'}, + {'X','X','X','O','X'}, + {'O','X','O','O','O'}, + {'X','X','O','X','O'}}; + + solution.solve(board2); + assertArrayEquals(expected2, board2); + + char[][] board3 = { + {'O','O','O','O','X','X'}, + {'O','O','O','O','O','O'}, + {'O','X','O','X','O','O'}, + {'O','X','O','O','X','O'}, + {'O','X','O','X','O','O'}, + {'O','X','O','O','O','O'}}; + + char[][] expected3 = { + {'O','O','O','O','X','X'}, + {'O','O','O','O','O','O'}, + {'O','X','O','X','O','O'}, + {'O','X','O','O','X','O'}, + {'O','X','O','X','O','O'}, + {'O','X','O','O','O','O'}}; + + solution.solve(board3); + assertArrayEquals(expected3, board3); + + + char[][] board4 = { + {'O','X','O','O','O','X'}, + {'O','O','X','X','X','O'}, + {'X','X','X','X','X','O'}, + {'O','O','O','O','X','X'}, + {'X','X','O','O','X','O'}, + {'O','O','X','X','X','X'}}; + + char[][] expected4 = { + {'O','X','O','O','O','X'}, + {'O','O','X','X','X','O'}, + {'X','X','X','X','X','O'}, + {'O','O','O','O','X','X'}, + {'X','X','O','O','X','O'}, + {'O','O','X','X','X','X'}}; + + solution.solve(board4); + assertArrayEquals(expected4, board4); + + char[][] board5 = { + {'X','O','X','X'}, + {'O','X','O','X'}, + {'X','O','X','O'}, + {'O','X','O','X'}, + {'X','O','X','O'}, + {'O','X','O','X'}}; + solution.solve(board5); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void solve(char[][] board) { + solve2(board); + } + + // 沉岛法 + private void solve1(char[][] board) { + if (board == null || board.length < 3 + || board[0] == null || board[0].length < 3) { + return; + } + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + tag(board, i, 0); + tag(board, i, n - 1); + } + for (int i = 1; i < n - 1; i++) { + tag(board, 0, i); + tag(board, m - 1, i); + } + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == '@') { + board[i][j] = 'O'; + } else if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + } + } + } + + private void tag(char[][] board, int i, int j) { + if (board[i][j] == 'X' || board[i][j] == '@') { + return; + } + board[i][j] = '@'; + int[] di = {-1, 1, 0, 0}; + int[] dj = {0, 0, -1, 1}; + for (int k = 0; k < 4; k++) { + int i2 = i + di[k]; + int j2 = j + dj[k]; + if (i2 >= 0 && i2 < board.length + && j2 >= 0 && j2 < board[0].length) { + tag(board, i2, j2); + } + } + } + + // 并查集 + private void solve2(char[][] board) { + if (board == null || board.length < 3 + || board[0] == null || board[0].length < 3) { + return; + } + + int m = board.length; + int n = board[0].length; + + UnionFind unionFind = new UnionFind(m, n); + + for (int i = 0; i < m - 1; i++) { + for (int j = 0; j < n - 1; j++) { + if (board[i][j] == 'O' && board[i + 1][j] == 'O') { + unionFind.join(i, j, i + 1, j); + } + if (board[i][j] == 'O' && board[i][j + 1] == 'O') { + unionFind.join(i, j, i, j + 1); + } + } + } + + for (int i = 1; i < m - 1; i++) { + for (int j = 1; j < n - 1; j++) { + if (board[i][j] == 'O' && unionFind.island(i, j)) { + board[i][j] = 'X'; + } + } + } + + } + + static class UnionFind { + int m; + int n; + int[] parent; + int[] rank; + boolean[] land; + + UnionFind(int m, int n) { + this.m = m; + this.n = n; + parent = new int[m * n]; + rank = new int[m * n]; + land = new boolean[m * n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + parent[i * n + j] = i * n + j; + if (i == 0 || j == 0 || i == m - 1 || j == n - 1) { + land[i * n + j] = true; + } + } + } + } + + int get(int p) { + if (parent[p] != p) { + parent[p] = get(parent[p]); + } + return parent[p]; + } + + int get(int i, int j) { + return get(i * n + j); + } + + boolean island(int i, int j) { + return !land[get(i, j)]; + } + + void join(int i1, int j1, int i2, int j2) { + int p1 = get(i1, j1); + int p2 = get(i2, j2); + + if (p1 != p2) { + if (rank[p1] < rank[p2]) { + parent[p1] = p2; + land[p2] = land[p1] || land[p2]; + } else { + parent[p2] = p1; + land[p1] = land[p1] || land[p2]; + rank[p1] += rank[p1] == rank[p2] ? 1 : 0; + } + } + } + + } + + + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_200_466.java b/Week 06/id_466/LeetCode_200_466.java new file mode 100644 index 000000000..b4880c60c --- /dev/null +++ b/Week 06/id_466/LeetCode_200_466.java @@ -0,0 +1,184 @@ +//给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 +// +// 示例 1: +// +// 输入: +//11110 +//11010 +//11000 +//00000 +// +//输出: 1 +// +// +// 示例 2: +// +// 输入: +//11000 +//11000 +//00100 +//00011 +// +//输出: 3 +// +// Related Topics 深度优先搜索 广度优先搜索 并查集 +package com.aseara.leetcode.editor.cn.a200; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 200.岛屿数量
+ * Date: 2019/11/3
+ * + * @author qiujingde + */ +class NumberOfIslands { + private Solution solution = new Solution(); + + @Test + void test1() { + char[][] island = new char[][] { + new char[] {'1','1','1','1','0'}, + new char[] {'1','1','0','1','0'}, + new char[] {'1','1','0','0','0'}, + new char[] {'0','0','0','0','0'} + }; + assertEquals(1, solution.numIslands(island)); + + island = new char[][] { + new char[] {'1','1','0','0','0'}, + new char[] {'1','1','0','0','0'}, + new char[] {'0','0','1','0','0'}, + new char[] {'0','0','0','1','1'} + }; + assertEquals(3, solution.numIslands(island)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public int numIslands(char[][] grid) { + return solve2(grid); + } + + private int solve1(char[][] grid) { + int cnt = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + cnt ++; + destroyIsland(grid, i, j); + } + } + } + return cnt; + } + + private void destroyIsland(char[][] grid, int x, int y) { + grid[x][y] = '0'; + + if (x - 1 >= 0 && grid[x - 1][y] == '1') { + destroyIsland(grid, x - 1, y); + } + + if (x + 1 < grid.length && grid[x + 1][y] == '1') { + destroyIsland(grid, x + 1, y); + } + + if (y - 1 >= 0 && grid[x][y - 1] == '1') { + destroyIsland(grid, x, y - 1); + } + + if (y + 1 < grid[x].length && grid[x][y + 1] == '1') { + destroyIsland(grid, x, y + 1); + } + } + + private int solve2(char[][] grid) { + if (grid == null || grid.length == 0 + || grid[0] == null || grid[0].length == 0) { + return 0; + } + + int m = grid.length; + int n = grid[0].length; + + UnionFind unionFind = new UnionFind(m, n); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '0') { + unionFind.count --; + } else { + if (i + 1 < m && grid[i + 1][j] == '1') { + unionFind.union(i, j, i + 1, j); + } + if (j + 1 < n && grid[i][j + 1] == '1') { + unionFind.union(i, j, i, j + 1); + } + } + } + } + + return unionFind.count; + } + + static class UnionFind { + int count; + int[] parent; + int[] rank; + + int m; + int n; + + UnionFind(int m, int n) { + this.m = m; + this.n = n; + count = m * n; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + parent[i * n + j] = i * n + j; + } + } + } + + int get(int p) { + while (parent[p] != p) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + int get(int i, int j) { + return get(i * n + j); + } + + void union(int p1, int p2) { + p1 = get(p1); + p2 = get(p2); + if (p1 != p2) { + if (rank[p2] > rank[p1]) { + parent[p1] = p2; + } else { + parent[p2] = p1; + rank[p1] += rank[p1] == rank[p2] ? 1 : 0; + } + count --; + } + } + + void union(int i1, int j1, int i2, int j2) { + union(i1 * n + j1, i2 * n + j2); + } + + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_208_466.java b/Week 06/id_466/LeetCode_208_466.java new file mode 100644 index 000000000..4111fcab4 --- /dev/null +++ b/Week 06/id_466/LeetCode_208_466.java @@ -0,0 +1,132 @@ +//实现一个 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 设计 字典树 +package com.aseara.leetcode.editor.cn.a208; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * desc: 208.实现 Trie (前缀树)
+ * Date: 2019/11/19
+ * + * @author qiujingde + */ +class ImplementTriePrefixTree { + + @Test + void test1() { + 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 + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + char[] chars = word.toCharArray(); + TrieNode node = root; + for (char c : chars) { + node = node.computeIfAbsent(c); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = getEndNode(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = getEndNode(prefix); + return node != null; + } + + public TrieNode getRoot() { + return root; + } + + private TrieNode getEndNode(String word) { + char[] chars = word.toCharArray(); + TrieNode node = root; + for (int i = 0; i < chars.length && node != null; i++) { + node = node.getNode(chars[i]); + } + return node; + } + + static class TrieNode { + private Map links = new HashMap<>(); + + private boolean isEnd; + + public TrieNode computeIfAbsent(char c) { + return links.computeIfAbsent(c, k -> new TrieNode()); + } + + public TrieNode getNode(char c) { + return links.get(c); + } + + public void setNode(char c, TrieNode node) { + links.put(c, node); + } + + public boolean isEnd() { + return isEnd; + } + + public void setEnd() { + isEnd = true; + } + } +} + + + +/** + * 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); + */ +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_212_466.java b/Week 06/id_466/LeetCode_212_466.java new file mode 100644 index 000000000..08165adc4 --- /dev/null +++ b/Week 06/id_466/LeetCode_212_466.java @@ -0,0 +1,207 @@ +//给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +// +// 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 +// +// 示例: +// +// 输入: +//words = ["oath","pea","eat","rain"] and board = +//[ +// ['o','a','a','n'], +// ['e','t','a','e'], +// ['i','h','k','r'], +// ['i','f','l','v'] +//] +// +//输出: ["eat","oath"] +// +// 说明: +//你可以假设所有输入都由小写字母 a-z 组成。 +// +// 提示: +// +// +// 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +// 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 +// +// Related Topics 字典树 回溯算法 +package com.aseara.leetcode.editor.cn.a212; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +/** + * desc: 212.单词搜索 II
+ * Date: 2019/11/19
+ * + * @author qiujingde + */ +class WordSearchIi { + private Solution solution = new Solution(); + + @Test + void test1() { + String[] words = {"oath","pea","eat","rain"}; + char[][] board = { + {'o','a','a','n'}, + {'e','t','a','e'}, + {'i','h','k','r'}, + {'i','f','l','v'} + }; + + Set result = new HashSet<>(solution.findWords(board, words)); + Set expected = new HashSet<>(Arrays.asList("eat","oath")); + + assertIterableEquals(expected, result); + } +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List findWords(char[][] board, String[] words) { + if (board == null || words == null) { + return Collections.emptyList(); + } + + Trie trie = new Trie(); + // 所有单词存入字典树 + for (String word : words) { + trie.insert(word); + } + + Trie.TrieNode root = trie.getRoot(); + + List result = new LinkedList<>(); + + // 遍历二维矩阵 + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + backtrace(board, root.getNode(board[i][j]), new Cor(i, j), "", result); + } + } + + return result; + } + + private void backtrace(char[][] board, Trie.TrieNode node, Cor cor, + String curWord, List result) { + if (node == null) { + return; + } + + char c = board[cor.x][cor.y]; + board[cor.x][cor.y] = 0; + curWord = curWord + c; + + if (node.isEnd()) { + result.add(curWord); + node.setEnd(false); + } + + List nextCors = cor.getNeighbors(board.length, board[0].length); + for (Cor nextCor: nextCors) { + char nextC = board[nextCor.x][nextCor.y]; + if (nextC != 0) { + backtrace(board, node.getNode(nextC), nextCor, curWord, result); + } + } + + board[cor.x][cor.y] = c; + } +} + +class Cor { + final int x; + final int y; + + Cor(int x, int y) { + this.x = x; + this.y = y; + } + + List getNeighbors(int maxX, int maxY) { + List nextCors = new LinkedList<>(); + // 上 + if (x - 1 >= 0) { + nextCors.add(new Cor(x - 1, y)); + } + // 下 + if (x + 1 < maxX) { + nextCors.add(new Cor(x + 1, y)); + } + // 左 + if (y - 1 >= 0) { + nextCors.add(new Cor(x, y - 1)); + } + // 右 + if (y + 1 < maxY) { + nextCors.add(new Cor(x, y + 1)); + } + return nextCors; + } +} + +class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + void insert(String word) { + char[] chars = word.toCharArray(); + TrieNode node = root; + for (char c : chars) { + node = node.computeIfAbsent(c); + } + node.setEnd(true); + } + + public TrieNode getRoot() { + return root; + } + + static class TrieNode { + private TrieNode[] links = new TrieNode[26]; + + private boolean isEnd; + + TrieNode computeIfAbsent(char c) { + TrieNode node = getNode(c); + if (node == null) { + setNode(c, new TrieNode()); + } + return getNode(c); + } + + TrieNode getNode(char c) { + return links[c - 'a']; + } + + private void setNode(char c, TrieNode node) { + links[c - 'a'] = node; + } + + public boolean isEnd() { + return isEnd; + } + + public void setEnd(boolean end) { + isEnd = end; + } + } +} + +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_36_466.java b/Week 06/id_466/LeetCode_36_466.java new file mode 100644 index 000000000..8993e825c --- /dev/null +++ b/Week 06/id_466/LeetCode_36_466.java @@ -0,0 +1,132 @@ +//判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 +// +// +// 数字 1-9 在每一行只能出现一次。 +// 数字 1-9 在每一列只能出现一次。 +// 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 +// +// +// +// +// 上图是一个部分填充的有效的数独。 +// +// 数独部分空格内已填入了数字,空白格用 '.' 表示。 +// +// 示例 1: +// +// 输入: +//[ +// ["5","3",".",".","7",".",".",".","."], +// ["6",".",".","1","9","5",".",".","."], +// [".","9","8",".",".",".",".","6","."], +// ["8",".",".",".","6",".",".",".","3"], +// ["4",".",".","8",".","3",".",".","1"], +// ["7",".",".",".","2",".",".",".","6"], +// [".","6",".",".",".",".","2","8","."], +// [".",".",".","4","1","9",".",".","5"], +// [".",".",".",".","8",".",".","7","9"] +//] +//输出: true +// +// +// 示例 2: +// +// 输入: +//[ +//  ["8","3",".",".","7",".",".",".","."], +//  ["6",".",".","1","9","5",".",".","."], +//  [".","9","8",".",".",".",".","6","."], +//  ["8",".",".",".","6",".",".",".","3"], +//  ["4",".",".","8",".","3",".",".","1"], +//  ["7",".",".",".","2",".",".",".","6"], +//  [".","6",".",".",".",".","2","8","."], +//  [".",".",".","4","1","9",".",".","5"], +//  [".",".",".",".","8",".",".","7","9"] +//] +//输出: false +//解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 +// 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 +// +// 说明: +// +// +// 一个有效的数独(部分已被填充)不一定是可解的。 +// 只需要根据以上规则,验证已经填入的数字是否有效即可。 +// 给定数独序列只包含数字 1-9 和字符 '.' 。 +// 给定数独永远是 9x9 形式的。 +// +// Related Topics 哈希表 +package com.aseara.leetcode.editor.cn.a36; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * desc: 36.有效的数独
+ * Date: 2019/11/21
+ * + * @author qiujingde + */ +class ValidSudoku { + private Solution solution = new Solution(); + + @Test + void test1() { + char[][] board1 = { + {'5','3','.','.','7','.','.','.','.'}, + {'6','.','.','1','9','5','.','.','.'}, + {'.','9','8','.','.','.','.','6','.'}, + {'8','.','.','.','6','.','.','.','3'}, + {'4','.','.','8','.','3','.','.','1'}, + {'7','.','.','.','2','.','.','.','6'}, + {'.','6','.','.','.','.','2','8','.'}, + {'.','.','.','4','1','9','.','.','5'}, + {'.','.','.','.','8','.','.','7','9'} + }; + assertTrue(solution.isValidSudoku(board1)); + + char[][] board2 = { + {'8','3','.','.','7','.','.','.','.'}, + {'6','.','.','1','9','5','.','.','.'}, + {'.','9','8','.','.','.','.','6','.'}, + {'8','.','.','.','6','.','.','.','3'}, + {'4','.','.','8','.','3','.','.','1'}, + {'7','.','.','.','2','.','.','.','6'}, + {'.','6','.','.','.','.','2','8','.'}, + {'.','.','.','4','1','9','.','.','5'}, + {'.','.','.','.','8','.','.','7','9'} + }; + assertFalse(solution.isValidSudoku(board2)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean isValidSudoku(char[][] board) { + int[] check = new int[27]; + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + int num = 1 << (board[i][j] - '1'); + + int col = 9 + j; + int box = 18 + (i / 3) * 3 + j / 3; + + if (((check[i] | check[col] | check[box]) & num) > 0) { + return false; + } + + check[i] |= num; + check[col] |= num; + check[box] |= num; + } + } + } + return true; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_37_466.java b/Week 06/id_466/LeetCode_37_466.java new file mode 100644 index 000000000..683809273 --- /dev/null +++ b/Week 06/id_466/LeetCode_37_466.java @@ -0,0 +1,135 @@ +//编写一个程序,通过已填充的空格来解决数独问题。 +// +// 一个数独的解法需遵循如下规则: +// +// +// 数字 1-9 在每一行只能出现一次。 +// 数字 1-9 在每一列只能出现一次。 +// 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 +// +// +// 空白格用 '.' 表示。 +// +// +// +// 一个数独。 +// +// +// +// 答案被标成红色。 +// +// Note: +// +// +// 给定的数独序列只包含数字 1-9 和字符 '.' 。 +// 你可以假设给定的数独只有唯一解。 +// 给定数独永远是 9x9 形式的。 +// +// Related Topics 哈希表 回溯算法 +package com.aseara.leetcode.editor.cn.a37; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * desc: 37.解数独
+ * Date: 2019/11/21
+ * + * @author qiujingde + */ +class SudokuSolver { + private Solution solution = new Solution(); + + @Test + void test1() { + char[][] board = { + {'5','3','.','.','7','.','.','.','.'}, + {'6','.','.','1','9','5','.','.','.'}, + {'.','9','8','.','.','.','.','6','.'}, + {'8','.','.','.','6','.','.','.','3'}, + {'4','.','.','8','.','3','.','.','1'}, + {'7','.','.','.','2','.','.','.','6'}, + {'.','6','.','.','.','.','2','8','.'}, + {'.','.','.','4','1','9','.','.','5'}, + {'.','.','.','.','8','.','.','7','9'} + }; + solution.solveSudoku(board); + char[][] expected = { + {'5','3','4','6','7','8','9','1','2'}, + {'6','7','2','1','9','5','3','4','8'}, + {'1','9','8','3','4','2','5','6','7'}, + {'8','5','9','7','6','1','4','2','3'}, + {'4','2','6','8','5','3','7','9','1'}, + {'7','1','3','9','2','4','8','5','6'}, + {'9','6','1','5','3','7','2','8','4'}, + {'2','8','7','4','1','9','6','3','5'}, + {'3','4','5','2','8','6','1','7','9'} + }; + assertArrayEquals(expected, board); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void solveSudoku(char[][] board) { + int[] check = new int[27]; + initCheck(board, check); + dfs(board, 0, 0, check); + } + + private void initCheck(char[][] board, int[] check) { + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + int num = 1 << (board[i][j] - '1'); + + int col = 9 + j; + int box = 18 + (i / 3) * 3 + j / 3; + + check[i] |= num; + check[col] |= num; + check[box] |= num; + } + } + } + } + + private boolean dfs(char[][] board, int i, int j, int[] check) { + if (i == 9) { + return true; + } + + int col = 9 + j; + int box = 18 + (i / 3) * 3 + j / 3; + int curCheck = check[i] | check[col] | check[box]; + + int nextI = j == 8 ? i + 1 : i; + int nextJ = j == 8 ? 0 : j + 1; + + if (board[i][j] != '.') { + return dfs(board, nextI, nextJ, check); + } + for (int k = 0; k < 9; k++) { + int num = 1 << k; + if ((curCheck & num) == 0) { + check[i] |= num; + check[col] |= num; + check[box] |= num; + + if (dfs(board, nextI, nextJ, check)) { + board[i][j] = (char) (k + '1'); + return true; + } + + check[i] ^= num; + check[col] ^= num; + check[box] ^= num; + } + } + return false; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_437_466.java b/Week 06/id_466/LeetCode_437_466.java new file mode 100644 index 000000000..d671a15f6 --- /dev/null +++ b/Week 06/id_466/LeetCode_437_466.java @@ -0,0 +1,139 @@ +//一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一个。 +// +// 假设我们要调查一个基因序列的变化。一次基因变化意味着这个基因序列中的一个字符发生了变化。 +// +// 例如,基因序列由"AACCGGTT" 变化至 "AACCGGTA" 即发生了一次基因变化。 +// +// 与此同时,每一次基因变化的结果,都需要是一个合法的基因串,即该结果属于一个基因库。 +// +// 现在给定3个参数 — start, end, bank,分别代表起始基因序列,目标基因序列及基因库,请找出能够使起始基因序列变化为目标基因序列所需的最少变化次数。如果无法实现目标变化,请返回 -1。 +// +// 注意: +// +// +// 起始基因序列默认是合法的,但是它并不一定会出现在基因库中。 +// 所有的目标基因序列必须是合法的。 +// 假定起始基因序列与目标基因序列是不一样的。 +// +// +// 示例 1: +// +// +//start: "AACCGGTT" +//end: "AACCGGTA" +//bank: ["AACCGGTA"] +// +//返回值: 1 +// +// +// 示例 2: +// +// +//start: "AACCGGTT" +//end: "AAACGGTA" +//bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] +// +//返回值: 2 +// +// +// 示例 3: +// +// +//start: "AAAAACCC" +//end: "AACCCCCC" +//bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] +// +//返回值: 3 +// +// +package com.aseara.leetcode.editor.cn.a433; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 433.最小基因变化
+ * Date: 2019/11/24
+ * + * @author qiujingde + */ +class MinimumGeneticMutation { + private Solution solution = new Solution(); + + @Test + void test1() { + String start = "AAAAAAAA"; + String end = "CCCCCCCC"; + + String[] bank = {"AAAAAAAA","AAAAAAAC","AAAAAACC","AAAAACCC","AAAACCCC","AACACCCC","ACCACCCC","ACCCCCCC","CCCCCCCA","CCCCCCCC"}; + + assertEquals(8, solution.minMutation(start, end, bank)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int minMutation(String start, String end, String[] bank) { + if (bank == null || bank.length == 0) { + return -1; + } + Set dict = new HashSet<>(Arrays.asList(bank)); + + Set startSet = new HashSet<>(); + startSet.add(start); + + if (!dict.contains(end)) { + return -1; + } + dict.remove(end); + Set endSet = new HashSet<>(); + endSet.add(end); + + char[] codes = {'A', 'C', 'G', 'T'}; + + int step = 0; + while (!startSet.isEmpty()) { + step ++; + Set next = new HashSet<>(); + + for (String gen : startSet) { + char[] genCodes = gen.toCharArray(); + for (int i = 0; i < genCodes.length; i++) { + char curCode = genCodes[i]; + for (char code : codes) { + if (code != curCode) { + genCodes[i] = code; + String newGen = new String(genCodes); + if (endSet.contains(newGen)) { + return step; + } else if (dict.contains(newGen)){ + next.add(newGen); + dict.remove(newGen); + } + } + } + genCodes[i] = curCode; + } + } + + if (next.size() > endSet.size()) { + startSet = endSet; + endSet = next; + } else { + startSet = next; + } + } + + return -1; + } + + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_51_466.java b/Week 06/id_466/LeetCode_51_466.java new file mode 100644 index 000000000..5935261ee --- /dev/null +++ b/Week 06/id_466/LeetCode_51_466.java @@ -0,0 +1,118 @@ +//n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +// +// +// +// 上图为 8 皇后问题的一种解法。 +// +// 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 +// +// 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 +// +// 示例: +// +// 输入: 4 +//输出: [ +// [".Q..", // 解法 1 +// "...Q", +// "Q...", +// "..Q."], +// +// ["..Q.", // 解法 2 +// "Q...", +// "...Q", +// ".Q.."] +//] +//解释: 4 皇后问题存在两个不同的解法。 +// +// Related Topics 回溯算法 +package com.aseara.leetcode.editor.cn.a51; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * desc: 51.N皇后
+ * Date: 2019/11/22
+ * + * @author qiujingde + */ +class NQueens { + private Solution solution = new Solution(); + + @Test + void test1() { + System.out.println(solution.solveNQueens(1)); + System.out.println(solution.solveNQueens(4)); + System.out.println(solution.solveNQueens(8)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> solveNQueens(int n) { + if (n < 1) { + return null; + } + List> resultStore = new LinkedList<>(); + + // init chars + char[] chars = new char[n]; + Arrays.fill(chars, '.'); + + boolean[] col = new boolean[n]; + // 撇 + boolean[] left = new boolean[2 * n]; + // 捺 + boolean[] right = new boolean[2 * n]; + + // 位置记录 + LinkedList stack = new LinkedList<>(); + + dfs(0, stack, n, col, left, right, resultStore, chars); + + return resultStore; + } + + private void dfs(int row, LinkedList stack, int n, + boolean[] col, boolean[] left, boolean[] right, + List> resultStore, char[] chars) { + if (row == n) { + // 遍历完成,合法数据 + resultStore.add(to2D(chars, stack)); + return; + } + + for (int i = 0; i < n; i++) { + if (!col[i] && !left[i - row + n] && !right[i + row]) { + stack.add(i); + col[i] = true; + left[i - row + n] = true; + right[i + row] = true; + + dfs(row + 1, stack, n, col, left, right, resultStore, chars); + + right[i + row] = false; + left[i - row + n] = false; + col[i] = false; + stack.removeLast(); + } + } + } + + private List to2D(char[] chars, List result) { + List results = new LinkedList<>(); + for (int index : result) { + chars[index] = 'Q'; + results.add(new String(chars)); + chars[index] = '.'; + } + return results; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_466/LeetCode_547_466.java b/Week 06/id_466/LeetCode_547_466.java new file mode 100644 index 000000000..6c57d0446 --- /dev/null +++ b/Week 06/id_466/LeetCode_547_466.java @@ -0,0 +1,128 @@ +//班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 +// +// 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 +// +// 示例 1: +// +// +//输入: +//[[1,1,0], +// [1,1,0], +// [0,0,1]] +//输出: 2 +//说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 +//第2个学生自己在一个朋友圈。所以返回2。 +// +// +// 示例 2: +// +// +//输入: +//[[1,1,0], +// [1,1,1], +// [0,1,1]] +//输出: 1 +//说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 +// +// +// 注意: +// +// +// N 在[1,200]的范围内。 +// 对于所有学生,有M[i][i] = 1。 +// 如果有M[i][j] = 1,则有M[j][i] = 1。 +// +// Related Topics 深度优先搜索 并查集 +package com.aseara.leetcode.editor.cn.a547; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 547.朋友圈
+ * Date: 2019/11/20
+ * + * @author qiujingde + */ +class FriendCircles { + private Solution solution = new Solution(); + + @Test + void test1() { + int[][] M1 = { + {1,1,0}, + {1,1,0}, + {0,0,1} + }; + + assertEquals(2, solution.findCircleNum(M1)); + + int[][] M2 = { + {1,1,0}, + {1,1,1}, + {0,1,1} + }; + + assertEquals(1, solution.findCircleNum(M2)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int findCircleNum(int[][] M) { + if (M == null) { + return 0; + } + + if (M.length < 2) { + return M.length; + } + + int m = M.length; + + DisjointSet disjointSet = new DisjointSet(m); + for (int i = 0; i < m - 1; i++) { + for (int j = i + 1; j < m; j++) { + if (M[i][j] == 1) { + disjointSet.join(i, j); + } + } + } + return disjointSet.count; + } +} + +class DisjointSet { + int count; + private int[] parent; + + DisjointSet(int size) { + count = size; + parent = new int[size]; + for (int i = 1; i < size; i++) { + parent[i] = i; + } + } + + private int find(int i) { + while (i != parent[i]) { + parent[i] = parent[parent[i]]; + i = parent[i]; + } + return i; + } + + void join(int i, int j) { + int pi = find(i); + int pj = find(j); + if (pi != pj) { + parent[pj] = pi; + count--; + } + } +} + +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_471/LeetCode_130_471.java b/Week 06/id_471/LeetCode_130_471.java new file mode 100644 index 000000000..da65ad5af --- /dev/null +++ b/Week 06/id_471/LeetCode_130_471.java @@ -0,0 +1,31 @@ +class Solution { + public void solve(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[i].length; j++) { + boolean isEdge = i == 0 || j == 0 || i == board.length - 1 || j == board[i].length - 1; + if (isEdge && board[i][j] == 'O') { + dfs(board, i, j); + } + } + } + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[i].length; j++) { + board[i][j] = board[i][j] == 'O' ? 'X' : board[i][j] == 'X' ? 'X' : 'O'; + } + } + } + + public void dfs(char[][] board, int x, int y) { + board[x][y] = '@'; + int[][] step = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + for (int i = 0; i < step.length; i++) { + int tempX = x + step[i][0]; + int tempY = y + step[i][1]; + + if (tempX >= 0 && tempX < board.length && tempY >= 0 && tempY < board[tempX].length && board[tempX][tempY] == 'O') { + dfs(board, tempX, tempY); + } + } + } +} \ No newline at end of file diff --git a/Week 06/id_471/LeetCode_208_471.java b/Week 06/id_471/LeetCode_208_471.java new file mode 100644 index 000000000..6bbbb5b60 --- /dev/null +++ b/Week 06/id_471/LeetCode_208_471.java @@ -0,0 +1,91 @@ +class Trie { + + Initialize your data structure here. + private TrieNode trie; + public Trie() { + trie = new TrieNode(); + } + + Inserts a word into the trie. + public void insert(String word) { + TrieNode temp = trie; + for (int i = 0; i word.length(); i++) { + if(!temp.containsKey(word.charAt(i))) { + TrieNode node = new TrieNode(); + temp.put(word.charAt(i), node); + } + temp = temp.links[word.charAt(i) - 'a']; + } + + temp.setEnd(); + } + + Returns if the word is in the trie. + public boolean search(String word) { + TrieNode temp = trie; + + for (int i = 0; i word.length(); i++) { + char ch = word.charAt(i); + if (!temp.containsKey(ch)) { + return false; + } + + temp = temp.get(ch); + } + return temp.isEnd(); + } + + Returns if there is any word in the trie that starts with the given prefix. + public boolean startsWith(String prefix) { + TrieNode temp = trie; + + for (int i = 0; i prefix.length(); i++) { + char ch = prefix.charAt(i); + if (!temp.containsKey(ch)) { + return false; + } + + temp = temp.get(ch); + } + + return true; + } + + private class TrieNode{ + private TrieNode links[]; + private final int R = 26; + boolean isEnd; + + public TrieNode() { + links = new TrieNode[26]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + } +} + + + 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/Week 06/id_471/LeetCode_212_471.java b/Week 06/id_471/LeetCode_212_471.java new file mode 100644 index 000000000..dc9158061 --- /dev/null +++ b/Week 06/id_471/LeetCode_212_471.java @@ -0,0 +1,125 @@ +class Solution { + Set set = new HashSet<>(); + public List findWords(char[][] board, String[] words) { + + Trie tree = new Trie(); + Set set = new HashSet<>(); + boolean visited[][] = new boolean[board.length][board[0].length]; + List results = new ArrayList<>(); + for (int i = 0; i < words.length; i++) { + tree.insert(words[i]); + } + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[i].length; j++) { + visited[i][j] = true; + dfs(i, j, board[i][j] + "", visited, tree, results, board); + visited[i][j] = false; + } + } + + return results; + } + + public void dfs(int i, int j, String result, boolean[][] visited, Trie tree, List results,char[][] board) { + //System.out.println(result); + if (!tree.isPrefix(result)) { + return; + } + + if (tree.search(result) && !set.contains(result)) { + results.add(result); + set.add(result); + //return; + } + + int step[][] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + for (int k = 0; k < step.length; k++) { + int x = i + step[k][0]; + int y = j + step[k][1]; + if (x >= 0 && x < board.length && y >= 0 && y < board[x].length && !visited[x][y]) { + visited[x][y] = true; + dfs(x, y, result + board[x][y], visited, tree, results, board); + visited[x][y] = false; + } + + } + } + + public class Trie{ + private TrieNode trie; + + public Trie() { + trie = new TrieNode(); + } + public void insert(String word) { + TrieNode node = trie; + + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containsKey(ch)) { + node.put(ch, new TrieNode()); + } + node = node.getNode(ch); + } + node.setEnd(); + } + + public boolean search(String word) { + TrieNode node = trie; + + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containsKey(ch)) { + return false; + } + node = node.getNode(ch); + } + return node.isEnd(); + } + + public boolean isPrefix(String word) { + TrieNode node = trie; + + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containsKey(ch)) { + return false; + } + node = node.getNode(ch); + } + return true; + } + + private class TrieNode{ + private TrieNode links[]; + boolean isEnd; + private final int R = 26; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public TrieNode getNode(char ch) { + return links[ch - 'a']; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + } + } +} \ No newline at end of file diff --git a/Week 06/id_471/LeetCode_547_471.java b/Week 06/id_471/LeetCode_547_471.java new file mode 100644 index 000000000..ce46fc156 --- /dev/null +++ b/Week 06/id_471/LeetCode_547_471.java @@ -0,0 +1,39 @@ +class Solution { + + public int findParent(int[] parent, int i) { + if (parent[i] == -1) { + return i; + } + return findParent(parent, parent[i]); + } + + public void union(int[] parent, int i, int j) { + int x = findParent(parent, i); + int y = findParent(parent, j); + + if (x != y) { + parent[x] = y; + } + } + + public int findCircleNum(int[][] M) { + int n = M.length; + int parent[] = new int[n]; + Arrays.fill(parent, -1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (M[i][j] == 1) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) { + count++; + } + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_476/LeetCode_1091_476.java b/Week 06/id_476/LeetCode_1091_476.java new file mode 100644 index 000000000..fc241446c --- /dev/null +++ b/Week 06/id_476/LeetCode_1091_476.java @@ -0,0 +1,127 @@ +//在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。 +// +// 一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k 组成: +// +// +// 相邻单元格 C_i 和 C_{i+1} 在八个方向之一上连通(此时,C_i 和 C_{i+1} 不同且共享边或角) +// C_1 位于 (0, 0)(即,值为 grid[0][0]) +// C_k 位于 (N-1, N-1)(即,值为 grid[N-1][N-1]) +// 如果 C_i 位于 (r, c),则 grid[r][c] 为空(即,grid[r][c] == 0) +// +// +// 返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。 +// +// +// +// 示例 1: +// +// 输入:[[0,1],[1,0]] +// +//输出:2 +// +// +// +// 示例 2: +// +// 输入:[[0,0,0],[1,1,0],[1,1,0]] +// +//输出:4 +// +// +// +// +// +// 提示: +// +// +// 1 <= grid.length == grid[0].length <= 100 +// grid[i][j] 为 0 或 1 +// +// Related Topics 广度优先搜索 + +package com.markdown.leetcode.editor.cn; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +public class LeetCode_1091_ShortestPathInBinaryMatrix { + public static void main(String[] args) { + Solution solution = new LeetCode_1091_ShortestPathInBinaryMatrix().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + + if (grid == null || grid.length == 0) { + return 0; + } + int N = grid.length; + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) { + return -1; + } + return BFS(grid); + } + + private int BFS(int[][] grid) { + + int N = grid.length; + int end = N * N - 1; + int distance = 0; + int[][] direction = new int[][] {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; + Queue queue = new LinkedList<>(); + queue.offer(0); + Set visited = new HashSet<>(); + while (!queue.isEmpty()) { + distance++; + int size = queue.size(); + for (int i = 0; i < size; i++) { + Integer index = queue.poll(); + if (index == end) return distance; + visited.add(index); + int x = index / N; + int y = index % N; + for (int[] dir : direction) { + int n_x = x + dir[0]; + int n_y = y + dir[1]; + int n_index = n_x * N + n_y; + if (n_x >= 0 && n_x <= N - 1 && n_y >= 0 && n_y <= N - 1 && !visited.contains(n_index) && grid[n_x][n_y] == 0) { + queue.offer(n_index); + } + } + /*if (x > 0 && y > 0 && !visited.contains((x - 1) * N + y - 1) && grid[x - 1][y - 1] == 0) { + queue.offer((x - 1) * N + y - 1); + } + if (x > 0 && y >= 0 && !visited.contains((x - 1) * N + y) && grid[x - 1][y] == 0) { + queue.offer((x - 1) * N + y); + } + if (x > 0 && y < N - 1 && !visited.contains((x - 1) * N + y + 1) && grid[x - 1][y + 1] == 0) { + queue.offer((x - 1) * N + y + 1); + } + if (x >= 0 && y > 0 && !visited.contains((x) * N + y - 1) && grid[x][y - 1] == 0) { + queue.offer((x) * N + y - 1); + } + if (x >= 0 && y < N - 1 && !visited.contains((x) * N + y + 1) && grid[x][y + 1] == 0) { + queue.offer((x) * N + y + 1); + } + if (x < N - 1 && y > 0 && !visited.contains((x + 1) * N + y - 1) && grid[x + 1][y - 1] == 0) { + queue.offer((x + 1) * N + y - 1); + } + if (x < N - 1 && y >= 0 && !visited.contains((x + 1) * N + y) && grid[x + 1][y] == 0) { + queue.offer((x + 1) * N + y); + } + if (x < N - 1 && y < N - 1 && !visited.contains((x + 1) * N + y + 1) && grid[x + 1][y + 1] == 0) { + queue.offer((x + 1) * N + y + 1); + }*/ + } + + } + return -1; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 06/id_476/LeetCode_36_476.java b/Week 06/id_476/LeetCode_36_476.java new file mode 100644 index 000000000..5e0cd5253 --- /dev/null +++ b/Week 06/id_476/LeetCode_36_476.java @@ -0,0 +1,124 @@ +//判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 +// +// +// 数字 1-9 在每一行只能出现一次。 +// 数字 1-9 在每一列只能出现一次。 +// 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 +// +// +// +// +// 上图是一个部分填充的有效的数独。 +// +// 数独部分空格内已填入了数字,空白格用 '.' 表示。 +// +// 示例 1: +// +// 输入: +//[ +// ["5","3",".",".","7",".",".",".","."], +// ["6",".",".","1","9","5",".",".","."], +// [".","9","8",".",".",".",".","6","."], +// ["8",".",".",".","6",".",".",".","3"], +// ["4",".",".","8",".","3",".",".","1"], +// ["7",".",".",".","2",".",".",".","6"], +// [".","6",".",".",".",".","2","8","."], +// [".",".",".","4","1","9",".",".","5"], +// [".",".",".",".","8",".",".","7","9"] +//] +//输出: true +// +// +// 示例 2: +// +// 输入: +//[ +//  ["8","3",".",".","7",".",".",".","."], +//  ["6",".",".","1","9","5",".",".","."], +//  [".","9","8",".",".",".",".","6","."], +//  ["8",".",".",".","6",".",".",".","3"], +//  ["4",".",".","8",".","3",".",".","1"], +//  ["7",".",".",".","2",".",".",".","6"], +//  [".","6",".",".",".",".","2","8","."], +//  [".",".",".","4","1","9",".",".","5"], +//  [".",".",".",".","8",".",".","7","9"] +//] +//输出: false +//解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 +// 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 +// +// 说明: +// +// +// 一个有效的数独(部分已被填充)不一定是可解的。 +// 只需要根据以上规则,验证已经填入的数字是否有效即可。 +// 给定数独序列只包含数字 1-9 和字符 '.' 。 +// 给定数独永远是 9x9 形式的。 +// +// Related Topics 哈希表 + +package com.markdown.leetcode.editor.cn; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LeetCode_36_ValidSudoku { + public static void main(String[] args) { + Solution solution = new LeetCode_36_ValidSudoku().new Solution(); + char[][] board = new char[][]{ + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + solution.isValidSudoku(board); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public boolean isValidSudoku(char[][] board) { + if (board == null || board.length == 0) return false; + + List> row = new ArrayList<>(9); + List> col = new ArrayList<>(9); + List> bol = new ArrayList<>(9); + + for (int i = 0; i < 9; i++) { + row.add(i, new HashSet<>(9)); + col.add(i, new HashSet<>(9)); + bol.add(i, new HashSet<>(9)); + } + + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (row.get(i).contains(board[i][j])) { + return false; + } + row.get(i).add(board[i][j]); + + if (col.get(j).contains(board[i][j])) { + return false; + } + col.get(j).add(board[i][j]); + + int k = (i / 3) * 3 + j / 3; + if (bol.get(k).contains(board[i][j])) { + return false; + } + bol.get(k).add(board[i][j]); + } + } + return true; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 06/id_481/leetcode_200_481.java b/Week 06/id_481/leetcode_200_481.java new file mode 100644 index 000000000..d60fde301 --- /dev/null +++ b/Week 06/id_481/leetcode_200_481.java @@ -0,0 +1,36 @@ +class Solution { + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } +} \ No newline at end of file diff --git a/Week 06/id_481/leetcode_547_481.java b/Week 06/id_481/leetcode_547_481.java new file mode 100644 index 000000000..94e0c555a --- /dev/null +++ b/Week 06/id_481/leetcode_547_481.java @@ -0,0 +1,21 @@ +class Solution { + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_491/LeetCode_208_491.java b/Week 06/id_491/LeetCode_208_491.java new file mode 100644 index 000000000..c2373b0b8 --- /dev/null +++ b/Week 06/id_491/LeetCode_208_491.java @@ -0,0 +1,78 @@ +class Trie { + + private TrieNode[] root; + + /** Initialize your data structure here. */ + public Trie() { + this.root = new TrieNode[26]; + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + if(word != null && word.length() > 0) { + TrieNode[] temp = root; + for(int i = 0; i < word.length(); i++) { + int tempIndex = word.charAt(i) - 'a'; + TrieNode tempNode = temp[tempIndex]; + if(tempNode == null) { + tempNode = new TrieNode(); + tempNode.value = word.charAt(i); + temp[tempIndex] = tempNode; + } + + if(i == word.length() - 1) { + tempNode.isWord = true; + } + temp = temp[tempIndex].next; + } + } + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + if(word != null && word.length() > 0) { + TrieNode[] temp = root; + for(int i = 0; i < word.length(); i++) { + int tempIndex = word.charAt(i) - 'a'; + if(temp[tempIndex] == null) { + return false; + } else { + if(i == word.length() - 1) { + if(temp[tempIndex].isWord) { + return true; + } else { + return false; + } + } + temp = temp[tempIndex].next; + } + } + } + return false; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + if(prefix != null && prefix.length() > 0) { + TrieNode[] temp = root; + for(int i = 0; i < prefix.length(); i++) { + int tempIndex = prefix.charAt(i) - 'a'; + if(temp[tempIndex] == null) { + return false; + } else { + if(i == prefix.length() - 1) { + return true; + } + temp = temp[tempIndex].next; + } + } + } + return false; + } + + class TrieNode { + public boolean isWord; + public char value; + public TrieNode[] next = new TrieNode[26]; + } +} diff --git a/Week 06/id_491/LeetCode_547_491.java b/Week 06/id_491/LeetCode_547_491.java new file mode 100644 index 000000000..12996424a --- /dev/null +++ b/Week 06/id_491/LeetCode_547_491.java @@ -0,0 +1,52 @@ +class Solution { + public int findCircleNum(int[][] M) { + if (M == null || M.length == 0 || M[0].length == 0) { + return 0; + } + UnionFind union = new UnionFind(M.length); + for (int i = 0; i < M.length; i++) { + for (int j = i + 1; j < M.length; j++) { + if(M[i][j] == 1) { + union.union(i, j); + if(union.count == 1) { + return 1; + } + } + } + } + + return union.count; + } + + class UnionFind { + public int count; + private int[] parent; + + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + int temp = p; + while (parent[temp] != temp) { + parent[temp] = parent[parent[temp]]; + temp = parent[temp]; + } + return temp; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) { + return; + } + parent[rootP] = rootQ; + count--; + } + } +} diff --git a/Week 06/id_501/week06/LeetCode_217_501.java b/Week 06/id_501/week06/LeetCode_217_501.java new file mode 100644 index 000000000..10cfb0de6 --- /dev/null +++ b/Week 06/id_501/week06/LeetCode_217_501.java @@ -0,0 +1,63 @@ +package homework.week06; + +import java.util.*; + +/** + * 127. 单词接龙 + * https://leetcode-cn.com/problems/word-ladder + * @author tangxy + * @date 2019-11-24 + */ +public class LeetCode_217_501 { + public int ladderLength(String beginWord, String endWord, List wordList) { + if(!wordList.contains(endWord)){ + return 0; + } + int n = beginWord.length(); + Map> allCommons = new HashMap<>(); + wordList.forEach(word -> { + for (int i = 0; i < n; i++) { + String common = word.substring(0,i) + "*" + word.substring(i + 1); + if(!allCommons.containsKey(common)){ + allCommons.put(common,new ArrayList<>()); + } + allCommons.get(common).add(word); + } + }); + Set begin = new HashSet<>(); + Set end = new HashSet<>(); + begin.add(beginWord); + end.add(endWord); + Set visited = new HashSet<>(); + int len = 1; + while(!begin.isEmpty() && !end.isEmpty()){ + if(begin.size() > end.size()){ + Set tmp = begin; + begin = end; + end = tmp; + } + Set neighbor = new HashSet<>(); + for (String cur : begin) { + for (int i = 0; i < n; i++) { + String tmp = cur.substring(0,i) + "*" + cur.substring(i+1); + if(!allCommons.containsKey(tmp)){ + continue; + } + for (String str : allCommons.get(tmp)) { + if(end.contains(str)){ + return len + 1; + } + if(!visited.contains(str)){ + visited.add(str); + neighbor.add(str); + } + } + } + } + begin =neighbor; + len ++; + } + return 0; + } + +} diff --git a/Week 06/id_501/week06/LeetCode_547_501.java b/Week 06/id_501/week06/LeetCode_547_501.java new file mode 100644 index 000000000..9eba5b484 --- /dev/null +++ b/Week 06/id_501/week06/LeetCode_547_501.java @@ -0,0 +1,45 @@ +package homework.week06; + +import java.util.Arrays; + +/** + * 547. 朋友圈 + * https://leetcode-cn.com/problems/friend-circles/ + * @author tangxy + * @date 2019-11-24 + */ +public class LeetCode_547_501 { + + int find(int[] parent,int i){ + if(parent[i] == -1){ + return i; + } + return find(parent,parent[i]); + } + void union(int[] parent,int x,int y){ + int xset = find(parent,x); + int yset = find(parent,y); + if(xset != yset){ + parent[xset] = yset; + } + } + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent,-1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if(M[i][j] == 1 && i != j){ + union(parent,i,j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if(parent[i] == -1){ + count ++; + } + } + return count; + } +} diff --git a/Week 06/id_501/week06/Trie.java b/Week 06/id_501/week06/Trie.java new file mode 100644 index 000000000..9ffc036d1 --- /dev/null +++ b/Week 06/id_501/week06/Trie.java @@ -0,0 +1,137 @@ +package homework.week06; + +import java.util.LinkedList; + +/** + * 实现Trie字典树 + * @author tangxy + * @date 2019-11-24 + */ +public class Trie { + + public static void main(String[] args) { + Trie trie = new Trie(); + trie.insert("hello"); + trie.insert("helloworld"); + trie.insert("hellotree"); + System.out.println(trie.search("hello")); + System.out.println(trie.startsWith("hello2")); + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(' '); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + // 已存在,不插入 + if(search(word)){ + return; + } + TrieNode current = root; + for (int i = 0; i < word.length(); i++) { + TrieNode child = current.subNode(word.charAt(i)); + if(child != null){ + current = child; + }else { + current.childList.add(new TrieNode(word.charAt(i))); + current = current.subNode(word.charAt(i)); + } + current.count ++ ; + } + current.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode current = root; + for (int i = 0; i < word.length(); i++) { + if(current.subNode(word.charAt(i)) == null){ + return false; + }else{ + current = current.subNode(word.charAt(i)); + } + } + if(current.isEnd){ + return true; + } + return false; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode current = root; + for (int i = 0; i < prefix.length(); i++) { + if(current.subNode(prefix.charAt(i)) == null){ + return false; + }else{ + current = current.subNode(prefix.charAt(i)); + } + } + return true; + } + + /** + * 删除字符串 + * @param word + */ + public void deleteWord(String word){ + if(!search(word)){ + return; + } + TrieNode current = root; + for(char c : word.toCharArray()){ + TrieNode child = current.subNode(c); + if(child.count == 1){ + current.childList.remove(child); + return; + }else { + child.count --; + current = child; + } + } + current.isEnd = false; + } + + class TrieNode { + /** + * 内容 + */ + char content; + /** + * 是否是最后 + */ + boolean isEnd; + /** + * 统计 + */ + int count; + /** + * 子树 + */ + LinkedList childList; + + public TrieNode(char content) { + this.content = content; + this.isEnd = false; + this.count = 0; + this.childList = new LinkedList<>(); + } + + public TrieNode subNode(char c){ + if(childList != null){ + for (TrieNode trieNode : childList) { + if(trieNode.content == c){ + return trieNode; + } + } + } + return null; + } + + } + +} diff --git a/Week 06/id_501/week06/UnionFind.java b/Week 06/id_501/week06/UnionFind.java new file mode 100644 index 000000000..78eb58fc1 --- /dev/null +++ b/Week 06/id_501/week06/UnionFind.java @@ -0,0 +1,37 @@ +package homework.week06; + +/** + * 并查集代码模版 + * @author tangxy + * @date 2019-11-24 + */ +public class UnionFind { + private int count = 0; + private int[] parent; + + public UnionFind(int n){ + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p){ + while(p != parent[p]){ + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p,int q){ + int rootP = find(p); + int rootQ = find(q); + if(rootP == rootQ){ + return; + } + parent[rootP] = rootQ; + count --; + } +} diff --git a/Week 06/id_506/LeetCode_208_506.java b/Week 06/id_506/LeetCode_208_506.java new file mode 100644 index 000000000..13003267a --- /dev/null +++ b/Week 06/id_506/LeetCode_208_506.java @@ -0,0 +1,104 @@ +class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode parent = root; + for (int i = 0; i < word.length(); i++){ + char ch = word.charAt(i); + if (!parent.containsKey(ch)) { + parent.put(new TrieNode(), ch); + } + parent = parent.get(ch); + } + parent.setIsEnd(true); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode parent = root; + for (int i = 0; i < word.length(); i++){ + + if (parent.containsKey(word.charAt(i))){ + if (!parent.getIsEnd()){ + parent = parent.get(word.charAt(i)); + } + }else { + return false; + } + + } + if (!parent.getIsEnd()){ + return false; + } + return true; + + + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode parent = root; + for (int i = 0; i < prefix.length(); i++){ + + if (parent.containsKey(prefix.charAt(i))){ + if (!parent.getIsEnd()){ + parent = parent.get(prefix.charAt(i)); + } + }else { + return false; + } + + } + + return true; + } + + public class TrieNode{ + + TrieNode[] links; + + final int R = 26; + + private boolean isEnd; + + public TrieNode(){ + links = new TrieNode[26]; + } + + public boolean containsKey(char ch){ + if (links[ch - 'a'] == null){ + return false; + } + return true; + } + + public TrieNode get(char ch){ + return links[ch - 'a']; + } + + + public void put(TrieNode node, char ch){ + int index = ch - 'a'; + links[index] = node; + } + public void setIsEnd(boolean isEnd){ + this.isEnd = isEnd; + } + + public boolean getIsEnd(){ + return this.isEnd; + } + + + + + } + +} \ No newline at end of file diff --git a/Week 06/id_506/LeetCode_547_506.java b/Week 06/id_506/LeetCode_547_506.java new file mode 100644 index 000000000..53a0a5599 --- /dev/null +++ b/Week 06/id_506/LeetCode_547_506.java @@ -0,0 +1,32 @@ +class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } + +} \ No newline at end of file diff --git a/Week 06/id_511/LeetCode_130_511.java b/Week 06/id_511/LeetCode_130_511.java new file mode 100644 index 000000000..77445a866 --- /dev/null +++ b/Week 06/id_511/LeetCode_130_511.java @@ -0,0 +1,49 @@ +package id_511; + +/** + * @version 1.0 + * @Description: 130. 被围绕的区域 + * @author: bingyu + * @date: 2019/11/24 19:00 + */ +public class LeetCode_130_511 { + + public void solve(char[][] board) { + if (board == null || board.length == 0) return; + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 从边缘o开始搜索 + boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1; + if (isEdge && board[i][j] == 'O') { + dfs(board, i, j); + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + if (board[i][j] == '#') { + board[i][j] = 'O'; + } + } + } + } + + public void dfs(char[][] board, int i, int j) { + if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') { + // board[i][j] == '#' 说明已经搜索过了. + return; + } + board[i][j] = '#'; + dfs(board, i - 1, j); // 上 + dfs(board, i + 1, j); // 下 + dfs(board, i, j - 1); // 左 + dfs(board, i, j + 1); // 右 + } + +} diff --git a/Week 06/id_511/LeetCode_547_511.java b/Week 06/id_511/LeetCode_547_511.java new file mode 100644 index 000000000..1add352e7 --- /dev/null +++ b/Week 06/id_511/LeetCode_547_511.java @@ -0,0 +1,31 @@ +package id_511; + +/** + * @version 1.0 + * @Description: 朋友圈 + * @author: bingyu + * @date: 2019/11/24 18:58 + */ +public class LeetCode_547_511 { + + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + +} diff --git a/Week 06/id_511/NOTE.md b/Week 06/id_511/NOTE.md index a6321d6e2..8cab6b97d 100644 --- a/Week 06/id_511/NOTE.md +++ b/Week 06/id_511/NOTE.md @@ -1,4 +1,28 @@ -# NOTE - - - +一、并查集 +1. 情景 +组团、配对问题 + +2. 基本操作 +(1).makeSet(s):建立一个新的并查集,其中包含s个单元素集合。 +(2).unionSet(x,y):把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交不合并。 +(3).find(x):找到元素x所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将他们各自的代表比较以下就可以了 + +二、高级搜索 +1.剪枝: +状态树是树和分支的形态 + +2.回溯: +回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是几步的计算,再通过其它可能的分步解答再次寻找问题的答案。 +回溯法通常采用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: +找到一个可能存在的正确的答案 +在尝试了所有可能的分步方法后宣告该问题没有答案 +在最坏的情况下,回溯法会导致一次复杂度为指数级时间的计算。 + +3.双向BFS +和单向BFS异曲同工 + +4.启发式搜索 +根据某一项条件,优化搜索方向,通过优先级 + + + diff --git a/Week 06/id_516/Leetcode_37_516.java b/Week 06/id_516/Leetcode_37_516.java new file mode 100644 index 000000000..47ef54573 --- /dev/null +++ b/Week 06/id_516/Leetcode_37_516.java @@ -0,0 +1,38 @@ +public class LeetCode37 { + public void solveSudoku(char[][] board) { + if (board == null || board.length == 0) + return; + solve(board); + } + + private boolean solve(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == '.') { + for (char c = '1'; c <= '9';c++) { + if (isValid(board,i,j,c)) { + board[i][j] = c; + if (solve(board)) { + return true; + } + // rollback + board[i][j] = '.'; + } + } + return false; + } + } + } + return true; + } + + private boolean isValid(char[][] board, int row, int col, char c) { + for (int i = 0; i < 9; i++) { + if (board[i][col] != '.' && board[i][col] == c)return false; + if (board[row][i] != '.' && board[row][i] == c)return false; + if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] != '.' + && board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c)return false; + } + return true; + } +} diff --git a/Week 06/id_516/Leetcode_773_516.java b/Week 06/id_516/Leetcode_773_516.java new file mode 100644 index 000000000..40056fb3e --- /dev/null +++ b/Week 06/id_516/Leetcode_773_516.java @@ -0,0 +1,99 @@ +package com.hjj.leetcode.week6.nov24; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; + +public class LeetCode773 { + public int slidingPuzzle(int[][] board) { + int R = board.length, C = board[0].length; + int sr = 0, sc = 0; + + //Find sr, sc + search: + for (sr = 0; sr < R; sr++) + for (sc = 0; sc < C; sc++) + if (board[sr][sc] == 0) + break search; + + int[][] directions = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + PriorityQueue heap = new PriorityQueue((a, b) -> + (a.heuristic + a.depth) - (b.heuristic + b.depth)); + Node start = new Node(board, sr, sc, 0); + heap.add(start); + + Map cost = new HashMap(); + cost.put(start.boardstring, 9999999); + + String target = Arrays.deepToString(new int[][]{{1, 2, 3}, {4, 5, 0}}); + String targetWrong = Arrays.deepToString(new int[][]{{1, 2, 3}, {5, 4, 0}}); + + while (!heap.isEmpty()) { + Node node = heap.poll(); + if (node.boardstring.equals(target)) + return node.depth; + if (node.boardstring.equals(targetWrong)) + return -1; + if (node.depth + node.heuristic > cost.get(node.boardstring)) + continue; + + for (int[] di : directions) { + int nei_r = di[0] + node.zero_r; + int nei_c = di[1] + node.zero_c; + + // If the neighbor is not on the board or wraps incorrectly around rows/cols + if ((Math.abs(nei_r - node.zero_r) + Math.abs(nei_c - node.zero_c) != 1) || + nei_r < 0 || nei_r >= R || nei_c < 0 || nei_c >= C) + continue; + + int[][] newboard = new int[R][C]; + int t = 0; + for (int[] row : node.board) + newboard[t++] = row.clone(); + + // Swap the elements on the new board + newboard[node.zero_r][node.zero_c] = newboard[nei_r][nei_c]; + newboard[nei_r][nei_c] = 0; + + Node nei = new Node(newboard, nei_r, nei_c, node.depth + 1); + if (nei.depth + nei.heuristic >= cost.getOrDefault(nei.boardstring, 9999999)) + continue; + heap.add(nei); + cost.put(nei.boardstring, nei.depth + nei.heuristic); + } + } + + return -1; + } +} + +class Node { + int[][] board; + String boardstring; + int heuristic; + int zero_r; + int zero_c; + int depth; + + Node(int[][] B, int zr, int zc, int d) { + board = B; + boardstring = Arrays.deepToString(board); + + //Calculate heuristic + heuristic = 0; + int R = B.length, C = B[0].length; + for (int r = 0; r < R; ++r) + for (int c = 0; c < C; ++c) { + if (board[r][c] == 0) continue; + int v = (board[r][c] + R * C - 1) % (R * C); + // v/C, v%C: where board[r][c] should go in a solved puzzle + heuristic += Math.abs(r - v / C) + Math.abs(c - v % C); + } + heuristic /= 2; + zero_r = zr; + zero_c = zc; + depth = d; + } +} + diff --git a/Week 06/id_516/NOTE.md b/Week 06/id_516/NOTE.md index a6321d6e2..0d839f769 100644 --- a/Week 06/id_516/NOTE.md +++ b/Week 06/id_516/NOTE.md @@ -1,4 +1,167 @@ -# NOTE +# 字典树 +> 单词查找树,Trie树。典型应用用于统计、排序和保存大量的字符串,经常呗搜索引擎系统应用于文本词频统计。优点:利用字符串的公共前缀来减少查询的时间,减少无所谓的字符串比较,查询效率比哈希树高。 + +```java +class TrieNode { + public boolean isWord; + public TrieNode[] children = new TrieNode[26]; + public TrieNode() {} +} + +class Trie { + private TrieNode root; + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode ws = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (ws.children[c - 'a'] == null) { + ws.children[c - 'a'] = new TrieNode(); + } + ws = ws.children[c - 'a']; + } + ws.isWord = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode ws = root; + for (int i = 0; i < word.length(); i ++) { + char c = word.charAt(i); + if (ws.children[c - 'a'] == null) return false; + ws = ws.children[c -'a']; + } + return ws.isWord; + } + + + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode ws = root; + for (int i = 0; i < prefix.length(); i++) { + char c = prefix.charAt(i); + if (ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a'] + } + return true; + } +} +``` + +### 题目 + +- https://leetcode-cn.com/problems/implement-trie-prefix-tree/#/description +- https://leetcode-cn.com/problems/word-search-ii/ + + + + + +# 并查集 + +> 是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题。 + + + +### 题目 + +- https://leetcode-cn.com/problems/friend-circles/ +- https://leetcode-cn.com/problems/number-of-islands/ +- https://leetcode-cn.com/problems/surrounded-regions/ + +# 高级搜索 + +优化: 不重复,剪枝(生成括号问题) + +搜索方向:DFS、BFS、双向搜索、启发式搜索 + + + +## 剪枝 + +> 深度优先搜索中让搜索树减少一些节点,使得搜索时间减少的功能。 + + + + + +### 题目 + +- https://leetcode-cn.com/problems/n-queens/ +- https://leetcode-cn.com/problems/valid-sudoku/description/ +- https://leetcode-cn.com/problems/sudoku-solver/#/description + + + + + +## 双向BFS + +> 双向BFS适用于知道起点和终点的状态下使用,从起点和终点两个方向开始进行搜索,可以非常大的提高单个BFS的搜索效率。 + + + +```python +def BFS(graph,start,end): + start_queue = [] + end_queue = [] + start_queue.append([start]) + end_queue.append([end]) + while start_queue: + node = start_queue.pop() + visited.add(node) + + process(node) + + nodes = generate_related_nodes(node) + queue.push(nodes) + + if (len(start_queue) > len(end_queue)): + start_queue,end_queue = end_queue,start_queue + + ... + +``` + + + +### 题目 + +- https://leetcode-cn.com/problems/word-ladder/ +- https://leetcode-cn.com/problems/minimum-genetic-mutation/ + + + +## 启发式搜索 + +> 依赖于估价函数与优先级队列。 +> +> 启发式搜索(Heuristically Search)又称为有信息搜索(Informed Search),它是利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的,这种利用启发信息的搜索过程称为启发式搜索。 + + + + + +### 题目 + + + +- https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/ +- https://leetcode-cn.com/problems/sliding-puzzle/ +- https://leetcode-cn.com/problems/sudoku-solver/ + + + + + +## 平衡树 +> 它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。实现有红黑树、AVL.... \ No newline at end of file diff --git a/Week 06/id_526/LeetCode_200_526 b/Week 06/id_526/LeetCode_200_526 new file mode 100644 index 000000000..332df6882 --- /dev/null +++ b/Week 06/id_526/LeetCode_200_526 @@ -0,0 +1,78 @@ +class Solution { + class UnionFind { + int count; // # of connected components + int[] parent; + int[] rank; + + public UnionFind(char[][] grid) { // for problem 200 + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { // path compression + if (parent[i] != i) parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { // union with rank + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r-1][c] == '1') { + uf.union(r * nc + c, (r-1) * nc + c); + } + if (r + 1 < nr && grid[r+1][c] == '1') { + uf.union(r * nc + c, (r+1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c-1] == '1') { + uf.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c+1] == '1') { + uf.union(r * nc + c, r * nc + c + 1); + } + } + } + } + return uf.getCount(); + } +} \ No newline at end of file diff --git a/Week 06/id_526/LeetCode_547_526 b/Week 06/id_526/LeetCode_547_526 new file mode 100644 index 000000000..7d9473f6d --- /dev/null +++ b/Week 06/id_526/LeetCode_547_526 @@ -0,0 +1,31 @@ +class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_536/leetcode_208_536.cpp b/Week 06/id_536/leetcode_208_536.cpp new file mode 100644 index 000000000..1e8ad9abb --- /dev/null +++ b/Week 06/id_536/leetcode_208_536.cpp @@ -0,0 +1,105 @@ +#include +#include + +using namespace std; +/***** + 1ʾINSERT "cp" + ROOT(this) + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[c-'a'] + --------------------------- + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[p-'a'] + --------------------------- + isEnd = true + p = new Trie(); һڵ + abcdefghijklmnopqrstuvwxyz + + 2ʾINSERT "apple" + ROOT(this) + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[a-'a'] + --------------------------- + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[p-'a'] + -------------------------- + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[p-'a'] + -------------------------- + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[l-'a'] + -------------------------- + isEnd = false + abcdefghijklmnopqrstuvwxyz + | next[e-'a'] + -------------------------- + isEnd = true + p = new Trie(); + abcdefghijklmnopqrstuvwxyz +******/ + +class Trie { + Trie *next[26]; + bool isEnd; +public: + /** Initialize your data structure here. */ + Trie() { + isEnd = false;//ָڵǶӦĽβֻǼǰ׺ + memset(next,0,sizeof(next)); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + Trie *p = this;//pʼΪָroot + for(char c : word) { + if(!p->next[c-'a']) { + p->next[c-'a'] = new Trie(); + } + p = p->next[c-'a']; + } + p->isEnd = true; //ָڵǶӦĽβ + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + Trie *p = this; + for(char c : word) { + if(!p->next[c-'a']){ + return false; + } + p = p->next[c-'a']; + } + return p->isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + Trie *p = this; + for(char c : prefix) { + if(!p->next[c-'a']){ + return false; + } + p = p->next[c-'a']; + } + return true; + } +}; + + +int main() +{ + Trie* obj = new Trie(); + obj->insert("apple"); + cout << obj->search("apple") <search("app") <startsWith("app") <insert("app"); + cout << obj->search("app") < +#include +#include +#include + +using namespace std; + +//copy +class TrieNode{ +public: + bool is_end; + vector children; + TrieNode(){ + is_end=false; + children=vector(26, NULL); + } +}; + +class Trie{ +public: + TrieNode* getRoot(){return root;} + Trie(vector& words){ + root=new TrieNode(); + for(int i=0; ichildren[index]==NULL) + cur->children[index]=new TrieNode(); + cur=cur->children[index]; + } + cur->is_end=true; + } +private: + TrieNode* root; +}; + +class Solution { +public: + vector findWords(vector>& board, vector& words) { + Trie* trie = new Trie(words); + TrieNode* root=trie->getRoot(); + set result_set; + for(int x=0; x result; + for(auto it:result_set) result.push_back(it); + return result; + } +private: + void findWords(vector>& board, int x, int y, TrieNode* root, string word, set& result){ + if(x<0||x>=board.size()||y<0||y>=board[0].size() || board[x][y]==' ') return; + + if(root->children[board[x][y]-'a'] != NULL){ + word=word+board[x][y]; + root=root->children[board[x][y]-'a']; + if(root->is_end) result.insert(word); + char c=board[x][y]; + board[x][y]=' '; + findWords(board, x+1, y, root, word, result); + findWords(board, x-1, y, root, word, result); + findWords(board, x, y+1, root, word, result); + findWords(board, x, y-1, root, word, result); + board[x][y]=c; + } + } +}; + + +int main() +{ + cout << "Hello world!" << endl; + return 0; +} diff --git a/Week 06/id_546/LeetCode_208_546.cs b/Week 06/id_546/LeetCode_208_546.cs new file mode 100644 index 000000000..2d28131db --- /dev/null +++ b/Week 06/id_546/LeetCode_208_546.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + ///

+ /// 208. 实现 Trie (前缀树) + /// + + class TrieNode + { + public char val; + public bool isWord; + public TrieNode[] children = new TrieNode[26]; + public TrieNode() { } + public TrieNode(char c) + { + TrieNode node = new TrieNode(); + node.val = c; + } + } + + public class Trie + { + private TrieNode root; + public Trie() + { + root = new TrieNode(); + root.val = ' '; + } + + public void Insert(String word) + { + TrieNode ws = root; + for (int i = 0; i < word.Length; i++) + { + char c = word[i]; + if (ws.children[c - 'a'] == null) + { + ws.children[c - 'a'] = new TrieNode(c); + } + ws = ws.children[c - 'a']; + } + ws.isWord = true; + } + + public bool Search(String word) + { + TrieNode ws = root; + for (int i = 0; i < word.Length; i++) + { + char c = word[i]; + if (ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return ws.isWord; + } + + public bool StartsWith(String prefix) + { + TrieNode ws = root; + for (int i = 0; i < prefix.Length; i++) + { + char c = prefix[i]; + if (ws.children[c - 'a'] == null) return false; + ws = ws.children[c - 'a']; + } + return true; + } + } +} diff --git a/Week 06/id_546/LeetCode_51_546.cs b/Week 06/id_546/LeetCode_51_546.cs new file mode 100644 index 000000000..e92b679ed --- /dev/null +++ b/Week 06/id_546/LeetCode_51_546.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hard +{ + /// + /// 51. N皇后 + /// + public class NQueens + { + + } + + + public class Solution + { + public List> SolveNQueens(int n) + { + List> res = new List>(); + bool[] vertical = new bool[n]; + bool[] tiltU = new bool[2 * n - 1]; + bool[] tiltD = new bool[2 * n - 1]; + int[] h = new int[n]; + helper(res, h, vertical, tiltU, tiltD, n, 0); + return res; + } + + void helper(List> res, int[] h, bool[] v, bool[] u, bool[] d, int n, int row) + { + if (row == n) + { + List list = new List(); + for (int i = 0; i < n; i++) + { + char[] cs = new char[n]; + Array.Fill(cs, '.'); + cs[h[i]] = 'Q'; + list.Add(new String(cs)); + } + res.Add(list); + return; + } + + for (int col = 0; col < n; col++) + { + if (v[col] || u[col + row] || d[row - col + n - 1]) + { + continue; + } + v[col] = true; + u[col + row] = true; + d[row - col + n - 1] = true; + h[row] = col; + helper(res, h, v, u, d, n, row + 1); + v[col] = false; + u[col + row] = false; + d[row - col + n - 1] = false; + } + } + } + + + +} diff --git a/Week 06/id_551/LeetCode_208_551.py b/Week 06/id_551/LeetCode_208_551.py new file mode 100644 index 000000000..b37b70e13 --- /dev/null +++ b/Week 06/id_551/LeetCode_208_551.py @@ -0,0 +1,27 @@ +class Trie: + def __init__(self): + self.dic={} + def insert(self,strr): + a=self.dic + for i in strr: + if not i in a: + a[i]={} + a=a[i] + a["end"]=True + def search(self,strr): + a=self.dic + for i in strr: + if not i in a: + return False + a=a[i] + if "end" in a: + return True + else: + return False + def startsWith(self,strr): + a=self.dic + for i in strr: + if not i in a: + return False + a=a[i] + return True diff --git a/Week 06/id_551/LeetCode_547_551.py b/Week 06/id_551/LeetCode_547_551.py new file mode 100644 index 000000000..32c2ffac8 --- /dev/null +++ b/Week 06/id_551/LeetCode_547_551.py @@ -0,0 +1,16 @@ +def findCircleNum2(self, M): + n = len(M) + circles = {i: i for i in range(n)} + + def find(i): + if i == circles[i]: + return i + circles[i] = find(circles[i]) + return circles[i] + + for i in range(n): + for j in range(i + 1, n): + if M[i][j] == 1: + circles[find(i)] = find(j) + + return sum([1 for k, v in circles.items() if k == v]) diff --git a/Week 06/id_556/LeetCode_208_556.java b/Week 06/id_556/LeetCode_208_556.java new file mode 100644 index 000000000..2030699b1 --- /dev/null +++ b/Week 06/id_556/LeetCode_208_556.java @@ -0,0 +1,72 @@ +public class Trie { + public boolean isWord; + public char word; + public Trie[] tries = new Trie[26]; + + /** + * Initialize your data structure here. + */ + public Trie() { + this.isWord = false; + this.word = ' '; + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] == null) { + node.tries[array[i] - 'a'] = new Trie(); + } + node = node.tries[array[i] - 'a']; + node.word = array[i]; + if (i == array.length - 1) { + node.isWord = true; + } + } + + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return node.isWord == true ? true : false; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + char[] array = prefix.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return true; + } +} diff --git a/Week 06/id_556/LeetCode_547_556.java b/Week 06/id_556/LeetCode_547_556.java new file mode 100644 index 000000000..23bd39433 --- /dev/null +++ b/Week 06/id_556/LeetCode_547_556.java @@ -0,0 +1,81 @@ +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; + +public class FriendCircle { + // 1. DFS (O(n^2)) + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + // 2. BFS (O(n^2)) + public int findCircleNum2(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + Queue queue = new LinkedList<>(); + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + queue.add(i); + while (!queue.isEmpty()) { + int s = queue.remove(); + visited[s] = 1; + for (int j = 0; j < M.length; j++) { + if (M[s][j] == 1 && visited[j] == 0) + queue.add(j); + } + } + count++; + } + } + return count; + } + + // 3. UnionFind (O(n^3)) + public int findCircleNum3(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } + + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } +} \ No newline at end of file diff --git a/Week 06/id_556/NOTE.md b/Week 06/id_556/NOTE.md index a6321d6e2..9b5ce5b65 100644 --- a/Week 06/id_556/NOTE.md +++ b/Week 06/id_556/NOTE.md @@ -1,4 +1,88 @@ -# NOTE +### 字典树(Trie) - +又称单词查找树或键树,是一种多叉树,典型应用是统计和排序大量的字符串(或其他数据),经常被搜索引擎用于文本词频统计。优点是最大限度地减少无谓的字符串比较,查询效率比哈希表高。核心思想是利用字符串的公共前缀来降低时间开销,达到空间换时间的效率提升。 +字典树的特征: + +1. 节点不会存完整单词,而是字符 +2. 从根节点到某一节点,路径上经过的字符连接起来为该节点对应的字符串 +3. 每个节点的所有子节点路径代表的字符都不相同 + +### 并查集(DisjointSet/UnionFind) + +一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题,比如组团和配对问题。 + +实现并查集需要实现的三种操作: + +- makeSet(s) + +- unionSet(x,y) + +- find(x) + +--- + +### 二叉搜索树(Binary Search Tree) + +定义:左子树的所有节点都小于根节点,右子树所有节点都小于根节点 + +查找效率和高度有关,即O(logn) + +> 树和链表没有本质区别。二叉搜索树的极端情况:始终插入在一边,则会退化成链表,查找复杂度为O(n) + +因此,为保证性能,需要维持BST的平衡性和二维维度,故引入平衡二叉树(有很多形式,比如AVL、红黑树、2-3树和B+树) + +### AVL树 + +定义:平衡因子(balance factor)= 每个节点的左右子树高度差,最好保持在{-1, 0, 1}之间 + +通过旋转来进行平衡: + +- 左旋 +- 右旋 +- 左右旋 +- 右左旋 + +### 红黑树(Red-Black Tree) + +一种近似平衡二叉树,确保任何一个节点左右子树的高度差小于两倍,具有以下特点: + +- 每个节点要么是红色,要么是黑色 +- 根节点是黑色 +- 叶节点/空节点是黑色 +- 红色节点不能相邻 +- 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点 + +### 比较: + +- AVL因为更严格平衡,故查找性能更好 +- RBT的添加和删除更快,因为需要维护的旋转操作更少 +- AVL需要存储factor,RBT只需要一个bit来存Red或Black的状态,因此存储空间更少 +- 读操作多写操作少时用AVL(比如Database),否则用RBT(比如Map/Set的实现) + +### 高级搜索的三种优化 + +1. 剪枝:在朴素搜索的基础上,减少重复计算,或根据条件剪枝,尽早排除不可能的分支 + +2. 双向BFS(Two-ended):起点终点分别BFS,直到相遇 + +3. 启发式搜索(A*算法):根据问题特定的条件,使用优先队列代替BFS队列,优先扩散优先级高的,来引导搜索方向从而加速搜索过程 + +```python +def AStar(graph, start, end): + pq = colelctions.priority_queue + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(univisted) +``` + +启发式估价函数: h(n),根据问题特点,评价节点是否是所希望的解的可能性 + +> 如果简单以先入先出顺序为估价函数,则退化为简单BFS \ No newline at end of file diff --git a/Week 06/id_566/leetcode_212_566.py b/Week 06/id_566/leetcode_212_566.py new file mode 100644 index 000000000..859f56c79 --- /dev/null +++ b/Week 06/id_566/leetcode_212_566.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +/** + * 单词搜索 II + * https://leetcode-cn.com/problems/word-search-ii/ + * Author:show + */ +# 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 + + +def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + trie = {} # 构造字典树 + for word in words: + node = trie + for char in word: + node = node.setdefault(char, {}) + node['#'] = True + + def search(i, j, node, pre, visited): # (i,j)当前坐标,node当前trie树结点,pre前面的字符串,visited已访问坐标 + if '#' in node: # 已有字典树结束 + res.add(pre) # 添加答案 + for (di, dj) in ((-1, 0), (1, 0), (0, -1), (0, 1)): + _i, _j = i+di, j+dj + if -1 < _i < h and -1 < _j < w and board[_i][_j] in node and (_i, _j) not in visited: # 可继续搜索 + search(_i, _j, node[board[_i][_j]], pre+board[_i][_j], visited | {(_i, _j)}) # dfs搜索 + + res, h, w = set(), len(board), len(board[0]) + for i in range(h): + for j in range(w): + if board[i][j] in trie: # 可继续搜索 + search(i, j, trie[board[i][j]], board[i][j], {(i, j)}) # dfs搜索 + return list(res) \ No newline at end of file diff --git a/Week 06/id_566/leetcode_547_566.py b/Week 06/id_566/leetcode_547_566.py new file mode 100644 index 000000000..07db8ca55 --- /dev/null +++ b/Week 06/id_566/leetcode_547_566.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +/** + * 朋友圈 + * https://leetcode-cn.com/problems/friend-circles/ + * Author:show + */ +# 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 +# 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + + +class Solution(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + # 声明表示集合的树,用数组表示树,如 parent[5] == -1 表示 + # 5 是某个集合的代表,同时也是树根 + parent = [-1] * len(M) + # 为各个集合的深度排个序 + rank = dict() + # 只遍历左下部分 + for i in range(len(M)): + for j in range(i): + if M[i][j] == 1: + # 如果两人是朋友,就把两人放入同一个集合 + self.union(i, j, parent, rank) + ans = 0 + for i in parent: # 查看有多少集合,即多少个朋友圈 + if i == -1: + ans += 1 + return ans + + def findRoot(self, num, parent): + """ + :num:某个小朋友 + :parent:多个集合树 + 一直找到这个小朋友所在集合的代表,即树根 + """ + while parent[num] != -1: + num = parent[num] + return num + + def union(self, x, y, parent, rank): + """ + x,y 表示满足朋友关系的两小朋友 + """ + if x == y: # 表示自己和自己是朋友,这个直接返回 + return + x = self.findRoot(x, parent) # 找到所在集合的代表,可能就是自己 + y = self.findRoot(y, parent) + rank_x = rank[x] if x in rank else 0 # 查询该集合目前的深度 + rank_y = rank[y] if y in rank else 0 + if x == y: # 检测到 x, y 已经是在同一个集合了,直接返回 + return + if rank_x > rank_y: # 这里是做路径压缩的,避免树太深使得 findRoot 函数耗时过多 + parent[y] = x + elif rank_x < rank_y: + parent[x] = y + else: + parent[x] = y + rank[y] = 1 \ No newline at end of file diff --git a/Week 06/id_571/leetcode_1091_571.js b/Week 06/id_571/leetcode_1091_571.js new file mode 100644 index 000000000..0ce07132f --- /dev/null +++ b/Week 06/id_571/leetcode_1091_571.js @@ -0,0 +1,48 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var shortestPathBinaryMatrix = function(grid) { + //BFS + let que = new Array(); + let len = 1; + que.push({ i: 0, j: 0 }); + + while (que.length > 0) { + let i = 0, + end = que.length, + temp; + let q = new Array(); + while (i < end) { + temp = que[i]; + if ( + temp.i < 0 || + temp.j < 0 || + temp.i >= grid.length || + temp.j >= grid.length || + grid[temp.i][temp.j] == 1 + ) { + i++; + continue; + } + if (temp.i == grid.length - 1 && temp.j == grid.length - 1) return len; + q.push({ i: temp.i, j: temp.j + 1 }); + q.push({ i: temp.i, j: temp.j - 1 }); + q.push({ i: temp.i + 1, j: temp.j }); + q.push({ i: temp.i + 1, j: temp.j + 1 }); + q.push({ i: temp.i + 1, j: temp.j - 1 }); + q.push({ i: temp.i - 1, j: temp.j }); + q.push({ i: temp.i - 1, j: temp.j + 1 }); + q.push({ i: temp.i - 1, j: temp.j - 1 }); + + grid[temp.i][temp.j] = 1; //block back entry to itself + i++; + } + que = q; + len++; + } + return -1; +}; +/* + +*/ diff --git a/Week 06/id_571/leetcode_208_571.js b/Week 06/id_571/leetcode_208_571.js new file mode 100644 index 000000000..7d00d8561 --- /dev/null +++ b/Week 06/id_571/leetcode_208_571.js @@ -0,0 +1,26 @@ +class Trie { + constructor() { + this.root = {}; + } + + insert(word) { + let node = this.root; + for (let i = 0; i < word.length; i++) { + node = node[word[i]] = node[word[i]] || {}; + if (i === word.length - 1) node.isTerminal = true; + } + } + + search(word, isPrefix) { + let node = this.root; + for (let c of word) { + if (!node[c]) return false; + node = node[c]; + } + return isPrefix || !!node.isTerminal; + } + + startsWith(prefix) { + return this.search(prefix, true); + } +} diff --git a/Week 06/id_576/LeetCode_212_576.java b/Week 06/id_576/LeetCode_212_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 06/id_576/LeetCode_547_576.java b/Week 06/id_576/LeetCode_547_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 06/id_586/NOTE.md b/Week 06/id_586/NOTE.md index a6321d6e2..009314a86 100644 --- a/Week 06/id_586/NOTE.md +++ b/Week 06/id_586/NOTE.md @@ -1,4 +1,19 @@ # NOTE - +```python +def AstarSearch(graph, start, end): + + pq = collections.priority_queue() # 优先级 —> 估价函数 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() # can we add more intelligence here ? + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` diff --git a/Week 06/id_586/leetcode_1091_586.cc b/Week 06/id_586/leetcode_1091_586.cc new file mode 100644 index 000000000..4d765e69d --- /dev/null +++ b/Week 06/id_586/leetcode_1091_586.cc @@ -0,0 +1,42 @@ +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + if (grid.empty() || grid[0].empty() || + grid[0][0] == 1 || + grid[grid.size()-1][grid[grid.size()-1].size()-1] == 1) + return -1; + + queue> q; + q.push({0, 0}); + + vector dx = {1, 0, 1, 1,-1,-1, 0,-1}; + vector dy = {1, 1, 0,-1, 1,-1,-1, 0}; + + int step = 1; + while (! q.empty()) { + auto v = q.front(); + q.pop(); + + int x = v.first; + int y = v.second; + if (x == (grid[0].size() - 1) && y == grid.size() - 1) + return step; + + if (grid[y][x] != -1) { + grid[y][x] = -1; + + for (int n = 0; n < 8; ++n) { + int nx = x + dx[n]; + int ny = y + dy[n]; + if (nx >= 0 && nx < grid[0].size() && + ny >= 0 && ny < grid.size() && + grid[ny][nx] == 0) { + q.push({nx, ny}); + } + } + } + ++step; + } + return -1; + } +}; diff --git a/Week 06/id_586/leetcode_208_586.cc b/Week 06/id_586/leetcode_208_586.cc new file mode 100644 index 000000000..024c0a240 --- /dev/null +++ b/Week 06/id_586/leetcode_208_586.cc @@ -0,0 +1,62 @@ +class Trie { +public: + /** Initialize your data structure here. */ + struct TrieNode { + TrieNode() { + for (int i = 0; i < 26; ++i) + nodes[i] = NULL; + end_of_the_word = false; + } + TrieNode* nodes[26]; + bool end_of_the_word; + }; + + Trie() { + + } + + /** Inserts a word into the trie. */ + void insert(string word) { + TrieNode* root = &root_; + for (const auto& ch : word) { + int index = ch - 'a'; + if (root->nodes[index] == NULL) + root->nodes[index] = new TrieNode(); + root = root->nodes[index]; + } + root->end_of_the_word = true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + TrieNode* node = find(word); + return node != NULL && node->end_of_the_word; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + TrieNode* node = find(prefix); + return node != NULL; + } + +private: + TrieNode* find(string word) { + TrieNode* root = &root_; + for (int i = 0; i < word.size() && root != NULL; ++i) { + int index = word[i] - 'a'; + root = root->nodes[index]; + } + return root; + } + +private: + TrieNode root_; +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ diff --git a/Week 06/id_586/leetcode_547_586.cc b/Week 06/id_586/leetcode_547_586.cc new file mode 100644 index 000000000..23d3c3dfb --- /dev/null +++ b/Week 06/id_586/leetcode_547_586.cc @@ -0,0 +1,57 @@ +class DisjointSet { +public: + DisjointSet(int n) { + n_ = new int[n]; + count_ = n; + for (int i = 0; i < n; ++i) + n_[i] = i; + } + + int find(int i) { + int n = n_[i]; + while (n != n_[n]) { + n = n_[n]; + } + + while (i != n) { + int tmp = n_[i]; + n_[i] = n; + i = n_[tmp]; + } + + return n; + } + + void uni(int p, int q) { + int rp = find(p); + int rq = find(q); + + if (rp == rq) + return; + + --count_; + n_[rp] = rq; + } + + int count() { return count_; } + +private: + int* n_; + int count_; +}; + +class Solution { +public: + int findCircleNum(vector>& M) { + DisjointSet dj(M.size()); + + for (int y = 0; y < M.size(); ++y) { + for (int x = 0; x < M[y].size(); ++x) { + if (M[y][x] == 1) + dj.uni(y, x); + } + } + + return dj.count(); + } +}; diff --git a/Week 06/id_591/LeetCode_200_591.js b/Week 06/id_591/LeetCode_200_591.js new file mode 100644 index 000000000..5d5bc66ad --- /dev/null +++ b/Week 06/id_591/LeetCode_200_591.js @@ -0,0 +1,62 @@ +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + let m = grid.length; + if(m == 0){ + return 0; + } + let n = grid[0].length; + let count = 0; + let parent = []; + let rank = []; + + + let find = (p) => { + while(p != parent[p]){ + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + let union = (p,q) => { + let rootP = find(p); + let rootQ = find(q); + if(rootP == rootQ){ + return; + } + if(rank[rootP] > rank[rootQ]){ + parent[rootQ] = rootP; + }else if(rank[rootP] < rank[rootQ]){ + parent[rootP] = rootQ; + }else{ + parent[rootP] = rootQ; + rank[rootQ]++; + } + count--; + } + + for(let i = 0;i < m;i++){ + for(let j = 0;j < n;j++){ + if(grid[i][j] == 1){ + parent[i * n + j] = i * n + j; + count++; + } + rank[i * n + j] = 0; + } + } + + for(var i = 0;i=0 && grid[i-1][j] == 1 && union(i*n + j,(i-1)*n + j); + j-1>=0 && grid[i][j-1] == 1 && union(i*n + j,i*n + j-1); + i+1 { + let currNode = root; + for(let i = 0;i < word.length;i++){ + if(currNode.children[word[i]]){ + currNode = currNode.children[word[i]]; + }else{ + return null; + } + } + return currNode; +} +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let currNode = this.searchPrefix(word); + return currNode != null && currNode.END; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + return this.searchPrefix(prefix) != null; +}; \ No newline at end of file diff --git a/Week 06/id_591/NOTE.md b/Week 06/id_591/NOTE.md index a6321d6e2..2404a4961 100644 --- a/Week 06/id_591/NOTE.md +++ b/Week 06/id_591/NOTE.md @@ -1,4 +1,47 @@ -# NOTE +# 学习总结 +## 1、字典树 +### 1.1、字典树定义 +字典树,即 Trie 树,又称单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串)以所经常被搜索引擎系统用于文本词频统计。其核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 - +### 1.2、基本性质 +1. 结点本身不存完整单词; +2. 从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的字符串; +3. 每个结点的所有子结点路径代表的字符都不相同。 +## 2、并查集 +### 2.1、基本操作 +1. makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合 +2. unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所的集合不相交,如果相交则不合并。 +3. find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。 + +## 3、高级搜索 +### 3.1、初级搜索 +1. 优化方式:不重复(fibonacci)、剪枝(生成括号问题) +2. 搜索方向: +DFS: depth first search 深度优先搜索 +BFS: breadth first search 广度优先搜索 + +### 3.2 高级搜索 +双向搜索、启发式搜索 + +## 3、AVL树与红黑树 +### 3.1 AVL树 +1. 平衡二叉搜索树 +2. 每个结点存 balance factor = {-1, 0, 1} +3. 四种旋转操作 + +不足:结点需要存储额外信息、且调整次数频繁 + +### 3.2、红黑树 +红黑树是一种近似平衡的二叉搜索树(Binary Search Tree),它能够确保任何一个结点的左右子树的高度差小于两倍。具体来说,红黑树是满足如下条件的二叉搜 +索树: +1. 每个结点要么是红色,要么是黑色 +2. 根节点是黑色 +3. 每个叶节点(NIL节点,空节点)是黑色的。 +4. 不能有相邻接的两个红色节点 +5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。 + +### 3.3 对比 +1. AVL树有更快的查找性能,因为其比红黑树更平衡。 +2. 红黑树有更好的插入、删除性能,因为其实近似平衡树。 +3. AVL需要存储更多的额外一个整型的信息,而红黑树只需要额外多存储一个bit。 diff --git a/Week 06/id_596/LeetCode_127_596.py b/Week 06/id_596/LeetCode_127_596.py new file mode 100644 index 000000000..1488a2cf1 --- /dev/null +++ b/Week 06/id_596/LeetCode_127_596.py @@ -0,0 +1,26 @@ + +from collections import deque + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if endWord not in wordList: return 0 + wordList = set(wordList) + + res, forward, backword = 2, {beginWord}, {endWord} + while forward: + if len(forward) > len(backword): + forward, backword = backword, forward + + next_forward = set() + for word in forward: + for i in range(len(word)): + for k in range(26): + tmp = word[:i] + chr(ord("a") + k) + word[i + 1:] + if tmp in backword: + return res + if tmp in wordList: + next_forward.add(tmp) + wordList.remove(tmp) + res += 1 + forward = next_forward + return 0 \ No newline at end of file diff --git a/Week 06/id_596/LeetCode_208_596.py b/Week 06/id_596/LeetCode_208_596.py new file mode 100644 index 000000000..18a7c7e06 --- /dev/null +++ b/Week 06/id_596/LeetCode_208_596.py @@ -0,0 +1,50 @@ +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.lookup = {} + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + tree = self.lookup + for ch in word: + if ch not in tree: + tree[ch] = {} + tree = tree[ch] + tree["#"] = "#" + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + tree = self.lookup + for ch in word: + if ch not in tree: + return False + tree = tree[ch] + if "#" in tree: + return True + return False + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + tree = self.lookup + for ch in prefix: + if ch not in tree: + return False + tree = tree[ch] + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week 06/id_596/NOTE.md b/Week 06/id_596/NOTE.md index a6321d6e2..0b210ec6f 100644 --- a/Week 06/id_596/NOTE.md +++ b/Week 06/id_596/NOTE.md @@ -1,4 +1,137 @@ # NOTE - +## 学习笔记 +## 字典树 Tire + +### 字典树的基本结构 + +字典树,即Trie树,又称单词查找树或者建树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。 +它的优点是:最大限度的减少无谓的字符串比较,查询效率比哈希表高。 + +### 字典树的基本性质 + +1. 节点本身不存完整单词 +2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串 +3. 每个节点的所有子节点路径代表的字符都不相同 + +### 核心思想 + +Trie树的核心思想是空间换时间 + +利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的 + +### 实现 + +```python +class Trie(object): + def _init_(self): + self.root = {} + self.end_of_word = "#" + + def insert(self, word): + node = self.root + for char in word: + node = node.setdefault(char, {}) # 有值则取值没值赋值{} + node[self.end_of_word] = self.end_of_word + + def search(self,word): + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self,prefix): + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True +``` + +## 高级搜索 + +### 回溯法 + +回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其他的可能的分步解答再次尝试寻找问题的答案。 + +回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: + +- 找到一个可能存在的正确答案 +- 再尝试了所有可能的分步方法后宣告问题没有答案 + +在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。 + +### 双向BFS + +从图的开始和结束节点同时向中间扩散,在中间相遇即为搜索到了。 + +### 启发式搜索(A* search) + +代码模版 + +```python +def AstarSearch(graph,start,end): + pq = collections.priority_queue() # 优先级队列 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() # can we add more intelligence here? + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` + +### 估价函数 + +启发式函数:h(n),它用来评价那些节点最有希望的是一个我们要找的节点,h(n)会返回一个非负实数,也可以认为是从节点n的目标节点路径的估计成本。 + +启发式函数是一种告知搜索方向的方法。它提供了一种明智的方法来猜测哪个邻居节点会导向一个目标。 + +## AVL树和红黑树 + +### AVL树 + +1. 发明者G.M.Adelson-Velsky和Evgenii Landis +2. Balance Factor(平衡因子): + + 是它的左子树的高度减去它右子树的高度(有时相反)。 + + balance factor = {-1,0,1} +3. 通过旋转操作来进行平衡(四种) + +#### 旋转操作 + +1. 左旋 +2. 右旋 +3. 左右旋 +4. 右左旋 + +#### AVL总结 + +1. 平衡二叉搜索树 +2. 每个节点存balance factor = {-1, 0 ,1 } +3. 四种旋转操作 + +不足:节点需要存储额外信息、且调整次数频繁 + +### 红黑树(Red-black Tree) + +红黑树是一种近似平衡的二叉搜索树(Binary Search Tree),它能够确保任何一个节点的左右子树的高度差小于两倍。具体来说,红黑树是满足如下条件的二叉搜索树: + +- 每个节点要么是红色,要么是黑色 +- 根节点是黑色 +- 每个叶节点(NIL节点,空节点是黑色的) +- 不能有相邻的两个红色节点 +- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。 + +#### 关键性质 + +从根到叶子的最长的可能路径不多于最短可能路径的两倍长。 \ No newline at end of file diff --git a/Week 06/id_601/LeetCode_1091_601.java b/Week 06/id_601/LeetCode_1091_601.java new file mode 100644 index 000000000..496fe48d5 --- /dev/null +++ b/Week 06/id_601/LeetCode_1091_601.java @@ -0,0 +1,50 @@ +class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + if(grid[0][0]!=0 || grid[grid.length-1][grid[0].length-1]!=0 ) return -1; + + Queue q=new LinkedList<>(); + q.add(new int[]{0,0}); + int[][] dir={{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,-1},{-1,1},{1,-1}}; + + int path=1; + int xlen=grid.length; + int ylen=grid[0].length; + int len=q.size(); + grid[0][0]=1; + int c=0; + + while(!q.isEmpty()){ + + int[] data=q.poll(); + + int x=data[0]; + int y=data[1]; + + if(x==grid.length-1 && y==grid[0].length-1) return path; + + + for(int[] dat:dir){ + int x1=x+dat[0]; + int y1=y+dat[1]; + if(x1=0 && y1=0 && grid[x1][y1]==0){ + q.add(new int[]{x1,y1}); + grid[x1][y1]=1; + } + } + + + c++; + if(c==len){ + c=0; + path++; + len=q.size(); + + } + + + + } + + return -1; + } +} diff --git a/Week 06/id_601/LeetCode_130_601.java b/Week 06/id_601/LeetCode_130_601.java new file mode 100644 index 000000000..dd463260f --- /dev/null +++ b/Week 06/id_601/LeetCode_130_601.java @@ -0,0 +1,38 @@ +class Solution { + int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; //下,上,右,左 + public void solve(char[][] board) { + if (board == null || board.length == 0 || board[0] == null || board[0].length == 0) return; + int row = board.length; + int col = board[0].length; + for (int j = 0; j < col; j++) { + // 第一行 + if (board[0][j] == 'O') dfs(0, j, board, row, col); + // 最后一行 + if (board[row - 1][j] == 'O') dfs(row - 1, j, board, row, col); + } + + for (int i = 0; i < row; i++) { + // 第一列 + if (board[i][0] == 'O') dfs(i, 0, board, row, col); + // 最后一列 + if (board[i][col - 1] == 'O') dfs(i, col - 1, board, row, col); + } + + // 转变 + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (board[i][j] == 'O') board[i][j] = 'X'; + if (board[i][j] == 'B') board[i][j] = 'O'; + } + } + } + private void dfs(int i, int j, char[][] board, int row, int col) { + board[i][j] = 'B'; + for (int[] dir : dirs) { + int tmp_i = dir[0] + i; + int tmp_j = dir[1] + j; + if (tmp_i < 0 || tmp_i >= row || tmp_j < 0 || tmp_j >= col || board[tmp_i][tmp_j] != 'O') continue; + dfs(tmp_i, tmp_j, board, row, col); + } + } +} diff --git "a/Week 06/id_606/127.\345\215\225\350\257\215\346\216\245\351\276\231.java" "b/Week 06/id_606/127.\345\215\225\350\257\215\346\216\245\351\276\231.java" new file mode 100644 index 000000000..725b17039 --- /dev/null +++ "b/Week 06/id_606/127.\345\215\225\350\257\215\346\216\245\351\276\231.java" @@ -0,0 +1,111 @@ +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + * + * https://leetcode-cn.com/problems/word-ladder/description/ + * + * algorithms + * Medium (37.11%) + * Likes: 153 + * Dislikes: 0 + * Total Accepted: 13.7K + * Total Submissions: 36.3K + * Testcase Example: '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]' + * + * 给定两个单词(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" 不在字典中,所以无法进行转换。 + * + */ + +// @lc code=start +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set beginSet = new HashSet(), endSet = new HashSet(); + + int len = 1; + HashSet visited = new HashSet(); + + beginSet.add(beginWord); + endSet.add(endWord); + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + if (beginSet.size() > endSet.size()) { + Set set = beginSet; + beginSet = endSet; + endSet = set; + } + + Set temp = new HashSet(); + for (String word : beginSet) { + char[] chs = word.toCharArray(); + + for (int i = 0; i < chs.length; i++) { + for (char c = 'a'; c <= 'z'; c++) { + char old = chs[i]; + chs[i] = c; + String target = String.valueOf(chs); + + if (endSet.contains(target)) { + return len + 1; + } + + if (!visited.contains(target) && wordList.contains(target)) { + temp.add(target); + visited.add(target); + } + chs[i] = old; + } + } + } + + beginSet = temp; + len++; + } + + return 0; + } +} +// @lc code=end diff --git "a/Week 06/id_606/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" "b/Week 06/id_606/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" new file mode 100644 index 000000000..3725ae2a4 --- /dev/null +++ "b/Week 06/id_606/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" @@ -0,0 +1,113 @@ +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + * + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (62.45%) + * Likes: 151 + * Dislikes: 0 + * Total Accepted: 17.1K + * Total Submissions: 27.3K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * 实现一个 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 构成的。 + * 保证所有输入均为非空字符串。 + * + * + */ + +// @lc code=start +class Trie { + public boolean isWord; + public char word; + public Trie[] tries = new Trie[26]; + + /** Initialize your data structure here. */ + public Trie() { + this.isWord = false; + this.word = ' '; + + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] == null) { + node.tries[array[i] - 'a'] = new Trie(); + } + node = node.tries[array[i] - 'a']; + node.word = array[i]; + if (i == array.length - 1) { + node.isWord = true; + } + } + + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return node.isWord == true ? true : false; + + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + char[] array = prefix.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return true; + } +} + +/** + * 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); + */ +// @lc code=end diff --git a/Week 06/id_611/LeetCode_208_611.java b/Week 06/id_611/LeetCode_208_611.java new file mode 100644 index 000000000..ece663688 --- /dev/null +++ b/Week 06/id_611/LeetCode_208_611.java @@ -0,0 +1,75 @@ +class Trie { + TreeNode root; + /** Initialize your data structure here. */ + public Trie() { + root = new TreeNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TreeNode node = root; + for( int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(!node.containsKey(c)) + node.put(c, new TreeNode()); + node = node.get(c); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TreeNode treeNode = searchPrefix(word); + return treeNode != null && treeNode.isEnd(); + } + + public TreeNode searchPrefix(String word){ + TreeNode node = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(node.containsKey(c)) + node = node.get(c); + else + return null; + } + return node; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + return searchPrefix(prefix) != null; + } +} + +class TreeNode{ + private int size = 26; + private TreeNode children []; + private boolean isEnd = false; + + public TreeNode(){ + children = new TreeNode[size]; + } + //判断是否有对应字符串 + public boolean containsKey(char key){ + return children[key - 'a'] != null; + } + + //查询子树 + public TreeNode get(char key){ + return children[key - 'a']; + } + + //插入子树 + public void put(char key,TreeNode sub){ + children[key-'a'] = sub; + } + + //设为结束点 + public void setEnd(){ + isEnd = true; + } + + public boolean isEnd(){ + return isEnd; + } +} \ No newline at end of file diff --git a/Week 06/id_611/LeetCode_212_611.java b/Week 06/id_611/LeetCode_212_611.java new file mode 100644 index 000000000..9b713b5e4 --- /dev/null +++ b/Week 06/id_611/LeetCode_212_611.java @@ -0,0 +1,136 @@ +import java.util.ArrayList; +import java.util.HashSet; + +/* + * @lc app=leetcode.cn id=212 lang=java + * + * [212] 单词搜索 II + */ + +// @lc code=start +class Solution { + private HashSet set = new HashSet<>(); + private boolean[][] meno; + private Trie trie; + + public List findWords(char[][] board, String[] words) { + meno = new boolean[board.length][]; + trie = new Trie(); + + //初始化备忘录 + for(int i = 0; i < board.length; i++){ + meno[i] = new boolean[board[i].length]; + } + + //生成字典树 + for(int i = 0; i < words.length; i++){ + trie.insert(words[i]); + } + + //dfs查找 + for(int row = 0; row < board.length; row++){ + for(int col = 0; col < board[row].length; col++){ + dfs(board, row, col, "", trie); + } + } + return new ArrayList<>(set); + } + + public void dfs(char[][] board, int row, int col, String str, Trie trie){ + //终止条件 + if(row < 0 || col <0 || row >= board.length || col >= board[row].length || meno[row][col] ) + return; + + str += board[row][col]; + //匹配到前缀字符串 + if(!trie.startWith(str)) + return; + + meno[row][col] = true; + if(trie.search(str)) + set.add(str); + + //上下左右查找匹配路径 + dfs(board, row - 1, col, str, trie); + dfs(board, row + 1, col, str, trie); + dfs(board, row, col - 1, str, trie); + dfs(board, row, col + 1, str, trie); + meno[row][col] = false; + } + +} + +class TreeNode{ + private final int SIZE = 26; + private TreeNode children []; + private boolean isEnd = false; + + public TreeNode(){ + children = new TreeNode[SIZE]; + } + //判断是否有对应字符串 + public boolean containsKey(char key){ + return children[key - 'a'] != null; + } + + //查询子树 + public TreeNode get(char key){ + return children[key - 'a']; + } + + //插入子树 + public void put(char key,TreeNode sub){ + children[key-'a'] = sub; + } + + //设为结束点 + public void setEnd(){ + isEnd = true; + } + + public boolean isEnd(){ + return isEnd; + } + +} + +class Trie{ + TreeNode root; + public Trie(){ + root = new TreeNode(); + } + + public void insert(String word){ + TreeNode node = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(!node.containsKey(c)){ + node.put(c, new TreeNode()); + } + node = node.get(c); + } + node.setEnd(); + } + + //抽象出查找前缀的公有方法 + private TreeNode searchPrefix(String word){ + TreeNode node = root; + for(int i = 0; i < word.length(); i++){ + char c = word.charAt(i); + if(!node.containsKey(c)){ + return null; + } + node = node.get(c); + } + return node; + } + + public boolean search(String word){ + TreeNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + public boolean startWith(String prefix){ + return searchPrefix(prefix) != null; + } +} \ No newline at end of file diff --git a/Week 06/id_611/LeetCode_433_611.java b/Week 06/id_611/LeetCode_433_611.java new file mode 100644 index 000000000..1affb043b --- /dev/null +++ b/Week 06/id_611/LeetCode_433_611.java @@ -0,0 +1,60 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +/* + * @lc app=leetcode.cn id=433 lang=java + * + * [433] 最小基因变化 + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + String start = "AACCGGTT"; + String end = "AACCGGTA"; + String[] bank = new String[]{"AACCGGTA","AACCGGTC"}; + minMutation(start, end, bank); + + + } + + public static int minMutation(String start, String end, String[] bank) { + if(start.equals(end)) return 0; + Set bankSet = new HashSet<>(); + for(String b :bank) bankSet.add(b); + + char[] chars = new char[]{'A','C','G','T'}; + int level = 0; + Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + visited.add(start); + queue.offer(start); + + while(!queue.isEmpty()){ + int size = queue.size(); + while(size-- > 0){ + String cur = queue.poll(); + if(cur.equals(end)) return level; + + char[] charArr = cur.toCharArray(); + for(int i = 0; i < charArr.length; i++){ + char old = charArr[i]; + for(int c =0; c < chars.length; c++){ + charArr[i] = chars[c]; + String next = new String(charArr); + if(!visited.contains(next) && bankSet.contains(next)){ + visited.add(next); + queue.offer(next); + } + } + charArr[i] = old; + } + } + level++; + } + return -1; + } +} \ No newline at end of file diff --git a/Week 06/id_616/LeetCode_1091_616.cpp b/Week 06/id_616/LeetCode_1091_616.cpp new file mode 100644 index 000000000..6d151c6e5 --- /dev/null +++ b/Week 06/id_616/LeetCode_1091_616.cpp @@ -0,0 +1,43 @@ +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + rows = grid.size(); + cols = grid[0].size(); + + if(grid[0][0] || grid[rows-1][cols-1]) return -1; + + queue que; + que.push(new Node(0,0,1)); + while(que.size()){ + auto now = que.front(); + que.pop(); + if(now->x == rows-1 && now->y == cols-1) return now->step; + for(int i = 0; i < 8; ++i){ + int nx = now->x + dir[i][0]; + int ny = now->y + dir[i][1]; + if(nx < 0 || nx >= rows || ny < 0 || ny >= cols || grid[nx][ny]) + continue; + que.push(new Node(nx, ny, now->step+1)); + grid[nx][ny] = 1; + } + } + return -1; + } +private: + struct Node{ + int x, y; + int step; + Node(int _x, int _y, int _s):x(_x),y(_y),step(_s){} + }; + int rows, cols; + int dir[8][2] = { + {0,1}, + {1,1}, + {1,0}, + {1,-1}, + {-1,0}, + {-1,-1}, + {0,-1}, + {-1,1} + }; +}; \ No newline at end of file diff --git a/Week 06/id_616/LeetCode_208_616.cpp b/Week 06/id_616/LeetCode_208_616.cpp new file mode 100644 index 000000000..12a3986ee --- /dev/null +++ b/Week 06/id_616/LeetCode_208_616.cpp @@ -0,0 +1,74 @@ +class TrieNode { +public: + TrieNode() { + for(auto &&i : childrens_){ + i = nullptr; + } + } + + TrieNode *insert(char c) { + if(childrens_[c-'a'] != nullptr) return childrens_[c-'a']; + + TrieNode *t = new TrieNode(); + childrens_[c-'a'] = t; + return t; + } + + TrieNode *search(char c) { + return childrens_[c-'a']; + } + + void setEnd() {is_end_ = true;} + bool isEnd() {return is_end_;} +private: + TrieNode *childrens_[26]; + bool is_end_ = false; +}; + +class Trie { +public: + /** Initialize your data structure here. */ + Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + TrieNode *t = root; + for(auto &c : word){ + t = t->insert(c); + } + t->setEnd(); + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + TrieNode *t = root; + for(auto &c : word){ + t = t->search(c); + if(t == nullptr) return false; + } + return t->isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + TrieNode *t = root; + for(auto &c : prefix){ + t = t->search(c); + if(t == nullptr) return false; + } + return true; + } + +private: + TrieNode *root; +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ \ No newline at end of file diff --git a/Week 06/id_616/LeetCode_547_616.cpp b/Week 06/id_616/LeetCode_547_616.cpp new file mode 100644 index 000000000..dca2c2695 --- /dev/null +++ b/Week 06/id_616/LeetCode_547_616.cpp @@ -0,0 +1,51 @@ +class DisjSet +{ +private: + std::vector parent; + +public: + DisjSet(int size) : parent(std::vector(size)) + { + for (int i = 0; i < size; ++i) + parent[i] = i; + } + + int find(int x) + { + return parent[x] == x ? x : find(parent[x]); + } + + void to_union(int x1, int x2) + { + parent[find(x1)] = find(x2); + } + + bool is_same(int e1, int e2) + { + return find(e1) == find(e2); + } +}; + +class Solution { +public: + int findCircleNum(vector>& M) { + int N = M.size(); + if( N == 0 ) return 0; + + int cnt = N; + + DisjSet disj_set(N); + + for(int i = 0; i < N; i++){ + for(int j = 0; j < N; j++){ + if(M[i][j] == 1){ + if(!disj_set.is_same(i,j)){ + disj_set.to_union(i,j); + cnt--; + } + } + } + } + return cnt; + } +}; \ No newline at end of file diff --git a/Week 06/id_616/NOTE.md b/Week 06/id_616/NOTE.md index a6321d6e2..c3e7a7df5 100644 --- a/Week 06/id_616/NOTE.md +++ b/Week 06/id_616/NOTE.md @@ -1,4 +1,71 @@ -# NOTE +# 学习总结 - +## 字典树(Trie) +核心思想是利用字符串的公共前缀来降低时间开销,达到空间换时间的效率提升。 + +字典树的特征: + +- 节点不会存完整单词,而是字符 +- 从根节点到某一节点,路径上经过的字符连接起来为该节点对应的字符串 +- 每个节点的所有子节点路径代表的字符都不相同 + +## 并查集(DisjointSet/UnionFind) + +一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题,比如组团和配对问题。 + +实现并查集需要实现的三种操作: + +- makeSet(s) +- unionSet(x,y) +- find(x) + +## 高级搜索的三种优化 + +### 剪枝 + +在朴素搜索的基础上,减少重复计算,或根据条件剪枝,尽早排除不可能的分支 + +### 双向BFS(Two-ended) + +起点终点分别BFS,直到相遇 + +### 启发式搜索(A*算法) + +根据问题特定的条件,使用优先队列代替BFS队列,优先扩散优先级高的,来引导搜索方向从而加速搜索过程 +启发式估价函数: h(n),根据问题特点,评价节点是否是所希望的解的可能性 +如果简单以先入先出顺序为估价函数,则退化为简单BFS + +## 二叉搜索树(Binary Search Tree) + +定义:左子树的所有节点都小于根节点,右子树所有节点都小于根节点 +查找效率和高度有关,即O(logn) +树和链表没有本质区别。二叉搜索树的极端情况:始终插入在一边,则会退化成链表,查找复杂度为O(n) +因此,为保证性能,需要维持BST的平衡性和二维维度,故引入平衡二叉树(有很多形式,比如AVL、红黑树、2-3树和B+树) + +### AVL树 + +定义:平衡因子(balance factor)= 每个节点的左右子树高度差,最好保持在{-1, 0, 1}之间 +通过旋转来进行平衡: + +- 左旋 +- 右旋 +- 左右旋 +- 右左旋 + +### 红黑树(Red-Black Tree) + +一种近似平衡二叉树,确保任何一个节点左右子树的高度差小于两倍,具有以下特点: + +- 每个节点要么是红色,要么是黑色 +- 根节点是黑色 +- 叶节点/空节点是黑色 +- 红色节点不能相邻 +- 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点 + +### 比较 + +AVL因为更严格平衡,故查找性能更好 +RBT的添加和删除更快,因为需要维护的旋转操作更少 +AVL需要存储factor,RBT只需要一个bit来存Red或Black的状态,因此存储空间更少 +读操作多写操作少时用AVL(比如Database),否则用RBT(比如Map/Set的实现) \ No newline at end of file diff --git a/Week 06/id_631/LeetCode_127_631.go b/Week 06/id_631/LeetCode_127_631.go new file mode 100644 index 000000000..e96b14257 --- /dev/null +++ b/Week 06/id_631/LeetCode_127_631.go @@ -0,0 +1,47 @@ +func ladderLength(beginWord string, endWord string, wordList []string) int { + flag := false + for _, word := range wordList { + if word == endWord { + flag = true + break + } + } + if !flag { + return 0 + } + + // 2. 预处理+bfs, 40ms + visitedMap := make(map[string]bool) + preMap := make(map[string][]string) // 预处理结果map + queue := []string{beginWord} + count := 0 + wordLen := len(beginWord) + + for _, word := range wordList { // 预处理 + for i := 0; i < wordLen; i++ { + key := word[:i] + "*" + word[i+1:] + preMap[key] = append(preMap[key], word) + } + } + + for len(queue) > 0 { + count++ + newQueue := make([]string, 0) + for _, item := range queue { + for i := 0; i < wordLen; i++ { + key := item[:i] + "*" + item[i+1:] + for _, word := range preMap[key] { + if word == endWord { + return count + 1 + } + if !visitedMap[word] { + visitedMap[word] = true + newQueue = append(newQueue, word) + } + } + } + } + queue = newQueue + } + return 0 +} \ No newline at end of file diff --git a/Week 06/id_631/LeetCode_208_631.go b/Week 06/id_631/LeetCode_208_631.go new file mode 100644 index 000000000..93ee20e3f --- /dev/null +++ b/Week 06/id_631/LeetCode_208_631.go @@ -0,0 +1,90 @@ +type Trie struct { + root *Node +} + +type Node struct { + value int32 + children []*Node + isComplete bool +} + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{ + root: &Node{ + children: make([]*Node, 0), + }, + } +} + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + node := this.root + wLen := len(word) + for i, w := range word { + var childrenRoot *Node + nodes := node.children + for _, n := range nodes { + if n.value == w { + childrenRoot = n + break + } + } + if childrenRoot == nil { + childrenRoot = &Node{value: w, children: make([]*Node, 0)} + node.children = append(node.children, childrenRoot) + } + if i == wLen-1 { + childrenRoot.isComplete = true + } + node = childrenRoot + } +} + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + node := this.root + wLen := len(word) + for i, w := range word { + var childrenRoot *Node + nodes := node.children + for i, n := range nodes { + if n.value == w { + childrenRoot = nodes[i] + break + } + } + if childrenRoot == nil { + return false + } + if i == wLen-1 && childrenRoot.isComplete { + return true + } + node = childrenRoot + } + return false +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + node := this.root + wLen := len(prefix) + for i, w := range prefix { + var childrenRoot *Node + nodes := node.children + for i, n := range nodes { + if n.value == w { + childrenRoot = nodes[i] + break + } + } + if childrenRoot == nil { + return false + } + if i == wLen - 1 { + return true + } + node = childrenRoot + } + return false +} \ No newline at end of file diff --git a/Week 06/id_631/NOTE.md b/Week 06/id_631/NOTE.md index a6321d6e2..fc1611085 100644 --- a/Week 06/id_631/NOTE.md +++ b/Week 06/id_631/NOTE.md @@ -1,4 +1,60 @@ # NOTE +单词搜索 2 用 Tire 树方式实现的时间复杂度是O(n*k) (k表示单词的平均长度) + +双向BFS模板 +```python +#!/usr/bin/env python3 +def BFS(graph,start,end): + start_queue = [] + end_queue = [] + start_queue.append([start]) + end_queue.append([end]) + while start_queue: + node = start_queue.pop() + visited.add(node) + + process(node) + + nodes = generate_related_nodes(node) + queue.push(nodes) + if (len(start_queue) > len(end_queue)): + start_queue,end_queue = end_queue,start_queue + ... +``` + +1. 字典树和并查集 + 1. 字典树 Trie + 1. 基本结构:字典树,即 Trie 树,又称单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎用于文本词频统计。优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高 + 2. 基本性质: + 1. 节点本身不存完整单词 + 2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串 + 3. 每个节点的所有子节点路径代表的字符都不相同 + 2. 并查集 Union-Find + 1. 并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题 + 2. 使用场景:组团, 配对问题 + +2. 高级搜索 + 1. 剪枝 + 1. 将复杂的决策树进行简化的过程称为剪枝,目的是去掉一些节点,包括叶节点和中间节点 + 2. 双向 BFS (Two-ended Breadth First Search) + 1. 如果已经知道搜索的开始状态和结束状态,要找一个满足某种条件的一条路径(常见是最短路径),为了避免无谓的“组合爆炸”产生,就可以采取双向广度优先搜索,也就是从开始状态和结束状态同时开始搜索,一个向前,一个向后 + 3. 启发式搜索/优先级搜索 Heuuristic Search(A*) + 1. 利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的 +3. 红黑树和AVL树 + 1. 平衡二叉搜索树 + 1. 保证性能的关键是左右子树节点平衡, 保证二叉搜索树的查询速度只与节点高度相关, 和节点数无关 + 2. AVL树 + 1. 自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1 + 3. 红黑树 Red-black tree + 1. 红黑树是一种近乎平衡的二叉搜索树,它能够确保任何一个节点的左右子树的高度差小于两倍。具体来说,红黑树是满足如下条件的二叉搜索树 + 2. 每个节点要么是红色,要么是黑色, 根节点是黑色, 每个叶节点(空节点)是黑色的 + 3. 不能有相邻接的两个红色节点 + 4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点 + 4. 对比 + 1. AVL树查询比红黑树更快,因为AVL树是更加严格的平衡 + 2. 红黑树插入和删除比AVL树更快, 因为AVL树的旋转操作会更多 + 3. AVL树要在每个节点存额外的信息(平衡因素和高度),红黑树只要一个bit来存0,1表示黑或红 + 4. 查询操作多推荐用AVL树,否则选择红黑树 \ No newline at end of file diff --git a/Week 06/id_641/lesson13/LeetCode_200_641.java b/Week 06/id_641/lesson13/LeetCode_200_641.java new file mode 100644 index 000000000..6baee13ff --- /dev/null +++ b/Week 06/id_641/lesson13/LeetCode_200_641.java @@ -0,0 +1,83 @@ +package com.code.lesson13; + + +/** + * 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + * + * 链接:https://leetcode-cn.com/problems/number-of-islands + */ +public class LeetCode_200_641 { + + + class UnionFind { + + int count; + + int[] parent; + + public UnionFind(char[][] grid) { + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + } + } + } + + public int find(int i) { + if (parent[i] != i) { + parent[i] = find(parent[i]); + } + return parent[i]; + } + + public void union(int x, int y) { + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + parent[rootx] = rooty; + --count; + } + } + + public int getCount() { + return count; + } + } + + //并查集 + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int total = 0, row = grid.length, col = grid[0].length; + UnionFind uf = new UnionFind(grid); + for (int i = 0; i < row; ++i) { + for (int j = 0; j < col; ++j) { + if (grid[i][j] == '1') { + grid[i][j] = '0'; + int old = i * col + j; + if (i - 1 >= 0 && grid[i - 1][j] == '1') { + uf.union(old, (i - 1) * col + j); + } + if (i + 1 < row && grid[i + 1][j] == '1') { + uf.union(old, (i + 1) * col + j); + } + if (j - 1 >= 0 && grid[i][j - 1] == '1') { + uf.union(old, i * col + j - 1); + } + if (j + 1 < col && grid[i][j + 1] == '1') { + uf.union(old, i * col + j + 1); + } + } + } + } + return uf.getCount(); + } +} diff --git a/Week 06/id_641/lesson13/LeetCode_537_641.java b/Week 06/id_641/lesson13/LeetCode_537_641.java new file mode 100644 index 000000000..fcf254330 --- /dev/null +++ b/Week 06/id_641/lesson13/LeetCode_537_641.java @@ -0,0 +1,61 @@ +package com.code.lesson13; + + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 链接:https://leetcode-cn.com/problems/friend-circles + */ +public class LeetCode_537_641 { + + + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) {//没有访问 + dfs(M, visited, i); + count++; + } + } + return count; + } + + //深度优先遍历 + private void dfs(final int[][] M, final int[] visited, final int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) {//没有访问过,连通的 + visited[j] = 1; + dfs(M, visited, j);//横竖遍历 + } + } + } + + //广度优先遍历 + public int findCircleNum2(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + Queue queue = new LinkedList<>(); + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) {//没有访问过 + queue.add(i); + while (!queue.isEmpty()) { + int s = queue.remove(); + visited[s] = 1; + for (int j = 0; j < M.length; j++) { + if (M[s][j] == 1 && visited[j] == 0) { + queue.add(j); + } + } + } + count++; + } + } + return count; + } +} diff --git a/Week 06/id_641/lesson14/LeetCode_1091_641.java b/Week 06/id_641/lesson14/LeetCode_1091_641.java new file mode 100644 index 000000000..a9aa67b8c --- /dev/null +++ b/Week 06/id_641/lesson14/LeetCode_1091_641.java @@ -0,0 +1,119 @@ +package com.code.lesson14; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。 + * + * 一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k 组成: + * + * 相邻单元格 C_i 和 C_{i+1} 在八个方向之一上连通(此时,C_i 和 C_{i+1} 不同且共享边或角) + * C_1 位于 (0, 0)(即,值为 grid[0][0]) + * C_k 位于 (N-1, N-1)(即,值为 grid[N-1][N-1]) + * 如果 C_i 位于 (r, c),则 grid[r][c] 为空(即,grid[r][c] == 0) + * 返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。 + * + * 链接:https://leetcode-cn.com/problems/shortest-path-in-binary-matrix + */ +public class LeetCode_1091_641 { + + //方向 + private static final int[][] direct = new int[][]{ + {-1, 0}, //左 + {1, 0},// 右 + {0, -1},//上 + {0, 1},// 下 + {1, 1}, + {-1, 1}, + {1, -1}, + {-1, -1}, + }; + + + //最短路径 + public int shortestPathBinaryMatrix(int[][] grid) { + if (grid.length == 0) { + return -1; + } + + if (grid.length == 1) { + return grid[0][0] == 0 ? 1 : -1; + } + + final int N = grid.length; + + if ((grid[0][0] == 1) || (grid[N - 1][N - 1] == 1)) {//如果入口和出口都不能访问 + return -1; + } + + List startSta = new ArrayList<>(N * N); + List endSta = new ArrayList<>(N * N); + startSta.add(new State(0, 0)); + endSta.add(new State(N - 1, N - 1)); + + boolean[][] visited = new boolean[N][N]; + visited[0][0] = true; + visited[N - 1][N - 1] = true; + + boolean[][] startVisited = new boolean[N][N]; + boolean[][] endVisited = new boolean[N][N]; + startVisited[0][0] = true; + endVisited[N - 1][N - 1] = true; + + int len = 1; + + while (!startSta.isEmpty() && !endSta.isEmpty()) { + + if (startSta.size() > endSta.size()) { + List tmp = startSta; + startSta = endSta; + endSta = tmp; + boolean[][] tmpA = startVisited; + startVisited = endVisited; + endVisited = tmpA; + } + + List newStaSet = new ArrayList<>(); + for (State curSta : startSta) { + int i = curSta.i, j = curSta.j; + for (int[] pos : direct) { + int new_i = i + pos[0], new_j = j + pos[1]; + if (new_i >= 0 && new_i < N && new_j >= 0 && new_j < N && grid[new_i][new_j] == 0) { + State newSta = new State(new_i, new_j); + + if (endVisited[newSta.i][newSta.j]) { + return len + 1; + } + + if (visited[newSta.i][newSta.j]) { + continue; + } + + newStaSet.add(newSta); + visited[newSta.i][newSta.j] = true; + startVisited[newSta.i][newSta.j] = true; + } + } + } + + startSta = newStaSet; + len++; + } + return -1; + } + + private class State { + + int i; + + int j; + + public State(int i, int j) { + this.i = i; + this.j = j; + } + } + +} diff --git a/Week 06/id_641/lesson14/LeetCode_37_641.java b/Week 06/id_641/lesson14/LeetCode_37_641.java new file mode 100644 index 000000000..59a6788e7 --- /dev/null +++ b/Week 06/id_641/lesson14/LeetCode_37_641.java @@ -0,0 +1,64 @@ +package com.code.lesson14; + +/** + * https://leetcode-cn.com/problems/sudoku-solver/ + */ +public class LeetCode_37_641 { + + public void solveSudoku(char[][] board) { + // 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过 + boolean[][] rowUsed = new boolean[9][10]; + boolean[][] colUsed = new boolean[9][10]; + boolean[][][] boxUsed = new boolean[3][3][9]; + // 初始化 + for (int row = 0; row < board.length; row++) { + for (int col = 0; col < board[0].length; col++) { + int num = board[row][col] - '0'; + if (1 <= num && num <= 9) { + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row / 3][col / 3][num - 1] = true; + } + } + } + // 递归尝试填充数组 + recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, 0, 0); + } + + private boolean recusiveSolveSudoku(char[][] board, boolean[][] rowUsed, boolean[][] colUsed, + boolean[][][] boxUsed, int row, int col) { + // 边界校验, 如果已经填充完成, 返回true, 表示一切结束 + if (col == board[0].length) { + col = 0; + row++; + if (row == board.length) { + return true; + } + } + // 是空则尝试填充, 否则跳过继续尝试填充下一个位置 + if (board[row][col] == '.') { + // 尝试填充1~9 + for (int num = 1; num <= 9; num++) { + boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || boxUsed[row / 3][col / 3][num - 1]); + if (canUsed) { + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row / 3][col / 3][num - 1] = true; + + board[row][col] = (char) ('0' + num); + if (recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1)) { + return true; + } + board[row][col] = '.'; + + rowUsed[row][num] = false; + colUsed[col][num] = false; + boxUsed[row / 3][col / 3][num - 1] = false; + } + } + } else { + return recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1); + } + return false; + } +} diff --git "a/Week 06/id_646/\345\262\233\345\261\277\346\225\260\351\207\217.md" "b/Week 06/id_646/\345\262\233\345\261\277\346\225\260\351\207\217.md" new file mode 100644 index 000000000..2b0786a3b --- /dev/null +++ "b/Week 06/id_646/\345\262\233\345\261\277\346\225\260\351\207\217.md" @@ -0,0 +1,34 @@ +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + if (grid.length === 0 || grid[0].length === 0) { + return 0 + } + let count = 0 + for (let i = 0, len = grid.length; i < len; i ++) { + for(let j = 0, len = grid[0].length; j < len; j ++) { + if(grid[i][j] != 0) { + count ++ + findIslandSlibings(i, j) + } + } + } + function findIslandSlibings (i, j) { + grid[i][j] = 0 // 先拿掉当前的岛屿 + if(grid[i][j + 1] == 1) { + findIslandSlibings(i, j + 1) + } + if(grid[i][j - 1] == 1) { + findIslandSlibings(i, j - 1) + } + if(grid[i - 1] && grid[i - 1][j] == 1) { + findIslandSlibings(i - 1, j) + } + if(grid[i + 1] && grid[i + 1][j] == 1) { + findIslandSlibings(i + 1, j) + } + } + return count +}; diff --git "a/Week 06/id_646/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.md" "b/Week 06/id_646/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.md" new file mode 100644 index 000000000..6f9db6c32 --- /dev/null +++ "b/Week 06/id_646/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.md" @@ -0,0 +1,35 @@ +```js +var solve = function(board) { + let m = board.length; + if(m == 0){return}; + let n = board[0].length; + let cannot = {}; + let dfs = (i,j) => { + // 越界、标示过或者非相连O下return + if(i < 0 || j < 0 || i == m || j == n || board[i][j] != 'O' || cannot[i+'-'+j]){ + return; + } + cannot[i+'-'+j] = true; + dfs(i-1,j); + dfs(i+1,j); + dfs(i,j-1); + dfs(i,j+1); + } + for(let i = 0;i < m;i++){ + for(let j = 0;j < n;j++){ + // 从边缘O出发寻找其相连点都标示为不可替换 + if((i == 0 || j == 0 || i == m-1 || j == n-1) && board[i][j] == 'O'){ + dfs(i,j); + } + } + } + // 规避边界条件去循环 + for(let i = 1;i < m-1;i++){ + for(let j = 1;j < n-1;j++){ + if(!cannot[i+'-'+j] && board[i][j] == 'O'){ + board[i][j] = 'X'; + } + } + } +}; +``` \ No newline at end of file diff --git a/Week 06/id_651/LeetCode_127_651.py b/Week 06/id_651/LeetCode_127_651.py new file mode 100644 index 000000000..2bb66d3e7 --- /dev/null +++ b/Week 06/id_651/LeetCode_127_651.py @@ -0,0 +1,87 @@ +""" +给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 +说明: + +如果不存在这样的转换序列,返回 0。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +示例 1: + +输入: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +输出: 5 +""" +from collections import defaultdict +class Solution(object): + # TODO 方法一: BFS + def ladderLength(self, beginWord, endWord, wordList): + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + L = len(beginWord) + all_combo_dict = defaultdict(list) + for word in wordList: + for i in range(L): + all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + queue = [(beginWord, 1)] + visited = {beginWord: True} + while queue: + current_word, level = queue.pop(0) + for i in range(L): + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + for word in all_combo_dict[intermediate_word]: + if word == endWord: + return level + 1 + if word not in visited: + visited[word] = True + queue.append((word, level + 1)) + all_combo_dict[intermediate_word] = [] + return 0 + + # TODO 方法二: 双向BFS + def __init__(self): + self.length = 0 + self.all_combo_dict = defaultdict(list) + + def visitWordNode(self, queue, visited, others_visited): + current_word, level = queue.pop(0) + for i in range(self.length): + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + for word in self.all_combo_dict[intermediate_word]: + if word in others_visited: + return level + others_visited[word] + if word not in visited: + visited[word] = level + 1 + queue.append((word, level + 1)) + return None + + def ladderLength(self, beginWord, endWord, wordList): + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + self.length = len(beginWord) + for word in wordList: + for i in range(self.length): + self.all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + + queue_begin = [(beginWord, 1)] + queue_end = [(endWord, 1)] + + visited_begin = {beginWord: 1} + visited_end = {endWord: 1} + ans = None + + while queue_begin and queue_end: + ans = self.visitWordNode(queue_begin, visited_begin, visited_end) + if ans: + return ans + ans = self.visitWordNode(queue_end, visited_end, visited_begin) + if ans: + return ans + return 0 \ No newline at end of file diff --git a/Week 06/id_651/LeetCode_200_651.py b/Week 06/id_651/LeetCode_200_651.py new file mode 100644 index 000000000..0a75a7807 --- /dev/null +++ b/Week 06/id_651/LeetCode_200_651.py @@ -0,0 +1,133 @@ +""" +给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + +示例 1: + +输入: +11110 +11010 +11000 +00000 + +输出: 1 +示例 2: + +输入: +11000 +11000 +00100 +00011 + +输出: 3 +""" + +class Solution(object): + # x,y轴的正负方向 + directions = [(-1, 0), (0,-1), (1, 0), (0, 1)] + + # TODO 方法一: DFS + def numIslands(self, grid): + m = len(grid) + if m == 0: + return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + for i in range(m): + for j in range(n): + # 只要是陆地,且没有被访问过的,就用DFS发现与之相连的陆地,并进行标记 + if not marked[i][j] and grid[i][j] == '1': + count += 1 + self.dfs(grid, i, j, m, n, marked) + return count + + def dfs(self, grid, i, j, m, n marked): + marked[i][j] = True + for direction in self.directions: + new_i = i + direction[0] + new_j = j + direction[1] + if 0 <= new_i < m and 0 <= new_j < n and + not marked[new_i][new_j] and grid[new_i][new_j] == '1': + self.dfs(grid, new_i, new_j, m, n, marked) + + # TODO 方法二: BFS + def numIsland(self, grid): + m = len(grid) + if m == 0: + return 0 + n = len(grid[0]) + marked = [[False for _ in range(n)] for _ in range(m)] + count = 0 + for i in range(m): + for j in range(n): + if not marked[i][j] and grid[i][j] == '1': + count += 1 + queue = deque() + queue.append((i,j)) + marked[i][j] = True + while queue: + cur_x, cur_y = queue.popleft() + for direction in self.directions: + new_i = cur_x + direction[0] + new_j = cur_y + direction[1] + if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1': + queue.append((new_i, new_j)) + marked[new_i][new_j] = True + return count + + # TODO 方法三: 并查集 + def numIslands(self, grid): + class UnionFind(object): + def __init__(self, n): + self.count = n + self.parent = [i for i in range(n)] + self.rank = [1 for _ in range(n)] + def get_count(self): + return self.count + def find(self,p): + while p != self.parent[p]: + self.parent[p] = self.parent[self.parent[p]] + p = self.parent[p] + return p + + def is_connected(self,p,q): + return self.find(p) == self.find(q) + + def union(self, p, q): + p_root = self.find(p) + q_root = self.find(q) + if p_root == q_root: + return + if self.rank[p_root] > self.rank[q_root]: + self.parent[q_root] = p_root + elif self.rank[p_root] < self.rank[q_root]: + self.parent[p_root] = q_root + else: + self.parent[q_root] = p_root + self.rank[p_root] += 1 + self.count -= 1 + row = len(grid) + if row == 0: + return 0 + col = len(grid[0]) + + def get_index(x, y): + return x*col + y + + directions = [(1, 0), (0, 1)] + dummy_node = row * col + # 虚拟空间 + uf = UnionFind(dummy_node + 1) + for i in range(row): + for j in range(col): + # 如果是水, 都连到虚拟空间 + if grid[i][j] == '0': + uf.union(get_index(i, j), dummy_node) + if grid[i][j] == '1': + # 向下向右 是陆地就合并 + for direction in directions: + new_x = i + direction[0] + new_y = j + direction[1] + if new_x < row and new_y < col and grid[new_x][new_y] == '1': + uf.union(get_index(i, j), get_index(new_x, new_y)) + return uf.get_count() - 1 \ No newline at end of file diff --git a/Week 06/id_651/LeetCode_212_651.py b/Week 06/id_651/LeetCode_212_651.py new file mode 100644 index 000000000..44b1687d4 --- /dev/null +++ b/Week 06/id_651/LeetCode_212_651.py @@ -0,0 +1,92 @@ +""" +给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 + +单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 + +示例: + +输入: +words = ["oath","pea","eat","rain"] and board = +[ + ['o','a','a','n'], + ['e','t','a','e'], + ['i','h','k','r'], + ['i','f','l','v'] +] + +输出: ["eat","oath"] +说明: +你可以假设所有输入都由小写字母 a-z 组成。 +""" +class TrieNode(): + def __init__(self): + self.children = collections.defaultdict(TrieNode) + self.isWord = False +class Trie(): + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for w in word: + node = node.children[w] + node.isWord = True + +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + res = [] + trie = Trie() + node = trie.root + for w in words: + trie.insert(w) + for i in range(len(board)): + for j in range(len(board[0])): + self.dfs(board, node, i, j, "", res) + return res + + def dfs(self,board, node,i,j,path,res): + if node.isWord: + res.append(path) + node.isWord = False + if i<0 or i>= len(board) or j < 0 or j >= len(board[0]): + return + tmp = board[i][j] + node = node.children.get(tmp) + if not node: + return + board[i][j] = '#' + # 四个方向扩散 + self.dfs(board, node,i+1,j, path+tmp, res) + self.dfs(board, node,i-1,j, path+tmp, res) + self.dfs(board, node,i,j+1, path+tmp, res) + self.dfs(board, node,i,j-1, path+tmp, res) + board[i][j] = tmp + + def findWords(self, board, words): + root = {} + for word in words: + node = root + for c in word: + node = node.setdefault(c, {}) + node[None] = True + board = {i + 1j*j: c + for i, row in enumerate(board) + for j, c in enumerate(row)} + + found = [] + for z in board: + self.search(root, z, '') + return found + + def search(self, node, z, word): + if node.pop(None, None): + found.append(word) + c = board.get(z) + if c in node: + board[z] = None + for k in range(4): + search(node[c], z + 1j**k, word + c) + board[z] = c + +if __name__ == "__main__": + pass \ No newline at end of file diff --git a/Week 06/id_651/NOTE.md b/Week 06/id_651/NOTE.md index a6321d6e2..6d14eada3 100644 --- a/Week 06/id_651/NOTE.md +++ b/Week 06/id_651/NOTE.md @@ -1,4 +1,99 @@ # NOTE - +Week 06 +1. 字典树, 并查集 + 字典树:前缀树,典型应用是统计和排序大量的字符串 + 模板 + class Trie(object): + def __init__(self): + self.root = {} + self.end_of_word = '#' + def insert(self,word): + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + def search(self,word): + node = self.root + for char in word: + if char not in word: + return False + node = node[char] + return self.end_of_word in node + def startswith(self, prefix): + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return True + + 并查集: + 场景: 组团, 配对问题 + 模板 + def init(n): + p = [i for i in range(n)] + + def union(self, p, i, j): + p1 = self.parent(p, i) + p2 = self.parent(p, j) + p[p1] = p2 + + def parent(self, p, i): + root = i + while p[root] != root: + root = p[root] + while p[i] != i: + x = i + i = p[i] + p[x] = root + return root + +2. 双向BFS,A*/启发式搜索 + 双向BFS : BFS的进阶版本, 从头走到尾,和从尾向头走,相遇的地方即是解 + A*/启发式搜索: 在BFS的基础上, 加上了优先队列的概念(通过估价函数来判断哪些节点是需要优先搜索的) + + DFS模板: + def DFS(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + while stack: + node = stack.pop() + vistied.add(node) + process(node) + nodes = generate_related_nodes(node) + stack.push(nodes) + # other processing work + + BFS模板: + def BFS(graph, start, end): + queue = [] + queue.append([start]) + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + # other processing work + + +3. AVL树和红黑树 + AVL树: 平衡二叉树,有平衡因子/深度差(在-1 0 1范围内则结构是正常的, 如果超出了范围, 则需要做对应的节点调整) + 场景: 在需要查询次数比较多的时候, 更适合用AVL树 + 不足: 节点需要存储额外的信息。 调整的频繁 + + 红黑树:近似平衡二叉树, + 特性: + -- 任意节点的子节点的高度差小于两倍 + 不能有相邻接的两个红节点 + 从任意节点到其他叶子节点所有的路径都包含相同数目的黑色节点 + + 场景: 在需要频繁的插入,删除的操作的时候, 更适合用红黑树 + 优点: 调整的没AVL频繁, 存储的信息没AVL多 + + + 基本的旋转操作: + 左旋, 右旋, 左右旋, 右左旋 \ No newline at end of file diff --git "a/Week 06/id_676/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" "b/Week 06/id_676/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" new file mode 100644 index 000000000..9fdbd21e6 --- /dev/null +++ "b/Week 06/id_676/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" @@ -0,0 +1,95 @@ +import java.nio.channels.NonWritableChannelException; + +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i= 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (node.containsKey(currentChar)) { + node = node.get(currentChar); + } else { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} +class TrieNode { + + // R links to node children + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } +} + + +/** + * 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); + */ +// @lc code=end + diff --git "a/Week 06/id_676/547.\346\234\213\345\217\213\345\234\210.java" "b/Week 06/id_676/547.\346\234\213\345\217\213\345\234\210.java" new file mode 100644 index 000000000..f5932b910 --- /dev/null +++ "b/Week 06/id_676/547.\346\234\213\345\217\213\345\234\210.java" @@ -0,0 +1,81 @@ +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + */ +/* +*思路:1.DFS +*2.并查集(熟练并查集的代码模板) +*/ +// @lc code=start +//并查集 +class Solution { + class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + + public int count() { + return count; + } + + } + + public int findCircleNum(int[][] M) { + int n = M.length; + UnionFind uf = new UnionFind(n); + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (M[i][j] == 1) uf.union(i, j); + } + } + return uf.count(); + } + +} +// @lc code=end + +//DFS +class SolutionOne { + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + + } +} \ No newline at end of file diff --git a/Week 06/id_681/LeetCode_208_681.java b/Week 06/id_681/LeetCode_208_681.java new file mode 100644 index 000000000..b030f8ecb --- /dev/null +++ b/Week 06/id_681/LeetCode_208_681.java @@ -0,0 +1,61 @@ +class Trie { + public boolean isWord; + public char word; + public Trie[] tries = new Trie[26]; + + public Trie() { + this.isWord = false; + this.word = ' '; + + } + + public void insert(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] == null) { + node.tries[array[i] - 'a'] = new Trie(); + } + node = node.tries[array[i] - 'a']; + node.word = array[i]; + if (i == array.length - 1) { + node.isWord = true; + } + } + + } + + public boolean search(String word) { + char[] array = word.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return node.isWord == true ? true : false; + } + + public boolean startsWith(String prefix) { + char[] array = prefix.toCharArray(); + Trie node = this; + for (int i = 0; i < array.length; i++) { + if (node.tries[array[i] - 'a'] != null) { + node = node.tries[array[i] - 'a']; + if (node.word == array[i]) + continue; + else + return false; + } else + return false; + + } + return true; + } +} diff --git a/Week 06/id_681/LeetCode_547_681.java b/Week 06/id_681/LeetCode_547_681.java new file mode 100644 index 000000000..01c9b15ca --- /dev/null +++ b/Week 06/id_681/LeetCode_547_681.java @@ -0,0 +1,23 @@ +public class Solution { + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } +} + diff --git a/Week 06/id_686/LeetCode_127_686.java b/Week 06/id_686/LeetCode_127_686.java new file mode 100644 index 000000000..e36f46f4c --- /dev/null +++ b/Week 06/id_686/LeetCode_127_686.java @@ -0,0 +1,75 @@ +//给定两个单词(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 广度优先搜索 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set dict = new HashSet<>(wordList); + Queue queue = new LinkedList<>(); + queue.add(beginWord); + int level = 1; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int q=0; q < size; q++) { + char[] cur = queue.poll().toCharArray(); + for (int i=0; i < cur.length; i++) { + char tmp = cur[i]; + for (char chr='a'; chr <= 'z'; chr++) { + cur[i] = chr; + String dest = new String(cur); + if (dict.contains(dest)) { + if (dest.equals(endWord)) return level+1; + queue.add(dest); + dict.remove(dest); + } + } + cur[i] = tmp; + } + } + level++; + } + return 0; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_686/LeetCode_51_686.py b/Week 06/id_686/LeetCode_51_686.py new file mode 100644 index 000000000..624aaa877 --- /dev/null +++ b/Week 06/id_686/LeetCode_51_686.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode.cn id=51 lang=python3 +# +# [51] N皇后 +# + +# @lc code=start +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + board = [['.' for _ in range(n)] for _ in range(n)] + d1 = set() + d2 = set() + h = set() + v = set() + soln = [] + + def util(col): + if col == n: # Found a soln, so add it + soln.append([]) + for row in board: + soln[-1].append("".join(row)) + return + + for row in range(n): + if col not in v and row not in h and col+row not in d1 and (n-col-1 + row) not in d2: + board[col][row] = 'Q' + v.add(col) + h.add(row) + d1.add(col+row) + d2.add(n-col-1 + row) + + util(col+1) + + board[col][row] = '.' + v.remove(col) + h.remove(row) + d1.remove(col+row) + d2.remove(n-col-1 + row) + + util(0) + return soln +# @lc code=end + diff --git a/Week 06/id_691/691-Week 06/LeetCode-200-691.java b/Week 06/id_691/691-Week 06/LeetCode-200-691.java new file mode 100644 index 000000000..4c2e97f0a --- /dev/null +++ b/Week 06/id_691/691-Week 06/LeetCode-200-691.java @@ -0,0 +1,68 @@ +class Solution { + int[][] distance = {{1,0},{-1,0},{0,1},{0,-1}} + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0){ + return 0; + } + + UnionFind uf = new UnionFind(grid); + int rows = grid.length; + int cols = grid[0].length; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == '1') { + for (int[] d : distance) { + int x = i + d[0]; + int y = j + d[1]; + if (x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] == '1') { + int id1 = i * cols + j; + int id2 = x * cols + y; + uf.uion(id1, id2); + } + } + } + } + } + + return uf.count + } +} + +class UnionFind { + int[] father; + int m,n; + int count = 0; + + UnionFind (char[][] grid) { + m = grid.length; + n = grid[0].length; + father = new int[m*n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + int id = i * n + j; + father[id] = id; + count++; + } + } + } + } + + public void union(int node1, int node2) { + int find1 = find(node1); + int find2 = find(node2); + if (find1 != find2) { + father[find1] = find2; + count--; + } + } + + public int find(int node) { + if (father[node] == node) { + return node; + } + father[node] = find(father[node]); + return father[node]; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 06/id_691/691-Week 06/LeetCode-574-691.java b/Week 06/id_691/691-Week 06/LeetCode-574-691.java new file mode 100644 index 000000000..d23411424 --- /dev/null +++ b/Week 06/id_691/691-Week 06/LeetCode-574-691.java @@ -0,0 +1,23 @@ +class Solution { + + public void dfs(int[][] M,int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0){ + visited[j] = 1; + dfs(M,visited, j ); + } + } + } + + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i =0; i < M.length; i++) { + if(visited[i] == 0) { + dfs(M, visited, i ); + count++; + } + } + return count; + } +} diff --git a/Week 06/id_696/LeetCode_208_696.java b/Week 06/id_696/LeetCode_208_696.java new file mode 100644 index 000000000..e69d7ad77 --- /dev/null +++ b/Week 06/id_696/LeetCode_208_696.java @@ -0,0 +1,85 @@ +package week06; + +class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} + +class TrieNode { + + // R links to node children + private TrieNode[] links; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[26]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } +} + +/** + * 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); + */ diff --git a/Week 06/id_696/LeetCode_212_696.java b/Week 06/id_696/LeetCode_212_696.java new file mode 100644 index 000000000..f49c7cddb --- /dev/null +++ b/Week 06/id_696/LeetCode_212_696.java @@ -0,0 +1,76 @@ +package week06; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +class Solution { + public List findWords(char[][] board, String[] words) { + wordTrie myTrie = new wordTrie(); + trieNode root = myTrie.root; + for (String s : words) { + myTrie.insert(s); + } + + //使用set防止重复 + Set result = new HashSet<>(); + int m = board.length; + int n = board[0].length; + boolean[][] visited = new boolean[m][n]; + //遍历整个二维数组 + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board [0].length; j++){ + find(board,visited,i,j,m,n,result,root); + } + } + System.out.print(result); + return new LinkedList(result); + } + + private void find(char [] [] board, boolean [][]visited,int i,int j,int m,int n,Set result,trieNode cur){ + //边界以及是否已经访问判断 + if (i<0||i>=m||j<0||j>=n||visited[i][j]) + return; + cur = cur.child[board[i][j] - 'a']; + visited[i][j] = true; + if (cur == null) { + //如果单词不匹配,回退 + visited[i][j] = false; + return; + } + //找到单词加入 + if (cur.isLeaf) { + result.add(cur.val); + } + find(board, visited, i+1, j, m, n, result, cur); + find(board, visited, i, j+1, m, n, result, cur); + find(board, visited, i, j-1, m, n, result, cur); + find(board, visited, i-1, j, m, n, result, cur); + //最后要回退,因为下一个起点可能会用到上一个起点的字符 + visited[i][j] = false; + } +} + +class wordTrie { + public trieNode root = new trieNode(); + public void insert(String s) { + trieNode cur = root; + for (char c : s.toCharArray()) { + if (cur.child[c - 'a'] == null) { + cur.child[c - 'a'] = new trieNode(); + cur = cur.child[c - 'a']; + } else { + cur = cur.child[c - 'a']; + } + } + cur.isLeaf = true; + cur.val = s; + } +} +//字典树结点 +class trieNode { + public String val; + public trieNode[] child = new trieNode[26]; + public boolean isLeaf = false; +} \ No newline at end of file diff --git a/Week 06/id_701/NOTE.md b/Week 06/id_701/NOTE.md index a6321d6e2..b235f8161 100644 --- a/Week 06/id_701/NOTE.md +++ b/Week 06/id_701/NOTE.md @@ -1,4 +1,82 @@ -# NOTE +# 【701-week6】第六周学习总结 - +## 字典树(Trie) +### 数据结构 + +> 字典树,即 Trie 树,又称单词 查找树或键树,是一种树形结 构。典型应用是用于统计和排 序大量的字符串(但不仅限于 字符串),所以经常被搜索引 擎系统用于文本词频统计。 + +它的优点是:最大限度地减少 无谓的字符串比较,查询效率 比哈希表高。 + +### 核心思想 + +Trie 树的核心思想是空间换时间。 + +利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 + +### 基本性质 + +- 结点本身不存完整单词; +- 从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的 字符串; +- 每个结点的所有子结点路径代表的字符都不相同。 + +## 并查集 + +> 常用于组团、配对问题 + +### 基本操作 + +- makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合。 +- unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在 的集合不相交,如果相交则不合并。 +- find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元 素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。 + +## 搜索 + +### 初级搜索 + +- 朴素搜索 +- 优化方式:不重复(Fibonacci)、剪枝(生成括号问题) +- 搜索方向: + - DFS + - BFS + - 启发式搜索 + - 双向搜索 + +### 回溯法 + +回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。 + +回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: + +- 找到一个可能存在的正确的答案 +- 在尝试了所有可能的分步方法后宣告该问题没有答案 + +在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。 + +## 高级树、AVL 树和红黑树 + +叉搜索树,也称二叉搜索树、有序二叉树(Ordered Binary Tree)、 排序二叉树(Sorted Binary Tree),是指一棵空树或者具有下列性质的二叉树: + +- 左子树上所有结点的值均小于它的根结点的值; +- 右子树上所有结点的值均大于它的根结点的值; +- 以此类推:左、右子树也分别为二叉查找树。(这就是重复性!) +- 中序遍历为升序排列 + +AVL 是 +- 平衡二叉搜索树 +- 每个结点存 balance factor = {-1, 0, 1} +- 四种旋转操作 + - 左旋 + - 右旋 + - 左右旋 + - 右左旋 + +不足:结点需要存储额外信息、且调整次数频繁 + +红黑树是一种近似平衡的二叉搜索树(Binary Search Tree),它能够确保任何一 个结点的左右子树的高度差小于两倍。具体来说,红黑树是满足如下条件的二叉搜 索树: + +- 每个结点要么是红色,要么是黑色 +- 根节点是黑色 +- 每个叶节点(NIL节点,空节点)是黑色的。 +- 不能有相邻接的两个红色节点 +- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。 diff --git a/Week 06/id_701/leetcode_200_701.cs b/Week 06/id_701/leetcode_200_701.cs new file mode 100644 index 000000000..0908b49a1 --- /dev/null +++ b/Week 06/id_701/leetcode_200_701.cs @@ -0,0 +1,36 @@ +public class Solution +{ + public int NumIslands(char[][] grid) + { + int count = 0; + if (grid != null) + { + for (int i = 0; i < grid.Length; i++) + { + for (int j = 0; j < grid[i].Length; j++) + { + if (grid[i][j] == '1') + { + DFS(grid, i, j); + count += 1; + } + } + } + } + return count; + } + + private void DFS(char[][] grid, int x, int y) + { + if (x < 0 || x > grid.Length-1 || y < 0 || y > grid[0].Length-1 || grid[x][y] != '1') + { + return; + } + grid[x][y] = '#'; + + DFS(grid, x + 1, y); + DFS(grid, x - 1, y); + DFS(grid, x, y + 1); + DFS(grid, x, y - 1); + } +} \ No newline at end of file diff --git a/Week 06/id_701/leetcode_208_701.py b/Week 06/id_701/leetcode_208_701.py new file mode 100644 index 000000000..8f393eb7b --- /dev/null +++ b/Week 06/id_701/leetcode_208_701.py @@ -0,0 +1,46 @@ +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.end_of_word = "#" + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) diff --git a/Week 06/id_701/leetcode_547_701.py b/Week 06/id_701/leetcode_547_701.py new file mode 100644 index 000000000..3f20722ea --- /dev/null +++ b/Week 06/id_701/leetcode_547_701.py @@ -0,0 +1,15 @@ +class Solution: + def findCircleNum(self, M: List[List[int]]) -> int: + def dfs(node): + visited.add(node) + for friend in range(len(M)): + if M[node][friend] and friend not in visited: + dfs(friend) + + circle = 0 + visited = set() + for node in range(len(M)): + if node not in visited: + dfs(node) + circle += 1 + return circle diff --git a/Week 06/id_711/Leetcode_130_711.java b/Week 06/id_711/Leetcode_130_711.java new file mode 100644 index 000000000..220ddff3c --- /dev/null +++ b/Week 06/id_711/Leetcode_130_711.java @@ -0,0 +1,106 @@ +package Week6; + +import java.util.HashSet; +import java.util.Set; + +class UnionFindXO { + private int[] parent; + + public UnionFindXO(char[][] board) { + parent = new int[board.length * board[0].length]; + for (int i = 0; i < parent.length; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + if (rootX != rootY) { + parent[rootX] = rootY; + } + } +} + +public class Leetcode_130_711 { + public static void main(String[] args) { + char[][] board = { + {'x','O','x','x'}, + {'O','X','O','x'}, + {'x','O','X','O'}, + {'O','X','O','x'}, + {'x','O','X','O'}, + {'O','X','O','x'} + }; + new Leetcode_130_711().solve(board); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 4; j++) { + System.out.print(board[i][j]); + } + System.out.println(); + } + } + + int[] a = {0,0,1,-1}; + int[] b = {1,-1,0,0}; + + /** + * 并查集写法 + * 执行用时 :10 ms, 在所有 java 提交中击败了18.86%的用户 + * 内存消耗 :46 MB, 在所有 java 提交中击败了84.49%的用户 + * @param board + */ + private void solve(char[][] board) { + if (board == null || board.length == 0) + return; + int n = board.length; + int m = board[0].length; + UnionFindXO union = new UnionFindXO(board); + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (board[i][j] == 'O') { + for (int k = 0; k < 4; k++) { + int x = i + a[k]; + int y = j + b[k]; + if (x >= 0 && x < n && y >= 0 && y < m && board[x][y] == 'O') { + union.union(i * m + j, x * m + y); + } + } + } + } + } + Set set = new HashSet<>(); + for (int i = 0; i < n; i++) { + if (board[i][0] == 'O') { + set.add(union.find(i * m)); + } + if (board[i][m - 1] == 'O') { + set.add(union.find(i * m + m - 1)); + } + } + for (int i = 1; i < m - 1; i++) { + if (board[0][i] == 'O') { + set.add(union.find(i)); + } + if (board[n - 1][i] == 'O') { + set.add(union.find((n - 1) * m + i)); + } + } + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (board[i][j] == 'O' && !set.contains(union.find(i * m + j))) { + board[i][j] = 'X'; + } + } + } + } +} diff --git a/Week 06/id_711/Leetcode_200_711.java b/Week 06/id_711/Leetcode_200_711.java new file mode 100644 index 000000000..d40bde4ca --- /dev/null +++ b/Week 06/id_711/Leetcode_200_711.java @@ -0,0 +1,83 @@ +package Week6; + +class UnionFindLand { + public int count; + public int[] parent; + + public UnionFindLand(char[][] grid) { + int n = grid.length; + int m = grid[0].length; + parent = new int[n * m]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + parent[i * m + j] = i * m + j; + count++; + } + } + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + if (rootX != rootY) { + parent[rootX] = rootY; + count--; + } + } +} + +public class Leetcode_200_711 { + public static void main(String[] args) { + char[][] grid = { + {'1','1','1','1','0'}, + {'1','1','0','1','0'}, + {'1','1','0','0','0'}, + {'0','0','0','0','0'} + }; + System.out.println(new Leetcode_200_711().numIslands(grid)); + } + + int[] a = {0,0,1,-1}; + int[] b = {1,-1,0,0}; + + /** + * 并查集写法 + * 执行用时 :5 ms, 在所有 java 提交中击败了36.97%的用户 + * 内存消耗 :41.3 MB, 在所有 java 提交中击败了82.09%的用户 + * @param grid + * @return + */ + private int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) + return 0; + UnionFindLand union = new UnionFindLand(grid); + int n = grid.length; + int m = grid[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + for (int k = 0; k < 4; k++) { + int x = i + a[k]; + int y = j + b[k]; + if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '1') { + union.union(i * m + j, x * m + y); + } + } + } + } + } + return union.count; + } + + +} diff --git a/Week 06/id_711/Leetcode_208_711.java b/Week 06/id_711/Leetcode_208_711.java new file mode 100644 index 000000000..99c8d2b2e --- /dev/null +++ b/Week 06/id_711/Leetcode_208_711.java @@ -0,0 +1,95 @@ +package Week6; + +//class TrieNode { +// private TrieNode[] links; +// +// private final int R = 26; +// +// private boolean isEnd; +// +// public TrieNode() { +// links = new TrieNode[R]; +// } +// +// public boolean containKey(char ch) { +// return links[ch - 'a'] != null; +// } +// +// public TrieNode get(char ch) { +// return links[ch - 'a']; +// } +// +// public void put(char ch, TrieNode node) { +// links[ch - 'a'] = node; +// } +// +// public void setEnd() { +// isEnd = true; +// } +// +// public boolean isEnd() { +// return isEnd; +// } +//} +// +//class Trie { +// +// private TrieNode root; +// +// public Trie() { +// root = new TrieNode(); +// } +// +// public void insert(String word) { +// TrieNode node = root; +// for (int i = 0; i < word.length(); i++) { +// char currentChar = word.charAt(i); +// if (!node.containKey(currentChar)) { +// node.put(currentChar, new TrieNode()); +// } +// node = node.get(currentChar); +// } +// node.setEnd(); +// } +// +// private TrieNode searchPrefix(String word) { +// TrieNode node = root; +// for (int i = 0; i < word.length(); i++) { +// char currentChar = word.charAt(i); +// if (!node.containKey(currentChar)) +// return null; +// node = node.get(currentChar); +// } +// return node; +// } +// +// public boolean search(String word) { +// TrieNode node = searchPrefix(word); +// return node != null && node.isEnd(); +// } +// +//// +//// TrieNode node = root; +//// for (int i = 0; i < word.length(); i++) { +//// char currentChar = word.charAt(i); +//// if (!node.containKey(currentChar)) +//// return false; +//// node = node.get(currentChar); +//// } +//// return node.isEnd(); +// +// public boolean startsWith(String prefix) { +// return searchPrefix(prefix) != null; +// } +//} + +public class Leetcode_208_711 { + public static void main(String[] args) { +// Trie trie = new Trie(); +// trie.insert("asia"); +// trie.insert("asiawyz"); +// trie.insert("today"); +// System.out.println(trie.search("asia")); +// System.out.println(trie.startsWith("asdf")); + } +} diff --git a/Week 06/id_711/Leetcode_212_711.java b/Week 06/id_711/Leetcode_212_711.java new file mode 100644 index 000000000..03213ba56 --- /dev/null +++ b/Week 06/id_711/Leetcode_212_711.java @@ -0,0 +1,125 @@ +package Week6; + +import java.util.LinkedList; +import java.util.List; + +class TrieNode { + public char val; + public boolean isWord; + public TrieNode[] children = new TrieNode[26]; + public TrieNode() {} + public TrieNode(char c) { + TrieNode node = new TrieNode(); + node.val = c; + } +} + +class Trie { + private TrieNode root; + public Trie() { + root = new TrieNode(); + root.val = ' '; + } + + public void insert(String word) { + TrieNode ws = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (ws.children[ch - 'a'] == null) { + ws.children[ch - 'a'] = new TrieNode(ch); + } + ws = ws.children[ch - 'a']; + } + ws.isWord = true; + } + + public TrieNode searchPrefix(String prefix) { + TrieNode node = root; + for (int i = 0; i < prefix.length(); i++) { + char ch = prefix.charAt(i); + if (node.children[ch - 'a'] == null) { + return null; + } + node = node.children[ch - 'a']; + } + return node; + } + + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isWord; + } + + public boolean startsWith(String prefix) { + return searchPrefix(prefix) != null; + } +} + +public class Leetcode_212_711 { + public static void main(String[] args) { + String[] words = {"ab","cb","ad","bd","ac","ca","da","bc","db","adcb","dabc","abb","acb"}; + char[][] board = { + {'a','b'}, + {'c','d'} + }; + Leetcode_212_711 asia = new Leetcode_212_711(); + List lis = asia.findWords(board, words); + for (String st : lis) { + System.out.println(st); + } + } + + + + public Trie tree; + public List list; + public int[] a = {0,0,1,-1}; + public int[] b = {1,-1,0,0}; + public int n,m; + public char[][] bo; + + /** + * 先用字典树对所给的单词建树,然后对char数组进行dsf,利用字典树剪枝。 + * 执行用时 :27 ms, 在所有 java 提交中击败了69.77%的用户 + * 内存消耗 :47.3 MB, 在所有 java 提交中击败了88.51%的用户 + * @param board + * @param words + * @return + */ + private List findWords(char[][] board, String[] words) { + tree = new Trie(); + for (String str : words) { + tree.insert(str); + } + list = new LinkedList<>(); + n = board.length; + m = board[0].length; + bo = board; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + dfs(i,j,""); + } + } + return list; + } + + private void dfs(int x, int y, String s) { + String str = s + bo[x][y]; + TrieNode node = tree.searchPrefix(str); + if (node == null) + return; + if (node.isWord) { + list.add(str); + node.isWord = false; + } + char tmp = bo[x][y]; + bo[x][y] = '#'; + for (int i = 0; i < 4; i++) { + int x1 = x + a[i], y1 = y + b[i]; + if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= m || bo[x1][y1] == '#') + continue; + dfs(x + a[i], y + b[i], str); + } + bo[x][y] = tmp; + } +} diff --git a/Week 06/id_711/Leetcode_221_711.java b/Week 06/id_711/Leetcode_221_711.java new file mode 100644 index 000000000..83527a721 --- /dev/null +++ b/Week 06/id_711/Leetcode_221_711.java @@ -0,0 +1,56 @@ +package Week6; + +public class Leetcode_221_711 { + public static void main(String[] args) { + char[][] matrix = { + {'1','0','1','0','0'}, + {'1','0','1','1','1'}, + {'1','1','1','1','1'}, + {'1','0','0','1','0'} + }; + System.out.println(maximalSquare(matrix)); + } + + /** + * 预处理一下,a[i][j] 记录这行到j有多少个1,b[i][j]记录这列到i有多少个1 + * 当前为'1'时, + * dp[i][j] = min(a[i][j],b[i][j]) > dp[i - 1][j - 1](不为0) ? dp[i - 1][j - 1] + 1 : min(a[i][j], b[i][j]) + * 执行用时 :7 ms, 在所有 java 提交中击败了68.58%的用户 + * 内存消耗 :42.5 MB, 在所有 java 提交中击败了88.89%的用户 + * @param matrix + * @return + */ + private static int maximalSquare(char[][] matrix) { + int n = matrix.length, m = matrix[0].length; + int[][] dp = new int[n + 1][m + 1]; + int[][] a = new int[n + 1][m + 1]; + int[][] b = new int[n + 1][m + 1]; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m ; j++) { + if (matrix[i - 1][j - 1] == '1') { + a[i][j] = a[i][j - 1] + 1; + b[i][j] = b[i - 1][j] + 1; + } + } + } + int ans = 0; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m ; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = 1; + int x = Math.min(a[i][j],b[i][j]); + if (dp[i - 1][j - 1] > 0) { + if (x > dp[i - 1][j - 1]) { + dp[i][j] += dp[i - 1][j - 1]; + } + else { + dp[i][j] = x; + } + } + ans = Math.max(ans, dp[i][j]); + } + } + } + return ans * ans; + } +} diff --git a/Week 06/id_711/Leetcode_547_711.java b/Week 06/id_711/Leetcode_547_711.java new file mode 100644 index 000000000..31f0295ab --- /dev/null +++ b/Week 06/id_711/Leetcode_547_711.java @@ -0,0 +1,58 @@ +package Week6; + +class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + if (rootX == rootY) + return; + parent[rootX] = rootY; + count--; + } + + public int getCount() { + return this.count; + } +} +public class Leetcode_547_711 { + public static void main(String[] args) { + int[][] M = { + {1,1,0}, + {1,1,0}, + {0,0,1} + }; + System.out.println(findCircleNum(M)); + } + + private static int findCircleNum(int[][] M ) { + int n = M.length; + UnionFind union = new UnionFind(n); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (i == j) continue; + if (M[i][j] == 1) { + union.union(i,j); + } + } + } + return union.getCount(); + } +} diff --git a/Week 06/id_716/LeetCode_130_716.java b/Week 06/id_716/LeetCode_130_716.java new file mode 100644 index 000000000..7f847e728 --- /dev/null +++ b/Week 06/id_716/LeetCode_130_716.java @@ -0,0 +1,206 @@ +import java.util.Deque; +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_130_716 { + private int[] dx = new int[]{-1, 1, 0, 0}; + private int[] dy = new int[]{0, 0, -1, 1}; + + // 1. dfs + public void solve1(char[][] board) { + if (board.length == 0) return; + int rows = board.length, cols = board[0].length; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1) { + if (board[i][j] == 'O') + dfs(board, i, j); + } + } + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') board[i][j] = 'X'; + else if (board[i][j] == '#') board[i][j] = 'O'; + } + } + } + + private void dfs(char[][] board, int i, int j) { + if (board[i][j] == 'X' || board[i][j] == '#') return; + + board[i][j] = '#'; + for (int k = 0; k < dx.length; k++) { + int x = i + dx[k], y = j + dy[k]; + if (x >= 0 && x < board.length && y >= 0 && y < board[0].length) + dfs(board, x, y); + } + } + + // 2. dfs 非递归 + private int rows; + private int cols; + + public void solve2(char[][] board) { + if (board.length == 0) return; + rows = board.length; + cols = board[0].length; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1) { + if (board[i][j] == 'O') + dfs2(board, i * cols + j); + } + } + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') board[i][j] = 'X'; + else if (board[i][j] == '#') board[i][j] = 'O'; + } + } + } + + private void dfs2(char[][] board, int pos) { + int row = pos / cols, col = pos % cols; + Deque stack = new LinkedList<>(); + stack.addFirst(pos); + board[row][col] = '#'; + while (!stack.isEmpty()) { + int curr = stack.peekFirst(); + row = curr / cols; + col = curr % cols; + + boolean hasMore = false; + for (int k = 0; k < dx.length; k++) { + int x = row + dx[k], y = col + dy[k]; + if (x >= 0 && x < board.length && y >= 0 && y < board[0].length + && board[x][y] == 'O') { + stack.addFirst(x * cols + y); + board[x][y] = '#'; + hasMore = true; + } + } + if (!hasMore) + stack.removeFirst(); + } + } + + // 3. bfs + public void solve3(char[][] board) { + if (board.length == 0) return; + rows = board.length; + cols = board[0].length; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1) { + if (board[i][j] == 'O') + bfs(board, i * cols + j); + } + } + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') board[i][j] = 'X'; + else if (board[i][j] == '#') board[i][j] = 'O'; + } + } + } + + private void bfs(char[][] board, int pos) { + Queue queue = new LinkedList<>(); + queue.offer(pos); + int row = pos / cols, col = pos % cols; + board[row][col] = '#'; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + Integer curr = queue.poll(); + row = curr / cols; + col = curr % cols; + for (int j = 0; j < dx.length; j++) { + int x = row + dx[j], y = col + dy[j]; + if (x >= 0 && x < board.length && y >= 0 && y < board[0].length + && board[x][y] == 'O') { + queue.offer(x * cols + y); + board[x][y] = '#'; + } + } + } + } + } + + // 4. Disjoint set + public void solve4(char[][] board) { + if (board.length == 0) return; + rows = board.length; + cols = board[0].length; + + UnionFind uf = new UnionFind(rows * cols + 1); + int dummy = rows * cols; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + + if (board[row][col] == 'O') { + if (row == 0 || col == 0 || row == rows - 1 || col == cols - 1) { + uf.union(row * cols + col, dummy); + } else { + for (int i = 0; i < dx.length; i++) { + int x = row + dx[i], y = col + dy[i]; + if (x >= 0 && x < rows && y >= 0 && y < cols && board[x][y] == 'O') + uf.union(row * cols + col, x * cols + y); + } + } + } + } + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (uf.isConnected(i * cols + j, dummy)) { + board[i][j] = 'O'; + } else { + board[i][j] = 'X'; + } + } + } + } + + class UnionFind { + private int[] parent; + + public UnionFind(int n) { + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP != rootQ) { + // union + parent[rootQ] = rootP; + } + } + + public boolean isConnected(int p, int dummy) { + return find(p) == find(dummy); + } + } +} \ No newline at end of file diff --git a/Week 06/id_716/LeetCode_200_716.java b/Week 06/id_716/LeetCode_200_716.java new file mode 100644 index 000000000..b2cf8804b --- /dev/null +++ b/Week 06/id_716/LeetCode_200_716.java @@ -0,0 +1,201 @@ +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_200_716 { + private int[] dx = new int[]{-1, 1, 0, 0}; + private int[] dy = new int[]{0, 0, -1, 1}; + private char[][] g; + + // 1. 使用 flood fill:https://zh.wikipedia.org/wiki/Flood_fill + // 1.1 dfs + public int numIslands11(char[][] grid) { + int islands = 0; + g = grid; + + for (int i = 0; i < g.length; i++) { + for (int j = 0; j < g[i].length; j++) { + if (g[i][j] == '0') continue; + islands += sink(i, j); + } + } + + return islands; + } + + private int sink(int i, int j) { + // terminator + if (g[i][j] == '0') return 0; + + // process current logic + g[i][j] = '0'; + + // drill down + for (int k = 0; k < dx.length; k++) { + int newx = i + dx[k], newy = j + dy[k]; + if (newx >= 0 && newx < g.length && newy >= 0 && newy < g[i].length) { + if (g[newx][newy] == '0') continue; + sink(newx, newy); + } + } + + return 1; + } + + // 1.2 + public int numIslands12(char[][] grid) { + int islands = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + islands += dfsMarking(grid, i, j); + } + } + } + return islands; + } + + private int dfsMarking(char[][] grid, int i, int j) { + // terminator + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] != '1') + return 0; + + // process current logic + grid[i][j] = '0'; + + // drill down +// dfsMarking(grid, i + 1, j); +// dfsMarking(grid, i - 1, j); +// dfsMarking(grid, i, j + 1); +// dfsMarking(grid, i, j - 1); + for (int k = 0; k < dx.length; k++) { + dfsMarking(grid, i + dx[k], j + dy[k]); + } + + return 1; + } + + // 1.3 bfs + public int numIslands13(char[][] grid) { + int islands = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + bfsFill(grid, i, j); + islands++; + } + } + } + return islands; + } + + private void bfsFill(char[][] grid, int i, int j) { + grid[i][j] = '0'; + int n = grid.length; + int m = grid[0].length; + + // bfs fill + Queue queue = new LinkedList<>(); + queue.offer(i * m + j); + while (!queue.isEmpty()) { + int code = queue.poll(); + int r = code / m; + int c = code % m; + + if (r > 0 && grid[r - 1][c] == '1') { + queue.offer((r - 1) * m + c); + grid[r - 1][c] = '0'; + } + + if (r < n - 1 && grid[r + 1][c] == '1') { + queue.offer((r + 1) * m + c); + grid[r + 1][c] = '0'; + } + + if (c > 0 && grid[r][c - 1] == '1') { + queue.offer(r * m + (c - 1)); + grid[r][c - 1] = '0'; + } + + if (c < m - 1 && grid[r][c + 1] == '1') { + queue.offer(r * m + (c + 1)); + grid[r][c + 1] = '0'; + } + } + } + + // 1.4 还有一种并查集的解法,union find set + public int numIslands14(char[][] grid) { + int rows = grid.length, cols = rows > 0 ? grid[0].length : 0; + if (grid == null || rows == 0) return 0; + + UnionFind uf = new UnionFind(grid); + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + if (grid[row][col] == '1') { + grid[row][col] = '0'; + if (row - 1 >= 0 && grid[row - 1][col] == '1') { + uf.union(row * cols + col, (row - 1) * cols + col); + } + if (row + 1 < rows && grid[row + 1][col] == '1') { + uf.union(row * cols + col, (row + 1) * cols + col); + } + if (col - 1 >= 0 && grid[row][col - 1] == '1') { + uf.union(row * cols + col, row * cols + col - 1); + } + if (col + 1 < cols && grid[row][col + 1] == '1') { + uf.union(row * cols + col, row * cols + col + 1); + } + } + } + } + return uf.getCount(); + } + + class UnionFind { + private int count; + private int[] parent; + private int[] rank; + + public UnionFind(char[][] grid) { + int m = grid.length, n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + count++; + } + } + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP != rootQ) { + // union + if (rank[rootP] > rank[rootQ]) { + parent[rootQ] = rootP; + } else if (rank[rootP] < rank[rootQ]) { + parent[rootP] = rootQ; + } else { + parent[rootQ] = rootP; + rank[rootP] += 1; + } + count--; + } + } + + public int find(int p) { + while (p != parent[p]) { + p = parent[p]; + } + return p; + } + + public int getCount() { + return count; + } + } +} \ No newline at end of file diff --git a/Week 06/id_716/LeetCode_208_716.java b/Week 06/id_716/LeetCode_208_716.java new file mode 100644 index 000000000..9f01133f1 --- /dev/null +++ b/Week 06/id_716/LeetCode_208_716.java @@ -0,0 +1,108 @@ + +public class LeetCode_208_716 { + class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + + TrieNode p = root; + for (Character c : word.toCharArray()) { + if (!p.containsKey(c)) { + p.put(c, new TrieNode()); + } + p = p.get(c); + } + p.setEnd(); + + } + + private TrieNode searchPrefix(String word) { + TrieNode p = root; + for (Character c : word.toCharArray()) { + if (!p.containsKey(c)) { + return null; + } + + p = p.get(c); + } + + return p; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode p = searchPrefix(word); + return p != null && p.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode p = searchPrefix(prefix); + return p != null; + } + } + + class TrieNode { + + private TrieNode[] links; + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public TrieNode get(int position) { + return links[position]; + } + + public boolean containsKey(char ch) { + if (ch < 'a' || ch > 'z') return false; + return links[ch - 'a'] != null; + } + + public boolean isEmpty() { + for (TrieNode n : links) { + if (n != null) { + return false; + } + } + + return true; + } + + } + +} \ No newline at end of file diff --git a/Week 06/id_716/LeetCode_212_716.java b/Week 06/id_716/LeetCode_212_716.java new file mode 100644 index 000000000..c3b7f8674 --- /dev/null +++ b/Week 06/id_716/LeetCode_212_716.java @@ -0,0 +1,158 @@ +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class LeetCode_212_716 { + private int rows; + private int cols; + private int[] dx = new int[]{-1, 1, 0, 0}; + private int[] dy = new int[]{0, 0, -1, 1}; + + public List findWords(char[][] board, String[] words) { + Set res = new HashSet<>(); + rows = board.length; + cols = rows > 0 ? board[0].length : 0; + + // 将 words 构建一个 Trie + Trie trie = new Trie(); + for (String word : words) { + trie.insert(word); + } + + // dfs + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + dfs(board, trie, row, col, res, ""); + } + } + + return new LinkedList<>(res); + } + + private void dfs(char[][] board, Trie trie, int row, int col, Set res, String s) { + // terminator + if (row < 0 || row >= rows || col < 0 || col >= cols) return; + + String ss = s + board[row][col]; + if (!trie.startsWith(ss)) return; + if (trie.search(ss)) { + res.add(ss); + } + + board[row][col] ^= 256; + + // drill down + for (int i = 0; i < dx.length; i++) { + // if (row + dx[i] >= 0 && row + dx[i] < rows && col + dy[i] >= 0 && col + dy[i] < cols) + dfs(board, trie, row + dx[i], col + dy[i], res, ss); + } + + board[row][col] ^= 256; + } + + class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + + TrieNode p = root; + for (Character c : word.toCharArray()) { + if (!p.containsKey(c)) { + p.put(c, new TrieNode()); + } + p = p.get(c); + } + p.setEnd(); + + } + + private TrieNode searchPrefix(String word) { + TrieNode p = root; + for (Character c : word.toCharArray()) { + if (!p.containsKey(c)) { + return null; + } + + p = p.get(c); + } + + return p; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode p = searchPrefix(word); + return p != null && p.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode p = searchPrefix(prefix); + return p != null; + } + } + + class TrieNode { + + private TrieNode[] links; + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public TrieNode get(int position) { + return links[position]; + } + + public boolean containsKey(char ch) { + if (ch < 'a' || ch > 'z') return false; + return links[ch - 'a'] != null; + } + + public boolean isEmpty() { + for (TrieNode n : links) { + if (n != null) { + return false; + } + } + + return true; + } + + } +} \ No newline at end of file diff --git a/Week 06/id_716/LeetCode_36_716.java b/Week 06/id_716/LeetCode_36_716.java new file mode 100644 index 000000000..be3e6b5ef --- /dev/null +++ b/Week 06/id_716/LeetCode_36_716.java @@ -0,0 +1,82 @@ +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_36_716 { + + // 1. HashMap + public boolean isValidSudoku1(char[][] board) { + @SuppressWarnings("unchecked") Map[] rows = new HashMap[9]; + @SuppressWarnings("unchecked") Map[] cols = new HashMap[9]; + @SuppressWarnings("unchecked") Map[] boxed = new HashMap[9]; + for (int i = 0; i < 9; i++) { + rows[i] = new HashMap<>(); + cols[i] = new HashMap<>(); + boxed[i] = new HashMap<>(); + } + + // search the board + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + if (num != '.') { + int numN = (int) num; + int boxIdx = (i / 3) * 3 + j / 3; + + rows[i].put(numN, rows[i].getOrDefault(numN, 0) + 1); + cols[j].put(numN, cols[j].getOrDefault(numN, 0) + 1); + boxed[boxIdx].put(numN, boxed[boxIdx].getOrDefault(numN, 0) + 1); + + if (rows[i].get(numN) > 1 || cols[j].get(numN) > 1 || boxed[boxIdx].get(numN) > 1) + return false; + } + } + } + + return true; + } + + // 2. Bit + public boolean isValidSudoku2(char[][] board) { + + for (int i = 0; i < 9; i++) { + int row = 0, col = 0, sqre = 0; + for (int j = 0; j < 9; j++) { + int r = board[i][j] - 48, + c = board[j][i] - 48, + s = board[3 * (i / 3) + j / 3][3 * (i % 3) + j % 3] - 48; + + if (r > 0) row = sodokuer(r, row); + if (c > 0) col = sodokuer(c, col); + if (s > 0) sqre = sodokuer(s, sqre); + if (row == -1 || col == -1 || sqre == -1) return false; + } + } + return true; + } + + private int sodokuer(int n, int val) { + return ((val >> n) & 1) == 1 ? -1 : val ^ (1 << n); + } + + // 3 + public boolean isValidSudoku3(char[][] board) { + int[] row = new int[9]; + int[] col = new int[9]; + int[] box = new int[9]; + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] != '.') { + int value = (1 << (board[i][j] - '1')); + int index = (i / 3) * 3 + j / 3; + if ((value & row[i]) > 0 || (value & col[j]) > 0 || (value & box[index]) > 0) { + return false; + } + row[i] |= value; + col[j] |= value; + box[index] |= value; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 06/id_716/LeetCode_547_716.java b/Week 06/id_716/LeetCode_547_716.java new file mode 100644 index 000000000..06a037c47 --- /dev/null +++ b/Week 06/id_716/LeetCode_547_716.java @@ -0,0 +1,87 @@ +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_547_716 { + // 1. dfs + public int findCircleNum1(int[][] M) { + int circles = 0; + int[] visited = new int[M.length]; + + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + circles++; + } + } + return circles; + } + + private void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + // 2. dfs + public int findCircleNum2(int[][] M) { + int circles = 0; + Queue queue = new LinkedList<>(); + int[] visited = new int[M.length]; + + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + queue.offer(i); + while (!queue.isEmpty()) { + int s = queue.poll(); + visited[s] = 1; + for (int j = 0; j < M.length; j++) { + if (M[s][j] == 1 && visited[j] == 0) + queue.offer(j); + } + } + circles++; + } + } + + return circles; + } + + private int circles; + // 3. disjoint set + public int findCircleNum3(int[][] M) { + circles = M.length; + int[] parent = new int[M.length]; + for (int i = 0; i < M.length; i++) { + parent[i] = i; + } + + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + + return circles; + } + + private int find(int[] parent, int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + private void union(int[] parent, int p, int q) { + int rootP = find(parent, p); + int rootQ = find(parent, q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + circles--; + } +} \ No newline at end of file diff --git a/Week 06/id_716/NOTE.md b/Week 06/id_716/NOTE.md index a6321d6e2..e286fbab4 100644 --- a/Week 06/id_716/NOTE.md +++ b/Week 06/id_716/NOTE.md @@ -1,4 +1,116 @@ # NOTE - +## 笔记 +### 字典树 Trie + +Trie 是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。 + +题目和作业 + +- Tire 树代码模板 +- (done) +- (done) +- 分析单词搜索 2 用 Tire 树方式实现的时间复杂度,请同学们提交在第 6 周的学习总结中。 + +### 并查集 Disjoint Set + +将 n 个不同的元素分成一组不相交的集合,同时需要两种特别的操作:寻找包含指定元素的唯一集合和合并两个集合。并查集就是这样一种数据结构,基本操作如下: + +1. makeSet(s): 建立一个新的并查集,其中包含s个单元素集合 +2. unionSet(s1,s2): 把元素x和元素y所在的集合合并,要求x和y所在的集合不合并,如果相交则不合并 +3. find(x): 找到x所在集合的代表,该操作也用来判断两个元素是否位于同一集合,只要比较他们各自的代表 + +题目: + +- (done) +- (done) +- (done) + +### 高级搜索算法 + +高级搜索由初级搜索演化而来,最容易想到的是暴力搜索,也是最简单的,所谓暴力就是穷举所有可能;在此基础之上,在特定的子问题上做优化,比如对重复子问题记忆化、对不满足的情况提前剪枝;此外,在不同方向上的搜索策略,又可以抽象为深度优先和广度优先,这两种算法都可以做到将所有节点都搜索完毕。以上这些都可以总结为基本的搜索算法,是比较不智能的;那么更加聪明的搜索是在子问题的选择上做优化,更加符合解的趋势。 + +- 剪枝 +- 双向 BFS +- A* 启发式搜索 + +题目: + +- (done) +- (done) +- +- (done) +- +- +- +- +- + +## 总结 + +本周是第六周了,悄悄的接近了尾声。本周重点围绕字典树、并查集、剪枝搜索、双向BFS和启发式搜索等进行了学习,每部分都有了不同的收获。 + +### 字典树 + +又叫 `Trie`,是一种树形结构。同时它还是一种专门用来处理字符串匹配的数据结构,在一组字符串集合中快速查找某个字符串。比较典型的应用是搜索引擎的搜索关键词提示。通过观察 Trie,我们能理解它的本质是利用字符串之间的公共前缀,将重复的前缀合并在一起。 + +学习 Trie,重点需要掌握以下几点: + +- 如何存储 Trie? + +Trie 的实现是将字符串进行分割,分成可识别的字符,将这些字符构造成一个树形结构,所以我们需要首先限定字符范围,我们暂时只考虑26个英文字母,如果考虑中文字符等,范围就更加广了。 + +```java +// 典型的 Trie 树的节点的框架 +class TrieNode { + char data; + TrieNode[] links = new TrieNode[26]; +} +``` + +说明 Trie 的每个节点都包含 26 个 TrieNode. + +- Trie 的常见操作 + +Trie 需要做的主要操作有两个:根据关键词库构建一个 Trie和从给定的 Trie 中查找一个字符串 + +```java +public void insert(char[] text); +// or +public void insert(String word); + +public boolean search(String word); +// or +public boolean startsWith(String word); +``` + +我们需要根据关键词的词库动态构建一颗 Trie 树,构建的时间复杂度是 O(n), n 是所有关键词的长度和。 +对于查找操作,时间复杂度是 O(k), k 是要查找单词的长度。 + +在构建 Trie 时,我们使用了一个数组来表示一个节点,这样会有点浪费内存,但是查询效率会很高,一种空间换时间的思路。但是我们可以对 Trie 的节点做优化,比如使用有序数组、跳表、散列表、红黑树等,以提高内存使用。 + +- Trie 的特点与限制 + +1. 字符串包含的字符集不能太大,否则内存占用会迅速膨胀。 +2. 要求字符串的前缀重合比较多,不然空间消耗会变大很多。 +3. 要实现一个 Trie,需要满足工程化的要求,不是一件容易的事情。 +4. Trie 是用指针的方式将数据串联起来的,对缓存不友好(因为数据存取是按页的) + +Trie 树不适合精确匹配查找,这种问题更适合用散列表或者红黑树来解决。Trie 树比较适合的是查找前缀匹配的字符串,比如关键词提示。 + +### 并查集 + +Disjoint Set,将 n 个不同的元素分成一组不相交的集合,同时需要两种特别的操作:寻找包含指定元素的唯一集合和合并两个集合。并查集就是这样一种数据结构,基本操作如下: + +1. makeSet(s): 建立一个新的并查集,其中包含s个单元素集合 +2. unionSet(s1,s2): 把元素x和元素y所在的集合合并,要求x和y所在的集合不合并,如果相交则不合并 +3. find(x): 找到x所在集合的代表,该操作也用来判断两个元素是否位于同一集合,只要比较他们各自的代表 + +非常典型的题目是:朋友圈个数、岛屿数量以及被围绕的区域等。 + +### 高级搜索 + +高级搜索由初级搜索演化而来,最容易想到的是暴力搜索,也是最简单的,所谓暴力就是穷举所有可能;在此基础之上,在特定的子问题上做优化,比如对重复子问题记忆化、对不满足的情况提前剪枝;此外,在不同方向上的搜索策略,又可以抽象为深度优先和广度优先,这两种算法都可以做到将所有节点都搜索完毕。以上这些都可以总结为基本的搜索算法,是比较不智能的;那么更加聪明的搜索是在子问题的选择上做优化,更加符合解的趋势。 + +对于图和图相关的算法会再做个更加深入的总结,以及实现一些比较常用的功能。 diff --git a/Week 06/id_721/LeetCode_212_721.java b/Week 06/id_721/LeetCode_212_721.java new file mode 100644 index 000000000..f31261a6e --- /dev/null +++ b/Week 06/id_721/LeetCode_212_721.java @@ -0,0 +1,92 @@ +package tree; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 思路: + * 1. 暴力循环:遍历每个words中的word,将word中的每个字符,拿到board中去进行4连通法则匹配,即匹配上下左右字符,看能否一直找到最后一个字符 + * 2. 利用字典树(Tires): 利用words构建字段树,再将board中的每个字符,按照4连通法则,去tries中去找单词,如果能找到单词,说明该单词在board中 + * + * @date 2019/11/23 11:54 PM + */ +public class LeetCode_212_721 { + + private TrieNode root; + + public LeetCode_212_721() { + root = new TrieNode(); + } + + public List findWords(char[][] board, String[] words) { + // build tries + buildTries(words); + int rows = board.length; + int column = board[0].length; + boolean[][] visited = new boolean[rows][column]; + Set result = new HashSet<>(); + // 递归遍历每个字符的4连通字符,是否在目标搜索树中 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < column; j++) { + TrieNode node = root; + findRecur(board, visited, i, j, rows, column, result, node); + } + } + return new LinkedList<>(result); + } + + private void findRecur(char[][] board, boolean[][] visited, int i, int j, int rows, int column, Set result, TrieNode cur) { + // terminator + if (i >= rows || j >= column || i < 0 || j < 0 || visited[i][j]) { + return; + } + // process current level + cur = cur.child[board[i][j] - 'a']; + visited[i][j] = true; + if (null == cur) { + visited[i][j] = false; + return; + } + if (cur.isLeaf) { + result.add(cur.val); + } + + // drill down + findRecur(board, visited, i + 1, j, rows, column, result, cur); + findRecur(board, visited, i, j + 1, rows, column, result, cur); + findRecur(board, visited, i - 1, j, rows, column, result, cur); + findRecur(board, visited, i, j - 1, rows, column, result, cur); + // reset status 最后要回退,因为下一个起点可能会用到上一个起点的字符 + visited[i][j] = false; + + } + + private void buildTries(String[] words) { + for (String word : words) { + TrieNode node = root; + for (char ch : word.toCharArray()) { + if (node.child[ch - 'a'] == null) { + node.child[ch - 'a'] = new TrieNode(); + } + node = node.child[ch - 'a']; + } + node.isLeaf = true; + node.val = word; + + } + } + + class TrieNode { + public String val; + public TrieNode[] child = new TrieNode[26]; + public boolean isLeaf = false; + + TrieNode() { + + } + } + + +} diff --git a/Week 06/id_721/LeetCode_547_721.java b/Week 06/id_721/LeetCode_547_721.java new file mode 100644 index 000000000..5a7524712 --- /dev/null +++ b/Week 06/id_721/LeetCode_547_721.java @@ -0,0 +1,84 @@ +package tree; + +/** + * 题意:一个n*n的数组M,n代表一个班级的学生数, + * M每个数字表示第i个学生和第j个学生是否为朋友关系,并且朋友关系可以传导; + * 求这个M数组中,有多少个朋友圈 + *

+ * 思路: + * + * @date 2019/11/24 1:56 PM + */ +public class LeetCode_547_721 { + + /** + * 深度优先 + */ + public int findCircleNumDFS(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + + private void dfs(int[][] m, int[] visited, int i) { + for (int j = 0; j < m.length; j++) { + if (m[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(m, visited, j); + } + } + } + + + /** + * 并查集 + */ + public int findCircleNumUnion(int[][] M) { + int n = M.length; + // 创建并查集 + UnionFind uf = new UnionFind(n); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + // 如果i和j是朋友关系,就合并i、j + if (M[i][j] == 1) + uf.union(i, j); + } + } + return uf.count; + } + + class UnionFind { + private int count = 0; + private int[] parent; + + public UnionFind(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + } +} diff --git a/Week 06/id_731/LeetCode_127_731.txt b/Week 06/id_731/LeetCode_127_731.txt new file mode 100644 index 000000000..061db1abf --- /dev/null +++ b/Week 06/id_731/LeetCode_127_731.txt @@ -0,0 +1,38 @@ +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + # ȸwordListбеȥ + word_set = set(wordList) + # 嵱ǰĵʼΪbeginWord + cur_word = [beginWord] + # һĵʼ + next_word = [] + # beginWord endWord תеij + depth = 1 + while cur_word: + for word in cur_word: + # endWordڵǰcur_wordʼУظ + if word == endWord: + return depth + for index in range(len(word)): + for indice in "abcdefghijklmnopqrstuvwxyz": + new_word = word[:index]+indice+word[index+1:] + if new_word in word_set: + word_set.remove(new_word) + next_word.append(new_word) + # endWordδڵǰcur_wordʼУ+1 + depth += 1 + cur_word = next_word + next_word = [] + return 0 + +if __name__ == "__main__": + beginWord = "hit" + endWord = "cog" + wordList = ["hot","dot","dog","lot","log","cog"] + sequence_length = Solution().ladderLength(beginWord, endWord, wordList) \ No newline at end of file diff --git a/Week 06/id_731/LeetCode_212_731.txt b/Week 06/id_731/LeetCode_212_731.txt new file mode 100644 index 000000000..2a43dfc19 --- /dev/null +++ b/Week 06/id_731/LeetCode_212_731.txt @@ -0,0 +1,63 @@ +struct Node { + bool word; + string str; + unordered_map words; +}; +class Trie { +public: + Trie() { + root = new Node(); + } + void insert(string word) { + Node* p = root; + for (char c: word) { + if (p->words.find(c) == p->words.end()) { + Node* t = new Node(); + p->words[c] = t; + } + p = p->words[c]; + } + p->str = word; // nodeӦwordΪ֮nodeҵ + p->word = true; + } + void search(vector& res, vector>& board) { + for (int i = 0; i < board.size(); i++) { + for (int j = 0; j < board[i].size(); j++) { + help(res, board, root, i, j); + } + } + } + void help(vector&res, vector>& board, Node* p, int x, int y) { + if (p->word) { + p->word = false; // ͲٰѴ𰸷Žȥ + res.push_back(p->str); + return; + } + if (x < 0 || x == board.size() || y < 0 || y == board[x].size()) return; + if (p->words.find(board[x][y]) == p->words.end()) return; + p = p->words[board[x][y]]; // ʱpַ + char cur = board[x][y]; + board[x][y] = '#'; + help(res, board, p, x+1, y); + help(res, board, p, x-1, y); + help(res, board, p, x, y+1); + help(res, board, p, x, y-1); + board[x][y] = cur; + } + +private: + Node* root; +}; +class Solution { +public: + vector findWords(vector>& board, vector& words) { + Trie trie; + vector res; + for (string& w: words) { + trie.insert(w); + } + trie.search(res, board); + return res; + + } +}; diff --git "a/Week 06/id_756/[130]\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" "b/Week 06/id_756/[130]\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" new file mode 100644 index 000000000..addbcd7e2 --- /dev/null +++ "b/Week 06/id_756/[130]\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" @@ -0,0 +1,37 @@ +class Solution { + public void solve(char[][] board) { + if (board == null || board.length == 0) return; + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1; + if (isEdge && board[i][j] == 'O') { + dfs(board, i, j); + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + if (board[i][j] == '#') { + board[i][j] = 'O'; + } + } + } + } + + public void dfs(char[][] board, int i, int j) { + if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') { + return; + } + board[i][j] = '#'; + dfs(board, i - 1, j); + dfs(board, i + 1, j); + dfs(board, i, j - 1); + dfs(board, i, j + 1); + } +} \ No newline at end of file diff --git "a/Week 06/id_756/[547] \346\234\213\345\217\213\345\234\210.java" "b/Week 06/id_756/[547] \346\234\213\345\217\213\345\234\210.java" new file mode 100644 index 000000000..3e3e09bd7 --- /dev/null +++ "b/Week 06/id_756/[547] \346\234\213\345\217\213\345\234\210.java" @@ -0,0 +1,31 @@ +public class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 06/id_766/LeetCode_312_766.py b/Week 06/id_766/LeetCode_312_766.py new file mode 100644 index 000000000..63aa9f272 --- /dev/null +++ b/Week 06/id_766/LeetCode_312_766.py @@ -0,0 +1,21 @@ +# +# @lc app=leetcode.cn id=312 lang=python3 +# +# [312] 戳气球 +# + +# @lc code=start +class Solution: + def maxCoins(self, nums: List[int]) -> int: + nums = [1] + nums + [1] + n = len(nums) + dp = [[0] * n for _ in range(n)] + for k in range(2, n): + for i in range(n - k): + j = i + k + for t in range(i + 1, j): + dp[i][j] = max(dp[i][j], nums[i] * nums[t] * nums[j] + dp[i][t] + dp[t][j]) + return dp[0][n - 1] + +# @lc code=end + diff --git a/Week 06/id_766/LeetCode_32_766.java b/Week 06/id_766/LeetCode_32_766.java new file mode 100644 index 000000000..c6780b527 --- /dev/null +++ b/Week 06/id_766/LeetCode_32_766.java @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=32 lang=java + * + * [32] 最长有效括号 + */ + +// @lc code=start +class Solution { + public int longestValidParentheses(String s) { + if (s == null || s.length() == 0) return 0; + int[] dp = new int[s.length()]; + int res = 0; + for (int i = 0; i < s.length(); i++) { + if (i > 0 && s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i - 2 >= 0 ? dp[i - 2] + 2 : 2); + } else if (s.charAt(i - 1) == ')' && i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0); + } + } + res = Math.max(res, dp[i]); + } + return res; + } +} + + + + + + + +// @lc code=end + diff --git a/Week 06/id_766/LeetCode_647_766.py b/Week 06/id_766/LeetCode_647_766.py new file mode 100644 index 000000000..1738c59b7 --- /dev/null +++ b/Week 06/id_766/LeetCode_647_766.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode.cn id=647 lang=python3 +# +# [647] 回文子串 +# + +# @lc code=start +class Solution: + def countSubstrings(self, s: str) -> int: + counts, count = [], 1 + for i in range(len(s)-1): + if s[i] == s[i+1]: + count += 1 + else: + counts.append((s[i], count)) + count = 1 + counts.append((s[-1], count)) + res = 0 + for i in range(len(counts)): + res += counts[i][1]*(counts[i][1]+1)//2 + + j = 1 + while i-j >= 0 and i+j < len(counts): + left, right = counts[i-j], counts[i+j] + if left[0] == right[0]: + if left[1] != right[1]: + res += min(left[1], right[1]) + break + else: + res += left[1] + j += 1 + else: + break + return res + +# @lc code=end + diff --git a/Week 06/id_766/LeetCode_72_766.java b/Week 06/id_766/LeetCode_72_766.java new file mode 100644 index 000000000..c09116666 --- /dev/null +++ b/Week 06/id_766/LeetCode_72_766.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=72 lang=java + * + * [72] 编辑距离 + */ + +// @lc code=start +class Solution { + public int minDistance(String word1, String word2) { + int n1 = word1.length(); + int n2 = word2.length(); + int[][] dp = new int[n1 + 1][n2 + 1]; + for (int j = 1; j <= n2; j++) dp[0][j] = dp[0][j -1] + 1; + for (int i = 1; i <= n1; i++) dp[i][0] =dp[i - 1][0] + 1; + + + for (int i = 1; i <= n1; i++) { + for (int j = 1; j <=n2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1]; + else dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; + } + + } + return dp[n1][n2]; + + } +} +// @lc code=end + diff --git a/Week 07/id_006/LeetCode_1122_006.java b/Week 07/id_006/LeetCode_1122_006.java new file mode 100644 index 000000000..3fa026968 --- /dev/null +++ b/Week 07/id_006/LeetCode_1122_006.java @@ -0,0 +1,56 @@ +package com.mrglint.leetcode.week07.solution1122; + +import java.util.Arrays; + +/** + * @author luhuancheng + * @since 2019-11-28 21:34 + */ +public class Solution { + /** + * 1. 开辟1001大小的数组空间,记为cache + * 2. 遍历arr1,进行计数 + * 3. 遍历arr2,作为索引到cache中获取值 + * @param arr1 + * @param arr2 + * @return + */ + public int[] relativeSortArray(int[] arr1, int[] arr2) { + if (arr1.length == 0) { + return arr1; + } + int[] cache = new int[Arrays.stream(arr1).max().getAsInt() + 1]; + for (int i : arr1) { + cache[i]++; + } + int[] res = new int[arr1.length]; + int index = 0; + // arr2的顺序 + for (int i : arr2) { + while (cache[i] > 0) { + res[index++] = i; + cache[i]--; + } + cache[i] = 0; + } + + // 剩余的arr1,需要由小到大排列 + for (int i = 0; i < cache.length; i++) { + while (cache[i] > 0) { + res[index++] = i; + cache[i]--; + } + } + return res; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + int[] ints = solution.relativeSortArray(new int[]{28, 6, 22, 8, 44, 17}, new int[]{22, 28, 8, 6}); + System.out.println(Arrays.toString(ints)); + } + + + +} + diff --git a/Week 07/id_006/LeetCode_146_006.java b/Week 07/id_006/LeetCode_146_006.java new file mode 100644 index 000000000..5ffd881d9 --- /dev/null +++ b/Week 07/id_006/LeetCode_146_006.java @@ -0,0 +1,123 @@ +package com.mrglint.leetcode.week07.solution146; + +import java.util.HashMap; +import java.util.Map; + +/** + * 使用双向链表和哈希表实现 + * + * @author luhuancheng + * @since 2019-11-27 23:04 + */ +public class LRUCache { + + private static class DoubleList { + private static class Node { + int key; + int value; + Node prev, next; + + Node(int key, int value) { + this.key = key; + this.value = value; + } + } + + private Node head, tail; + private int size; + + DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + } + + /** + * 加入链表头部 + * @param x + */ + void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size++; + } + + /** + * 删除指定节点 + * @param x + */ + void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size--; + } + + /** + * 删除最后一个节点 + * @return + */ + Node removeLast() { + if (tail.prev == head) { + return null; + } + Node last = tail.prev; + remove(last); + return last; + } + } + + + private int capacity; + private Map map; + private DoubleList cache; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.map = new HashMap<>(); + cache = new DoubleList(); + } + + /** + * 从哈希表中获取链表节点:Node , + * 从链表中删除该节点,放入链表头部 + * @param key + * @return + */ + public int get(int key) { + if (!map.containsKey(key)) { + return -1; + } + int value = map.get(key).value; + put(key, value); + return value; + } + + /** + * 判断链表是否达到capacity大小,达到了则删除最后一个节点之后,放入新节点 + * @param key + * @param value + */ + public void put(int key, int value) { + DoubleList.Node node = new DoubleList.Node(key, value); + if (map.containsKey(key)) { + // 删除旧节点 + cache.remove(map.get(key)); + // 添加新节点 + cache.addFirst(node); + map.put(key, node); + } else { + // 淘汰最后一个节点 + if (capacity == cache.size) { + DoubleList.Node last = cache.removeLast(); + map.remove(last.key); + } + map.put(key, node); + cache.addFirst(node); + } + } + +} + diff --git a/Week 07/id_006/LeetCode_190_006.java b/Week 07/id_006/LeetCode_190_006.java new file mode 100644 index 000000000..604815ba0 --- /dev/null +++ b/Week 07/id_006/LeetCode_190_006.java @@ -0,0 +1,38 @@ +package com.mrglint.leetcode.week07.solution190; + +/** + * @author luhuancheng + * @since 2019-11-25 08:42 + */ +public class Solution { + + public int reverseBits1(int n) { + int result = 0; + for (int i = 0; i < 32; i++) { + // result << 1左移一位,为补上来的n的最后一位留出空间 + result = (result << 1) + (n & 1); + // n >> 1 右移一位,将下一次要补上到result最后一位的值,移动到n的最后一位,下一次循环通过 n & 1获得 + n = n >> 1; + } + return result; + } + + /** + * 循环32次 + * 1. 空出一位 + * 2. 空出的一位置换为n的最后一位 + * 3. n的最后一位替换为倒数第二位 + * @param n + * @return + */ + public int reverseBits(int n) { + int result = 0; + for (int i = 0; i < 32; i++) { + result <<= 1; + result |= n & 1; + n >>= 1; + } + return result; + } +} + diff --git a/Week 07/id_006/LeetCode_191_006.java b/Week 07/id_006/LeetCode_191_006.java new file mode 100644 index 000000000..e37e2b3e5 --- /dev/null +++ b/Week 07/id_006/LeetCode_191_006.java @@ -0,0 +1,27 @@ +package com.mrglint.leetcode.week07.solution191; + +/** + * @author luhuancheng + * @since 2019-11-25 08:07 + */ +public class Solution { + + /** + * 二进制表示: + * 11000 - 1 = 10111 + * 11000 & 10111 = 10000 打掉了一个1, + * 循环这两步操作,并记录循环次数。直到值为0,循环次数即为1的个数 + * + * @param n + * @return + */ + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + n = n & (n - 1); + count++; + } + return count; + } +} + diff --git a/Week 07/id_006/LeetCode_231_006.java b/Week 07/id_006/LeetCode_231_006.java new file mode 100644 index 000000000..e148a0e8b --- /dev/null +++ b/Week 07/id_006/LeetCode_231_006.java @@ -0,0 +1,12 @@ +package com.mrglint.leetcode.week07.solution231; + +/** + * @author luhuancheng + * @since 2019-11-25 08:36 + */ +public class Solution { + public boolean isPowerOfTwo(int n) { + return n != 0 && (n & (n - 1)) == 0; + } +} + diff --git a/Week 07/id_006/LeetCode_242_006.java b/Week 07/id_006/LeetCode_242_006.java new file mode 100644 index 000000000..b1e960f6e --- /dev/null +++ b/Week 07/id_006/LeetCode_242_006.java @@ -0,0 +1,25 @@ +package com.mrglint.leetcode.week07.solution242; + +/** + * @author luhuancheng + * @since 2019-11-28 22:21 + */ +public class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] cache = new int[26]; + for (char c : s.toCharArray()) { + cache[c - 'a']++; + } + for (char c : t.toCharArray()) { + cache[c - 'a']--; + if (cache[c - 'a'] < 0) { + return false; + } + } + return true; + } +} + diff --git a/Week 07/id_006/LeetCode_338_006.java b/Week 07/id_006/LeetCode_338_006.java new file mode 100644 index 000000000..912c33dde --- /dev/null +++ b/Week 07/id_006/LeetCode_338_006.java @@ -0,0 +1,95 @@ +package com.mrglint.leetcode.week07.solution338; + +/** + * @author luhuancheng + * @since 2019-11-27 07:50 + */ +public class Solution { + /** + * pop count 解法 + * @param num + * @return + */ + public int[] countBits1(int num) { + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + res[i] = popCount(i); + } + return res; + } + private int popCount(int i) { + int count = 0; + while (i > 0) { + i = i & (i - 1); + count++; + } + return count; + } + + /** + * DP解法 最高有效位 + * @param num + * @return + */ + public int[] countBits2(int num) { + // 0 0000 + // 1 0001 + // 2 0010 + // 3 0011 + // 4 0100 + // 5 0101 + // 6 0110 + // 7 0111 + // 8 1000 + // 9 1001 + // 10 1010 + // 11 1011 + // 12 1100 + // 13 1101 + // 14 1110 + // 15 1111 + + // [0, 1] -> [2, 3] + // [0, 3] -> [4, 7] + // [0, 7] -> [8, 15] + + // 动态转移方程:f(x + b) = f(x) + 1; b = 2^m; + int[] res = new int[num + 1]; + // 定义状态 + int i = 0; + int b = 1; + // 动态推导 + while (b <= num) { + // b = 2 ^ m <= num + while (i < b && i + b <= num) { + res[i + b] = res[i] + 1; + i++; + } + i = 0; + b <<= 1; + } + return res; + } + + public int[] countBits3(int num) { + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } + + public int[] countBits(int num) { + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i & (i - 1)] + 1; + } + return res; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + solution.countBits(4); + } +} + diff --git a/Week 07/id_006/LeetCode_493_006.java b/Week 07/id_006/LeetCode_493_006.java new file mode 100644 index 000000000..1582d69f4 --- /dev/null +++ b/Week 07/id_006/LeetCode_493_006.java @@ -0,0 +1,59 @@ +package com.mrglint.leetcode.week07.solution493; + +/** + * @author luhuancheng + * @since 2019-11-29 07:59 + */ +public class Solution { + private int count = 0; + + public int reversePairs(int[] nums) { + mergeSort(0, nums.length - 1, nums); + return count; + } + + private void mergeSort(int lo, int hi, int[] nums) { + if (lo >= hi) { + return; + } + int mid = lo + ((hi - lo) >> 1); + mergeSort(lo, mid, nums); + mergeSort(mid + 1, hi, nums); + merge(lo, mid, hi, nums); + } + + private void merge(int lo, int mid, int hi, int[] nums) { + // 统计 nums[i] > 2 * nums[j]; j ∈ [mid + 1, hi] 的个数 + for (int m = lo; m <= mid; m++) { + int n = mid + 1; + while (n <= hi && nums[m] > (long) 2 * nums[n]) { + n++; + } + count += n - (mid + 1); + } + + int i = lo; + int j = mid + 1; + int k = 0; + + // 临时数组 + int[] temp = new int[hi - lo + 1]; + while (i <= mid && j <= hi) { + if (nums[i] <= nums[j]) { + temp[k++] = nums[i++]; + } else { + temp[k++] = nums[j++]; + } + } + while (i <= mid) { + temp[k++] = nums[i++]; + } + while (j <= hi) { + temp[k++] = nums[j++]; + } + + // 拷贝回原数组 + System.arraycopy(temp, 0, nums, lo, hi - lo + 1); + } +} + diff --git a/Week 07/id_006/LeetCode_52_006.java b/Week 07/id_006/LeetCode_52_006.java new file mode 100644 index 000000000..9fb471946 --- /dev/null +++ b/Week 07/id_006/LeetCode_52_006.java @@ -0,0 +1,75 @@ +package com.mrglint.leetcode.week07.solution52; + +/** + * 使用一个32位的int来标记 + * + * @author luhuancheng + * @since 2019-11-26 08:49 + */ +public class Solution { + + private int size; + private int count; + + public int totalNQueens(int n) { + count = 0; + size = ( 1 << n) - 1; + solve(0, 0, 0); + return count; + } + + private void solve(int row, int ld, int rd) { + if (row == size) { + count++; + return; + } + int pos = size & (~(row | ld | rd)); + + while (pos != 0) { + int p = pos & (-pos); + pos -= p; + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + private String toBinaryRepresent(int n) { + int[] buffer = new int[32]; + for (int i = 0; i < 32; i++) { + buffer[31 - i] = n & 1; + n = n >> 1; + } + StringBuilder res = new StringBuilder(); + for (int i : buffer) { + res.append(i); + } + return res.toString(); + } + + public static void main(String[] args) { + Solution solution = new Solution(); + int res = solution.totalNQueens(4); + System.out.println(res); + // 原码:00000000000000000000000000000100 + // 反码:00000000000000000000000000000100 + // 补码:00000000000000000000000000000100 + // int input = 4; + + // 原码:10000000000000000000000000000100 最高位作为符号位,置为1 + // 反码:11111111111111111111111111111011 符号位不变,其余位取反 + // 补码:11111111111111111111111111111100 在反码的基础上加1 +// int input = 4 & -4; +// input = 4 - input; +// int[] buffer = new int[32]; +// for (int i = 0; i < 32; i++) { +// buffer[31 - i] = input & 1; +// input = input >> 1; +// } +// StringBuilder res = new StringBuilder(); +// for (int i : buffer) { +// res.append(i); +// } +// System.out.println(res.toString()); + } + +} + diff --git a/Week 07/id_006/LeetCode_56_006.java b/Week 07/id_006/LeetCode_56_006.java new file mode 100644 index 000000000..dd0497701 --- /dev/null +++ b/Week 07/id_006/LeetCode_56_006.java @@ -0,0 +1,28 @@ +package com.mrglint.leetcode.week07.solution56; + +import java.util.*; + +/** + * 1. 先对区间排序 + * 2. 遍历区间,比较结果集中最后一个区间的尾端值是否大于当前区间,大于则合并区间;小于则将当前区间添加到结果集 + * @author luhuancheng + * @since 2019-11-28 22:31 + */ +public class Solution { + public int[][] merge(int[][] intervals) { + LinkedList res = new LinkedList<>(); + // 区间排序 + Arrays.sort(intervals, Comparator.comparingInt(o -> o[0])); + // 遍历区间 + for (int i = 0; i < intervals.length; i++) { + if (res.isEmpty() || res.getLast()[1] < intervals[i][0]) { + res.add(intervals[i]); + } else { + // 合并区间,使用两个区间尾端较大值作为合并后的尾端 + res.getLast()[1] = Math.max(res.getLast()[1], intervals[i][1]); + } + } + return res.toArray(new int[0][0]); + } +} + diff --git a/Week 07/id_006/NOTE.md b/Week 07/id_006/NOTE.md index a6321d6e2..348c7ced2 100644 --- a/Week 07/id_006/NOTE.md +++ b/Week 07/id_006/NOTE.md @@ -1,4 +1,177 @@ -# NOTE +# 学习总结 +## 位运算 +关于位运算的应用,起初是在HashMap的源码中学习到的。JDK开发大叔们为了提高性能,使用了2 ^ n作为容器的大小,利用位运算的特性在取模时,可以高效的完成计算。 - +## 布隆过滤器和LRU缓存 +### 布隆过滤器 +利用n次hash算法之后,在哈希桶中设置标志位。在缓存的使用场景中,用于判定一个数据在不在缓存中,假设哈希桶的标志位都为1,那么数据可能存在于缓存中,否则一定不在缓存中需要去DB中获取。 +### LRU缓存 +最近最少使用淘汰机制,利用链表来维护最近最少使用的特征,利用哈希表来达到O(1)复杂度的读取。在Java中,有一个现成的LRU实现类LinkedHashMap,override其removeEldestEntry方法设定淘汰条件即可。 + +## 排序 +归并排序和快速排序都是利用分治思想来实现O(nlogn)的排序算法。 +### 冒泡排序实现 +```java +public class BubbleSort implements SortFunction { + +// @Override +// public void sort(int[] data) { +// for (int i = 0; i < data.length; i++) { +// for (int j = 0; j < data.length - i - 1; j++) { +// if (data[j] > data[j + 1]) { +// swap(data, j, j + 1); +// } +// } +// } +// } + + + /** + * 优化1,如果没有发生交换,说明所有数据都是有序状态,提前终止外层循环 + * @param data + */ +// @Override +// public void sort(int[] data) { +// for (int i = 0; i < data.length; i++) { +// boolean flag = false; +// for (int j = 0; j < data.length - i - 1; j++) { +// if (data[j] > data[j + 1]) { +// swap(data, j, j + 1); +// flag = true; +// } +// } +// if (!flag) { +// break; +// } +// } +// } + + /** + * 优化2,每次记录最后一次交换的位置,可以让内层循环提前结束 + * @param data + */ + @Override + public void sort(int[] data) { + int lastExchange = 0; + int k = data.length - 1; + for (int i = 0; i < data.length - 1; i++) { + boolean flag = false; + for (int j = 0; j < k; j++) { + if (data[j] > data[j + 1]) { + SortUtils.swap(data, j, j + 1); + flag = true; + lastExchange = j; + } + } + k = lastExchange; + if (!flag) { + break; + } + } + } + + public static void main(String[] args) { + int[] data = SortUtils.generateRandomArray(10, 1, 10); + System.out.println(Arrays.toString(data)); + SortUtils.testSort(data, new BubbleSort()); + } +} +``` + +### 插入排序 +插入排序可以用于在小数据量时的排序,其效率甚至高于快速排序和归并排序。 +```java +package com.mrglint.algorithm.sort; + +import java.util.Arrays; + +/** + * @author luhuancheng + * @since 2019-11-30 10:19 + */ +public class InsertSort implements SortFunction { + +// @Override +// public void sort(int[] data) { +// // i表示要插入的元素 +// for (int i = 1; i < data.length; i++) { +// int insertValue = data[i]; +// int j; +// // j表示第一个要比较的元素 +// for (j = i - 1; j >= 0; j--) { +// if (insertValue < data[j]) { +// data[j + 1] = data[j]; +// } else { +// break; +// } +// } +// // 此时分两种情况: +// // 1. j < 0 说明前面没有元素可以比较了,data[0] = insertValue; +// // 2. data[j] <= insertValue 说明此时的data[j]在正确的位置,data[j + 1] 就是要插入的位置 +// data[j + 1] = insertValue; +// } +// } + + @Override + public void sort(int[] data) { + for (int i = 1; i < data.length; i++) { + // 要插入的位置 + int insertIndex; + // 要插入的值 + int insertValue = data[i]; + // 当前一个元素大于要插入的值时,将前一个元素后移一个位置 + for (insertIndex = i; insertIndex > 0 && data[insertIndex - 1] > insertValue; insertIndex--) { + data[insertIndex] = data[insertIndex - 1]; + } + // 移动到第一个元素时、或者 data[insertIndex - 1] <= insertValue, 要插入的位置找到 + data[insertIndex] = insertValue; + } + } + + public static void main(String[] args) { + int[] data = SortUtils.generateNearlyOrderArray(10000, 100); + SortUtils.compareSort(data, Arrays.asList(new SelectSort(), new InsertSort())); + } +} + +``` + +### 选择排序 +```java +package com.mrglint.algorithm.sort; + +/** + * @author luhuancheng + * @since 2019-11-29 22:46 + */ +public class SelectSort implements SortFunction { + + @Override + public void sort(int[] data) { + + for (int i = 0; i < data.length; i++) { + // 寻找[i, data.length)中的最小值索引位置;初始化为i + int minIndex = i; + // 从[i + 1, data.length)中寻找最小值索引位置 + for (int j = i + 1; j < data.length; j++) { + if (data[j] < data[minIndex]) { + minIndex = j; + } + } + int temp = data[i]; + data[i] = data[minIndex]; + data[minIndex] = temp; + } + } + + public static void main(String[] args) { + // 1w : 51ms + // 10w : 4541ms + // O(n ^ 2) + int[] data = SortUtils.generateRandomArray(100000, 1, 100000); + SortUtils.testSort(data, new SelectSort()); + } +} + +``` diff --git a/Week 07/id_011/counting-bits.go b/Week 07/id_011/counting-bits.go new file mode 100644 index 000000000..6503e5063 --- /dev/null +++ b/Week 07/id_011/counting-bits.go @@ -0,0 +1,9 @@ +package algorithm00401 + +func countBits(num int) []int { + ans := make([]int, num+1) + for i := 1; i <= num; i++ { + ans[i] = ans[i>>1] + i&1 + } + return ans +} diff --git a/Week 07/id_011/lru-cache.go b/Week 07/id_011/lru-cache.go new file mode 100644 index 000000000..8b1902eda --- /dev/null +++ b/Week 07/id_011/lru-cache.go @@ -0,0 +1,78 @@ +package algorithm00401 + +type LRUCache struct { + len, cap int + first, last *doubleLinkedList + nodes map[int]*doubleLinkedList +} + +type doubleLinkedList struct { + key, val int + prev, next *doubleLinkedList +} + +func Constructor(capacity int) LRUCache { + return LRUCache{ + cap: capacity, + nodes: make(map[int]*doubleLinkedList, capacity), + } +} + +func (this *LRUCache) Get(key int) int { + if node, ok := this.nodes[key]; ok { + this.moveToFirst(node) + return node.val + } + return -1 +} + +func (this *LRUCache) moveToFirst(node *doubleLinkedList) { + if this.first == node { + return + } else if this.last == node { + this.removeLast() + } else { + node.prev.next = node.next + node.next.prev = node.prev + } + this.addToFirst(node) +} + +func (this *LRUCache) removeLast() { + if this.last.prev != nil { + this.last.prev.next = nil + } else { + this.first = nil + } + this.last = this.last.prev +} + +func (this *LRUCache) addToFirst(node *doubleLinkedList) { + if this.last == nil { + this.last = node + } else { + this.first.prev = node + node.next = this.first + } + this.first = node +} + +func (this *LRUCache) Put(key int, value int) { + if node, ok := this.nodes[key]; ok { + node.val = value + this.moveToFirst(node) + } else { + if this.len == this.cap { + delete(this.nodes, this.last.key) + this.removeLast() + } else { + this.len++ + } + node := &doubleLinkedList{ + key: key, + val: value, + } + this.nodes[key] = node + this.addToFirst(node) + } +} diff --git a/Week 07/id_011/number-of-1-bits.go b/Week 07/id_011/number-of-1-bits.go new file mode 100644 index 000000000..252f263a0 --- /dev/null +++ b/Week 07/id_011/number-of-1-bits.go @@ -0,0 +1,10 @@ +package algorithm00401 + +func hammingWeight(num unint32) int { + sum := 0 + for num != 0 { + sum++ + num &= (num - 1) + } + return sum +} diff --git a/Week 07/id_011/power-of-two.go b/Week 07/id_011/power-of-two.go new file mode 100644 index 000000000..aa6206b40 --- /dev/null +++ b/Week 07/id_011/power-of-two.go @@ -0,0 +1,5 @@ +package algorithm00401 + +func isPowerOfTwo(n int) bool { + return n != 0 && n&(n-1) == 0 +} diff --git a/Week 07/id_011/reverse-bits.go b/Week 07/id_011/reverse-bits.go new file mode 100644 index 000000000..6f84c14d6 --- /dev/null +++ b/Week 07/id_011/reverse-bits.go @@ -0,0 +1,11 @@ +package algorithm00401 + +func reverseBits(num uint32) uint32 { + bits, count := uint32(0), uint32(0) + for count > 0 { + bits |= (nums & 1) << (count - 1) + num >>= 1 + count-- + } + return bits +} diff --git a/Week 07/id_011/valid-anagram.go b/Week 07/id_011/valid-anagram.go new file mode 100644 index 000000000..66d20b3fe --- /dev/null +++ b/Week 07/id_011/valid-anagram.go @@ -0,0 +1,22 @@ +package algorithm00401 + +func isAnagram(s string, t string) bool { + if len(s) != len(t) { + return false + } + sr := []rune(s) + tr := []rune(t) + + counter := make([]rune, 26, 26) + for i := 0; i < len(sr); i++ { + counter[sr[i]-'a']++ + counter[tr[i]-'a']-- + } + + for i := 0; i < len(counter); i++ { + if counter[i] != 0 { + return false + } + } + return true +} diff --git a/Week 07/id_016/LeetCode_1122_016.js b/Week 07/id_016/LeetCode_1122_016.js new file mode 100644 index 000000000..0f3fa816e --- /dev/null +++ b/Week 07/id_016/LeetCode_1122_016.js @@ -0,0 +1,64 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-12-01 18:18:14 + * @LastEditTime: 2019-12-01 18:18:27 + */ +/* + * @lc app=leetcode id=1122 lang=javascript + * + * [1122] Relative Sort Array + * + * https://leetcode.com/problems/relative-sort-array/description/ + * + * algorithms + * Easy (66.19%) + * Likes: 301 + * Dislikes: 22 + * Total Accepted: 30.6K + * Total Submissions: 46K + * Testcase Example: '[2,3,1,3,2,4,6,7,9,2,19]\n[2,1,4,3,9,6]' + * + * Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all + * elements in arr2 are also in arr1. + * + * Sort the elements of arr1 such that the relative ordering of items in arr1 + * are the same as in arr2.  Elements that don't appear in arr2 should be + * placed at the end of arr1 in ascending order. + * + * + * Example 1: + * Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] + * Output: [2,2,2,1,4,3,3,9,6,7,19] + * + * + * Constraints: + * + * + * arr1.length, arr2.length <= 1000 + * 0 <= arr1[i], arr2[i] <= 1000 + * Each arr2[i] is distinct. + * Each arr2[i] is in arr1. + * + * + */ + +// @lc code=start +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ +var relativeSortArray = function(arr1, arr2) { + let res = []; + arr2.map(item => { + let index = arr1.indexOf(item); + while (index > -1) { + res.push(arr1.splice(index, 1)); + index = arr1.indexOf(item); + } + }); + return res.concat(arr1.sort((a, b) => a - b)); +}; +// @lc code=end diff --git a/Week 07/id_016/LeetCode_146_016.js b/Week 07/id_016/LeetCode_146_016.js new file mode 100644 index 000000000..a31fddf8c --- /dev/null +++ b/Week 07/id_016/LeetCode_146_016.js @@ -0,0 +1,102 @@ +/* + * @lc app=leetcode id=146 lang=javascript + * + * [146] LRU Cache + * + * https://leetcode.com/problems/lru-cache/description/ + * + * algorithms + * Medium (27.69%) + * Likes: 4035 + * Dislikes: 166 + * Total Accepted: 392K + * Total Submissions: 1.4M + * Testcase Example: '["LRUCache","put","put","get","put","get","put","get","get","get"]\n[[2],[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]' + * + * Design and implement a data structure for Least Recently Used (LRU) cache. + * It should support the following operations: get and put. + * + * get(key) - Get the value (will always be positive) of the key if the key + * exists in the cache, otherwise return -1. + * put(key, value) - Set or insert the value if the key is not already present. + * When the cache reached its capacity, it should invalidate the least recently + * used item before inserting a new item. + * + * The cache is initialized with a positive capacity. + * + * Follow up: + * Could you do both operations in O(1) time complexity? + * + * Example: + * + * + * LRUCache cache = new LRUCache( 2 /* capacity */ ); + * + * cache.put(1, 1); + * cache.put(2, 2); + * cache.get(1); // returns 1 + * cache.put(3, 3); // evicts key 2 + * cache.get(2); // returns -1 (not found) + * cache.put(4, 4); // evicts key 1 + * cache.get(1); // returns -1 (not found) + * cache.get(3); // returns 3 + * cache.get(4); // returns 4 + * + * + * + * + */ + +// @lc code=start +/** + * @param {number} capacity + */ +var LRUCache = function(capacity) { + this.arr = []; + this.map = {}; + this.capacity = capacity +}; + +/** + * @param {number} key + * @return {number} + */ +LRUCache.prototype.get = function(key) { + if(Number.isInteger(this.map[key])){ + let t = this.arr.find(item=>item.key === key); + this.arr = this.arr.filter(item=>item.key !== key); + this.arr.push(t); + return this.map[key] + } + return -1; +}; + +/** + * @param {number} key + * @param {number} value + * @return {void} + */ +LRUCache.prototype.put = function(key, value) { + if(Number.isInteger(this.map[key])){ + this.map[key] = value; + this.arr = this.arr.filter(item=>item.key !== key); + this.arr.push({key,value}) + return; + } + + if(this.arr.length === this.capacity){ + let item = this.arr.shift(); + delete this.map[item.key]; + } + this.arr.push({key,value}); + this.map[key] = value; +}; + +/** + * Your LRUCache object will be instantiated and called as such: + * var obj = new LRUCache(capacity) + * var param_1 = obj.get(key) + * obj.put(key,value) + */ +// @lc code=end + diff --git a/Week 07/id_016/LeetCode_242_016.js b/Week 07/id_016/LeetCode_242_016.js new file mode 100644 index 000000000..f219bbbe2 --- /dev/null +++ b/Week 07/id_016/LeetCode_242_016.js @@ -0,0 +1,75 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-12-01 18:26:22 + * @LastEditTime: 2019-12-01 18:26:28 + */ +/* + * @lc app=leetcode id=242 lang=javascript + * + * [242] Valid Anagram + * + * https://leetcode.com/problems/valid-anagram/description/ + * + * algorithms + * Easy (53.77%) + * Likes: 965 + * Dislikes: 124 + * Total Accepted: 432.4K + * Total Submissions: 796.2K + * Testcase Example: '"anagram"\n"nagaram"' + * + * Given two strings s and t , write a function to determine if t is an anagram + * of s. + * + * Example 1: + * + * + * Input: s = "anagram", t = "nagaram" + * Output: true + * + * + * Example 2: + * + * + * Input: s = "rat", t = "car" + * Output: false + * + * + * Note: + * You may assume the string contains only lowercase alphabets. + * + * Follow up: + * What if the inputs contain unicode characters? How would you adapt your + * solution to such case? + * + */ + +// @lc code=start +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +// var isAnagram = function(s, t) { +// if(s.length!=t.length) return false; +// let temp = t.split(""); +// for(let i = 0; i < s.length; i++){ +// let index = temp.indexOf(s[i]); +// if(index>-1){ +// temp.splice(index,1); +// } +// } +// return !temp.length +// }; + +var isAnagram = function(s, t) { + if(s.length !== t.length) return false; + let ts = s.split("").sort().join(""); + let tt = t.split("").sort().join(""); + + return tt === ts +}; +// @lc code=end + diff --git a/Week 07/id_021/algorithm.zip b/Week 07/id_021/algorithm.zip new file mode 100644 index 000000000..2de353344 Binary files /dev/null and b/Week 07/id_021/algorithm.zip differ diff --git a/Week 07/id_041/LeetCode_52_041.java b/Week 07/id_041/LeetCode_52_041.java new file mode 100644 index 000000000..f81e881a8 --- /dev/null +++ b/Week 07/id_041/LeetCode_52_041.java @@ -0,0 +1,29 @@ +package LeetCode_52_041; + +class Solution { + int count; + int size; + public int totalNQueens(int n) { + count = 0; + size =(1 << n) -1; + solve(0,0,0); + return count; + } + public void solve(int row, int ld,int rd){ + if(row == size){ + count ++; + return; + } + int pos = size & (~ (row | ld | rd)); + while(pos != 0){ + int p = pos & (-pos); + pos -= p; + solve(row | p,(ld | p) << 1,(rd |p)>>1); + } + } + public static void main(String[] args){ + Solution sn = new Solution(); + int result = sn.totalNQueens(4); + System.out.println(result); + } +} \ No newline at end of file diff --git a/Week 07/id_041/LeetCode_56_041.java b/Week 07/id_041/LeetCode_56_041.java new file mode 100644 index 000000000..157b071ca --- /dev/null +++ b/Week 07/id_041/LeetCode_56_041.java @@ -0,0 +1,26 @@ +package LeetCode_56_041; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedList; + +public class Solution { + public int[][] merge(int[][] intervals){ + LinkedList result = new LinkedList<>(); + if(intervals == null || intervals.length == 0) return result.toArray(new int[0][]); + Arrays.sort(intervals,new Comparator(){ + @Override + public int compare(int[] o1,int[]o2) { + return o1[0] - o2[0]; + } + }); + for(int i = 0; i < intervals.length;i++ ){ + if(result.isEmpty() || result.getLast()[1] < intervals[i][0]){ + result.add(intervals[i]); + }else{ + result.getLast()[i] = Math.max(result.getLast()[1],intervals[i][1]); + } + } + return result.toArray(new int[0][0]); + } +} diff --git a/Week 07/id_046/LeetCode_1122_046.java b/Week 07/id_046/LeetCode_1122_046.java new file mode 100644 index 000000000..ff9185fc3 --- /dev/null +++ b/Week 07/id_046/LeetCode_1122_046.java @@ -0,0 +1,29 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int maxValue = arr1[0]; + int[] bucket = new int[1001]; + int[] result = new int[arr1.length]; + for(int i = 0;i < arr1.length;i++){ + if(maxValue < arr1[i]){ + maxValue = arr1[i]; + } + bucket[arr1[i]]++; + } + int idx = 0; + for(int j = 0;j < arr2.length;j++){ + while(bucket[arr2[j]] > 0){ + result[idx] = arr2[j]; + idx++; + bucket[arr2[j]]--; + } + } + for(int left = 0;left <= maxValue;left++){ + while(bucket[left] > 0){ + result[idx] = left; + idx++; + bucket[left]--; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week 07/id_046/LeetCode_231_046.java b/Week 07/id_046/LeetCode_231_046.java new file mode 100644 index 000000000..79b87aaf7 --- /dev/null +++ b/Week 07/id_046/LeetCode_231_046.java @@ -0,0 +1,18 @@ +// 一开始没有考虑负数的情况,只做了模余判断 +class Solution { + public boolean isPowerOfTwo(int n) { + if(n <= 0) return false; + for(;n >= 2;){ + if(n % 2 == 1) return false; + n = n / 2; + } + return true; + } +} + +// 题解学习到的解法,思维值得学习 +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_046/LeetCode_56_046.java b/Week 07/id_046/LeetCode_56_046.java new file mode 100644 index 000000000..71a64c841 --- /dev/null +++ b/Week 07/id_046/LeetCode_56_046.java @@ -0,0 +1,52 @@ +class Solution { + private static class Interval { + int start; + int end; + Interval(int[] interval) { + this.start = interval[0]; + this.end = interval[1]; + } + + int[] toArray() { + return new int[]{this.start, this.end}; + } + } + + private class IntervalComparator implements Comparator { + @Override + public int compare(Interval a, Interval b) { + return a.start < b.start ? -1 : a.start == b.start ? 0 : 1; + } + } + + private List arraytoList(int[][] intervals){ + List listRes = new ArrayList<>(); + for(int i = 0; i< intervals.length; i ++){ + listRes.add(new Interval(intervals[i])); + } + return listRes; + } + + public int[][] merge(int[][] intervals) { + List srcList = arraytoList(intervals); + Collections.sort(srcList,new IntervalComparator()); + + LinkedList merged = new LinkedList(); + for (Interval interval : srcList) { + if (merged.isEmpty() || merged.getLast().end < interval.start) { + merged.add(interval); + } else { + merged.getLast().end = Math.max(merged.getLast().end, interval.end); + } + } + int[][] res = new int[merged.size()][2]; + for(int i = 0;i < merged.size(); i++){ + res[i] = merged.get(i).toArray(); + } + + return res; + + } +} + + diff --git a/Week 07/id_071/LeetCode_1122_071.go b/Week 07/id_071/LeetCode_1122_071.go new file mode 100644 index 000000000..ccf912bc0 --- /dev/null +++ b/Week 07/id_071/LeetCode_1122_071.go @@ -0,0 +1,28 @@ +package week07 + + +//3.1 https://leetcode-cn.com/problems/relative-sort-array/ +func relativeSortArray(arr1 []int, arr2 []int) []int { + + count := make([]int,1001) + result := make([]int, 0, len(arr1)) + + for _,num:=range arr1{ + count[num]++ + } + + for _,num:=range arr2{ + for j:=0; j this.capacity { + this.delNode() + } +} + +func (this *LRUCache) searchNode(key int ) *lruNode { + if this.tail == nil { + return nil + } + + tmp := this.node[hash(key)].hnext + for tmp != nil { + if tmp.key == key { + return tmp + } + tmp = tmp.hnext + } + return nil +} + +func (this *LRUCache) addNode(key int, value int) { + newNode := &lruNode{ + key : key, + value : value, + } + + tmp := &this.node[hash(key)] + newNode.hnext = tmp.hnext + tmp.hnext = newNode + this.used++ + + if this.tail == nil { + this.tail,this.head = newNode,newNode + return + } + this.tail.next = newNode + newNode.prev = this.tail + this.tail = newNode +} + +func (this *LRUCache) delNode(){ + + if this.head == nil { + return + } + + prev := &this.node[hash(this.head.key)] + tmp := prev.hnext + for tmp != nil && tmp.key != this.head.key { + prev = tmp + tmp = tmp.hnext + } + if tmp == nil { + return + } + + prev.hnext = tmp.hnext + this.head = this.head.next + this.head.prev = nil + this.used-- +} + +func (this *LRUCache) moveToTail(node *lruNode){ + if this.tail == node { + return + } + + if this.head == node { + this.head = node.next + this.head.prev = nil + }else { + node.next.prev = node.prev + node.prev.next = node.next + } + + node.next = nil + this.tail.next = node + node.prev = this.tail + + this.tail = node +} + +func hash(key int) int { + + if hostbit { + return (key ^ (key >> 32)) & (LENGTH - 1) + } + + return (key ^ (key >> 16)) & (LENGTH - 1) +} \ No newline at end of file diff --git a/Week 07/id_071/LeetCode_191_071.go b/Week 07/id_071/LeetCode_191_071.go new file mode 100644 index 000000000..09a801003 --- /dev/null +++ b/Week 07/id_071/LeetCode_191_071.go @@ -0,0 +1,13 @@ +package week07 + +// 1.1 https://leetcode-cn.com/problems/number-of-1-bits/ +func hammingWeight(num uint32) int { + + res := 0 + + for num != 0 { + res += int(num % 2) + num /= 2 + } + return res +} \ No newline at end of file diff --git a/Week 07/id_071/LeetCode_231_071.go b/Week 07/id_071/LeetCode_231_071.go new file mode 100644 index 000000000..17425131f --- /dev/null +++ b/Week 07/id_071/LeetCode_231_071.go @@ -0,0 +1,7 @@ +package week07 + +//1.2 https://leetcode-cn.com/problems/power-of-two/ +func isPowerOfTwo(n int) bool { + + return n > 0 && n&(n - 1) == 0 +} \ No newline at end of file diff --git a/Week 07/id_071/NOTE.md b/Week 07/id_071/NOTE.md index a6321d6e2..cac325216 100644 --- a/Week 07/id_071/NOTE.md +++ b/Week 07/id_071/NOTE.md @@ -1,4 +1,87 @@ # NOTE - + > 位运算 + + + 0100 4(d) + 01000 8(d) + 0101 5(d) + + 位运算符 + << 左移 0011 => 0110 + >> 右移 0110 => 0011 + | 按位或 0011 | 1011 => 1011 + & 按位与 0011 & 1011 => 1100 + ~ 按位取反 0011 => 1100 + 按位异或 ^ 0011 ^ 1011 => 1000 + + 异或操作 相同为0不同为1 不进位加法 + + x^0 = x + x ^1s = ~x //1s = ~0 + x ^(~x) = 1s + x ^ x = 0 + c = a ^ b => a ^ c = b,b ^ c = a + a ^ b ^ c = a^(b^c) = (a^b)^c + + 算数移位 + x 最右边的n位清零 x & (~0 << n) + 获取x的第n位值(0 1) (x >> n)&1 + + 位运算应用 + 判断奇偶 + x%2 == 1 --> (x & 1) == 1 + x%2 == 0 --> (x & 1) == 0 + x >> 1 -> x/2 + mid = (left+right)/2;--> mid = (left+right)>>1 + x = x & (x-1) 清零最低位的 1 + x & -x => 得到最低位的1 + x & ~x => 0 + + +**** + +> 布隆过滤器 LRU缓存 + +##### bloom filter 布隆过滤器 + + 一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中 + + + 优点是 空间效率 和 查询时间 都 远远超过一般的算法 + 缺点是 有一定的误识别率 和 删除困难 + + +##### LRU缓存 least recently used + + LFU least frequently used + + 两个要素 大小、替换策略 + Hash Table + Double Linkedlist + 查询 O(1) + 修改 更新 O(1) + +**** + +> 排序算法 + +##### 初级排序O(n^2) + + 选择排序 每次找最小值 然后放到待排序数组的起始位置 + + 插入排序 从前到后逐步构建有序序列,对于未排序数据,在已排序学历中从后向前扫描,找到相应位置并插入 + + 冒泡排序 相邻元素如果逆序 则交换 + +##### 高级排序O(nlogn) + + 快速排序 quick sort + 数组取标杆 pivot 将小元素放pivot 左边,大元素放右侧,然后一次对右边和右边的子数组继续快排,以达到整个序列有序 + + 归并排序 merge sort - 分治 + 先排序左右子数组,然后合并两个有序子数组 + + 堆排序 heap sort 堆插入 O(logn) 取最大最小 O(1) + +##### 特殊排序 diff --git a/Week 07/id_071/leetcode_242_071.go b/Week 07/id_071/leetcode_242_071.go new file mode 100644 index 000000000..eef9432ba --- /dev/null +++ b/Week 07/id_071/leetcode_242_071.go @@ -0,0 +1,18 @@ +package week07 + +//3.2 https://leetcode-cn.com/problems/valid-anagram/ +func isAnagram(s string, t string) bool { + + if len(s) != len(t) {return false} + var m [26]int + for i := 0; i < len(s); i++ { + m[s[i]-'a']++ + m[t[i]-'a']-- + } + for _, v := range m { + if v != 0 { + return false + } + } + return true +} \ No newline at end of file diff --git a/Week 07/id_081/BubbleSort.java b/Week 07/id_081/BubbleSort.java new file mode 100644 index 000000000..31ff39f58 --- /dev/null +++ b/Week 07/id_081/BubbleSort.java @@ -0,0 +1,17 @@ + +public class BubbleSort { + + public void bubbleSort(int[] arr) { + for(int i = arr.length - 1; i >= 0; --i) + for(int j = 0; j < i; ++j) + if(arr[j] > arr[j + 1]) + swap(arr, j, j + 1); + } + + + public void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} diff --git a/Week 07/id_081/CountingBits.java b/Week 07/id_081/CountingBits.java new file mode 100644 index 000000000..dd6eb5efd --- /dev/null +++ b/Week 07/id_081/CountingBits.java @@ -0,0 +1,12 @@ +/** + * CountingBits + */ +public class CountingBits { + + public int[] countBits(int num) { + int[] result = new int[num + 1]; + for(int i = 1; i <= num; i++) + result[i] += result[i >> 1] + (i & 1); + return result; + } +} \ No newline at end of file diff --git a/Week 07/id_081/InsertSort.java b/Week 07/id_081/InsertSort.java new file mode 100644 index 000000000..f64fe4b4d --- /dev/null +++ b/Week 07/id_081/InsertSort.java @@ -0,0 +1,50 @@ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class InsertSort { + + + public static void insertSort(int[] arr) { + if(arr == null) return ; + for (int i = 0; i < arr.length; ++i) { + int j = i - 1; + int value = arr[i]; + while (j >= 0 && arr[j] > value) { + arr[j + 1] = arr[j]; + --j; + } + arr[++j] = value; + } + } + + public static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public List asList(int[] arr) { + List list = new ArrayList<>(); + for (int i : arr) + list.add(i); + return list; + } + + public static void printArr(int[] arr) { + for (int i : arr) + System.out.print(i + ", "); + System.out.println(); + } + + public static void main(String[] args) { + int[] arr = { 2, 3, 1}; + insertSort(arr); + printArr(arr); + + } + + + +} diff --git a/Week 07/id_081/LRUCache.java b/Week 07/id_081/LRUCache.java new file mode 100644 index 000000000..112679d21 --- /dev/null +++ b/Week 07/id_081/LRUCache.java @@ -0,0 +1,88 @@ +import java.util.HashMap; + +public class LRUCache { + private HashMap cache = new HashMap(); + private int size; + private int capacity; + private DLinkedNode head, tail; + + public LRUCache(int capacity) { + this.size = 0; + this.capacity = capacity; + + head = new DLinkedNode(); + + tail = new DLinkedNode(); + + head.next = tail; + tail.prev = head; + } + + + class DLinkedNode { + int key; + int value; + DLinkedNode prev; + DLinkedNode next; + } + + private void addNode(DLinkedNode node) { + node.prev = head; + node.next = head.next; + + head.next.prev = node; + head.next = node; + } + + private void removeNode(DLinkedNode node){ + DLinkedNode prev = node.prev; + DLinkedNode next = node.next; + + prev.next = next; + next.prev = prev; + } + + private void moveToHead(DLinkedNode node){ + removeNode(node); + addNode(node); + } + + private DLinkedNode popTail() { + DLinkedNode res = tail.prev; + removeNode(res); + return res; + } + + public int get(int key) { + DLinkedNode node = cache.get(key); + if (node == null) return -1; + + moveToHead(node); + + return node.value; + } + + public void put(int key, int value) { + DLinkedNode node = cache.get(key); + + if(node == null) { + DLinkedNode newNode = new DLinkedNode(); + newNode.key = key; + newNode.value = value; + + cache.put(key, newNode); + addNode(newNode); + + ++size; + + if(size > capacity) { + DLinkedNode tail = popTail(); + cache.remove(tail.key); + --size; + } + } else { + node.value = value; + moveToHead(node); + } + } +} \ No newline at end of file diff --git a/Week 07/id_081/MergeSort.java b/Week 07/id_081/MergeSort.java new file mode 100644 index 000000000..6cb74cfdf --- /dev/null +++ b/Week 07/id_081/MergeSort.java @@ -0,0 +1,36 @@ + +public class MergeSort { + + //[i, j] + private void mergeSort(int[] arr, int l, int r) { + if(l >= r) + return ; + + int mid = (l + r) / 2; + mergeSort(arr, l, mid); + mergeSort(arr, mid + 1, r); + merge(arr, l, mid, r); + } + + //合并区间 ----> [l, mid] [mid + 1, r] + public void merge(int[] arr, int l, int mid, int r) { + int pL = l; + int pR = mid + 1; + + int hIndex = 0; + int[] help = new int[r - l + 1]; + + while(pL <= mid && pR <= r) + help[hIndex++] = arr[pL] < arr[pR] ? arr[pL++] : arr[pR++]; + + while(pL <= mid) + help[hIndex++] = arr[pL++]; + + while(pR <= r) + help[hIndex++] = arr[pR++]; + + for (int i = l; i <= r; ++i) + arr[i] = help[i - l]; + } + +} diff --git a/Week 07/id_081/NOTE.md b/Week 07/id_081/NOTE.md old mode 100644 new mode 100755 diff --git a/Week 07/id_081/NQueensII.java b/Week 07/id_081/NQueensII.java new file mode 100644 index 000000000..3fcde52e2 --- /dev/null +++ b/Week 07/id_081/NQueensII.java @@ -0,0 +1,30 @@ +/** + * NQueensII + */ +public class NQueensII { + private int size; + private int count; + + private void solve(int row, int ld, int rd) { + //当行中没有可以放置的位置 + if(row == size) { + count++; + return ; + } + //(row | ld | rd) 所有不能放置皇后的位置 + int pos = size & (~(row | ld | rd)); + while(pos != 0) { + int p = pos & (-pos); + pos -= p; + //在 p 的位置上, 放上皇后 + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + solve(0, 0, 0); + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_081/NumberOf1Bits.java b/Week 07/id_081/NumberOf1Bits.java new file mode 100644 index 000000000..3de708d8c --- /dev/null +++ b/Week 07/id_081/NumberOf1Bits.java @@ -0,0 +1,16 @@ +/** + * NumberOf1Bits + */ +public class NumberOf1Bits { + + public int hammingWeight(int n) { + int count = 0; + //这里的代码应该是看是否等于零 + //如果将它看成二进制位的形式来看 + while(n != 0) { + count ++; + n = n & (n - 1); + } + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_081/PowerOfTow.java b/Week 07/id_081/PowerOfTow.java new file mode 100644 index 000000000..5f322978c --- /dev/null +++ b/Week 07/id_081/PowerOfTow.java @@ -0,0 +1,9 @@ +/** + * PowerOfTow + */ +public class PowerOfTow { + + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_081/QuickSort.java b/Week 07/id_081/QuickSort.java new file mode 100644 index 000000000..7f15b11cf --- /dev/null +++ b/Week 07/id_081/QuickSort.java @@ -0,0 +1,36 @@ +public class QuickSort { + + private void quickSort(int[] arr, int l, int r) { + if (l >= r) + return; + + int[] res = partition(arr, l, r); + quickSort(arr, l, res[0]); + quickSort(arr, res[1], r); + } + + private int[] partition(int[] arr, int l, int r) { + int less = l - 1; + int more = r; + int i = l; + + while (i < more) { + if (arr[i] < arr[r]) + swap(arr, i++ , ++less); + else if(arr[i] > arr[r]) + swap(arr, i, --more); + else + ++i; + } + + swap(arr, more++, r); + + return new int[]{less, more}; + } + + private void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} diff --git a/Week 07/id_081/ReverseBits.java b/Week 07/id_081/ReverseBits.java new file mode 100644 index 000000000..cbb854cfc --- /dev/null +++ b/Week 07/id_081/ReverseBits.java @@ -0,0 +1,14 @@ +/** + * ReverseBits + */ +public class ReverseBits { + + public int reverseBits(int n) { + int result = 0; + for(int i = 0;i < 32;i++){ + result = (result << 1) + (n & 1); + n >>= 1; + } + return result; + } +} \ No newline at end of file diff --git a/Week 07/id_086/LeetCode_1122_086.java b/Week 07/id_086/LeetCode_1122_086.java new file mode 100644 index 000000000..131f9d4e6 --- /dev/null +++ b/Week 07/id_086/LeetCode_1122_086.java @@ -0,0 +1,24 @@ +/** + * 1122.数组的相对排序 + */ + +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] bucket = new int[1001]; + for (int num : arr1) { + bucket[num]++; + } + int i = 0; + for (int num:arr2) { + while (bucket[num] -- > 0) { + arr1[i++] = num; + } + } + for (int j = 0; j < 1001; j++) { + while (bucket[j]-- > 0) { + arr1[i++] = j; + } + } + return arr1; + } +} \ No newline at end of file diff --git a/Week 07/id_086/LeetCode_190_086.java b/Week 07/id_086/LeetCode_190_086.java new file mode 100644 index 000000000..cf2bad62b --- /dev/null +++ b/Week 07/id_086/LeetCode_190_086.java @@ -0,0 +1,16 @@ +/** + * 190. 颠倒二进制位 + */ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int reversal = 0; + for (int i = 0; i <= 32; i++) { + int tmp = n >> i; + tmp = tmp & 1; + tmp = tmp << (31 - i); + reversal |= tmp; + } + return reversal; + } +} \ No newline at end of file diff --git a/Week 07/id_086/LeetCode_191_086.java b/Week 07/id_086/LeetCode_191_086.java new file mode 100644 index 000000000..1ff417f28 --- /dev/null +++ b/Week 07/id_086/LeetCode_191_086.java @@ -0,0 +1,15 @@ +/** + * 191.位1的个数 + */ + +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 & (n-1); + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_086/LeetCode_231_086.java b/Week 07/id_086/LeetCode_231_086.java new file mode 100644 index 000000000..f2e527373 --- /dev/null +++ b/Week 07/id_086/LeetCode_231_086.java @@ -0,0 +1,14 @@ +/** + * 231. 2的幂 + */ + +class Solution { + public boolean isPowerOfTwo(int n) { + if (n <= 0) + return false; + if ((n & (n - 1)) == 0) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Week 07/id_091/Leetcode_146_091.py b/Week 07/id_091/Leetcode_146_091.py new file mode 100644 index 000000000..e69de29bb diff --git a/Week 07/id_091/Leetcode_191_091.py b/Week 07/id_091/Leetcode_191_091.py new file mode 100644 index 000000000..b2575d8f2 --- /dev/null +++ b/Week 07/id_091/Leetcode_191_091.py @@ -0,0 +1,33 @@ +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + count = 0 + while n: + ##把 n 与 1 进行与运算,将得到 n 的最低位数字。因此可以取出最低位数,再将 n 右移一位。循环此步骤,直到 n 等于零 + count += n & 1 + n >>= 1 + return count + + def hammingWeight1(self, n): + """ + :type n: int + :rtype: int + """ + count = 0 + while n: + res = n % 2 + if res == 1: + count += 1 + n //= 2 + return count + + +if __name__ == "__main__": + solution = Solution() + res = solution.hammingWeight(7) + res1 = solution.hammingWeight1(7) + print(res) + print(res1) diff --git a/Week 07/id_091/Leetcode_338_091.py b/Week 07/id_091/Leetcode_338_091.py new file mode 100644 index 000000000..181d149b9 --- /dev/null +++ b/Week 07/id_091/Leetcode_338_091.py @@ -0,0 +1,17 @@ +class Solution(object): + def countBits(self, num): + """ + bits[i] = bits[i & (i - 1)] + 1. + i & (i - 1):清除i二进制最后的1 + """ + + bits = [0] + for i in range(1, num + 1): + bits.append(bits[i & (i - 1)] + 1) + return bits + + +if __name__ == "__main__": + solution = Solution() + res = solution.countBits(7) + print(res) diff --git a/Week 07/id_091/sort.py b/Week 07/id_091/sort.py new file mode 100644 index 000000000..c23c1147d --- /dev/null +++ b/Week 07/id_091/sort.py @@ -0,0 +1,190 @@ +# 1.冒泡排序 +def bubbleSort(nums): + for i in range(len(nums) - 1): + for j in range(len(nums) - i - 1): + if nums[j] > nums[j + 1]: + nums[j], nums[j + 1] = nums[j + 1], nums[j] + return nums + + +nums = [61, 81, 31, 2, 9, 1] + +print(bubbleSort(nums)) + + +# 2.选择排序 +def selectSort(list): + for i in range(len(list) - 1): + for j in range(i, len(list)): + if list[j] < list[i]: + min = j + list[i], list[min] = list[min], list[i] + return list + + +print(selectSort([1, 3, 2])) + + +# 3.插入排序 +def insertSort(list): + for i in range(1, len(list)): + j = i - 1 + key = list[i] + while j >= 0: + if list[j] > key: + list[j + 1] = list[j] + list[j] = key + j -= 1 + return list + + +print(insertSort([4, 3, 2, 4])) + + +# 4.快排 +def quickSort(list, start, r): + if start < r: + q = partion(list, start, r) + quickSort(list, start, q) + quickSort(list, q + 1, r) + + +def partion(list, start, r): + i = start - 1 + for j in range(start, r): + if list[j] <= list[r]: + i += 1 + list[i], list[j] = list[j], list[i] + list[i + 1], list[r] = list[r], list[i + 1] + return i + + +list = [3, 2, 4, 1] +quickSort(list, 0, 3) +print(list) + + +# 5.希尔排序 +def shellSort(slist): + gap = len(slist) + while gap > 1: + gap = gap // 2 + for i in range(gap, len(slist)): + for j in range(i % gap, i, gap): + if slist[i] < slist[j]: + slist[i], slist[j] = slist[j], slist[i] + return slist + + +list = shellSort([14, 5, 6, 7, 3, 2, 6, 9, 8]) +print(list) + +# 6.堆排序 +import copy + + +def heapSort(hlist): + def heapAdjust(parent): + child = 2 * parent + 1 # left child + while child < len(heap): + if child + 1 < len(heap): + if heap[child + 1] > heap[child]: + child += 1 # right child + if heap[parent] >= heap[child]: + break + heap[parent], heap[child] = heap[child], heap[parent] + parent, child = child, 2 * child + 1 + + heap, hlist = copy.copy(hlist), [] + for i in range(len(heap) // 2, -1, -1): + heapAdjust(i) + while len(heap) != 0: + heap[0], heap[-1] = heap[-1], heap[0] + hlist.insert(0, heap.pop()) + heapAdjust(0) + return hlist + + +hlist = heapSort([4, 5, 6, 7, 3, 2, 6, 9, 8]) +print(hlist) + + +# 7.归并排序 +def mergeSort(array): + def mergeArr(arr_l, arr_r): + array = [] + while len(arr_l) and len(arr_r): + if arr_l[0] <= arr_r[0]: + array.append(arr_l.pop(0)) + elif arr_l[0] > arr_r[0]: + array.append(arr_r.pop(0)) + if len(arr_l) != 0: + array += arr_l + elif len(arr_r) != 0: + array += arr_r + return array + + def recursive(array): + if len(array) == 1: + return array + mid = len(array) // 2 + arr_l = recursive(array[:mid]) + arr_r = recursive(array[mid:]) + return mergeArr(arr_l, arr_r) + + return recursive(array) + + +list = mergeSort([4, 5, 6, 7, 3, 2, 6, 9, 8]) +print(list) + + +# 8.计数排序 +def countingSort(a, k): # k = max(a) + n = len(a) # 计算a序列的长度 + b = [0 for i in range(n)] # 设置输出序列并初始化为0 + c = [0 for i in range(k + 1)] # 设置计数序列并初始化为0, + for j in a: + c[j] = c[j] + 1 + for i in range(1, len(c)): + c[i] = c[i] + c[i - 1] + for j in a: + b[c[j] - 1] = j + c[j] = c[j] - 1 + return b + + +# 9.桶排序 +def bucketSort(a): + buckets = [0] * ((max(a) - min(a)) + 1) # 初始化桶元素为0 + for i in range(len(a)): + buckets[a[i] - min(a)] += 1 # 遍历数组a,在桶的相应位置累加值 + b = [] + for i in range(len(buckets)): + if buckets[i] != 0: + b += [i + min(a)] * buckets[i] + return b + + +arr = [14, 25, 36, 17, 3, 2, 6, 9, 8] +list = bucketSort(arr) +print(list) + + +# 10.基数排序 +def radixSort(array): + bucket, digit = [[]], 0 + while len(bucket[0]) != len(array): + bucket = [[], [], [], [], [], [], [], [], [], []] + for i in range(len(array)): + num = (array[i] // 10 ** digit) % 10 + bucket[num].append(array[i]) + array.clear() + for i in range(len(bucket)): + array += bucket[i] + digit += 1 + return array + + +list = radixSort([4, 5, 6, 7, 3, 2, 6, 9, 8]) +print(list) diff --git a/Week 07/id_101/README.md b/Week 07/id_101/README.md new file mode 100644 index 000000000..73712a426 --- /dev/null +++ b/Week 07/id_101/README.md @@ -0,0 +1,73 @@ +#### String +##### reference +[are your strings immutable](https://lemire.me/blog/2017/07/07/are-your-strings-immutable/) +[Atoi sample code](https://shimo.im/docs/KkDKkpWxjjrJXdpY/read) +```angular2html + def myAtoi(self, s): + + if len(s) == 0 : return 0 + ls = list(s.strip()) + + sign = -1 if ls[0] == '-' else 1 + + if ls[0] in ['-','+'] : del ls[0] + + ret, i = 0, 0 + + while i < len(ls) and ls[i].isdigit() : + ret = ret*10 + ord(ls[i]) - ord('0') + i += 1 + + return max(-2**31, min(sign * ret,2**31-1)) +``` +##### basic +`#` | leetcode-cn | leetcode | solution +---:|:----|:----|:---- +58 | [最后一个单词的长度](https://leetcode-cn.com/problems/length-of-last-word/) | [length-of-last-word](https://leetcode.com/problems/length-of-last-word/) | [python]([58]最后一个单词的长度.py) +709| [转换成小写字母](https://leetcode-cn.com/problems/to-lower-case/) | [to-lower-case](https://leetcode.com/problems/to-lower-case/) +771 | [宝石与石头](https://leetcode-cn.com/problems/jewels-and-stones/) | [jewels-and-stones](https://leetcode.com/problems/jewels-and-stones/) +387 | [字符串中的第一个唯一字符](https://leetcode-cn.com/problems/first-unique-character-in-a-string/) | [first-unique-character-in-a-string](https://leetcode-cn.com/problems/first-unique-character-in-a-string/) +8 | [字符串转换整数 (atoi)](https://leetcode-cn.com/problems/string-to-integer-atoi/) | [string-to-integer-atoi](https://leetcode-cn.com/problems/string-to-integer-atoi/) +##### operation +`#` | leetcode-cn | leetcode | +---:|:----|:----| +14 | [最长公共前缀](https://leetcode-cn.com/problems/longest-common-prefix/) | [longest-common-prefix](https://leetcode.com/problems/longest-common-prefix/) +344 | [反转字符串](https://leetcode-cn.com/problems/reverse-string) | [reverse-string](https://leetcode.com/problems/reverse-string) +541 | [反转字符串 II](https://leetcode-cn.com/problems/reverse-string-ii/) | [reverse-string-ii](https://leetcode.com/problems/reverse-string-ii/) +151 | [翻转字符串里的单词](https://leetcode-cn.com/problems/reverse-words-in-a-string/) | [reverse-words-in-a-string](https://leetcode.com/problems/reverse-words-in-a-string/) +557 | [反转字符串中的单词 III](https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/) | [reverse-words-in-a-string-iii](https://leetcode.com/problems/reverse-words-in-a-string-iii/) +917 | [仅仅反转字母](https://leetcode-cn.com/problems/reverse-only-letters/) | [reverse-only-letters](https://leetcode.com/problems/reverse-only-letters/) +##### anagram +`#` | leetcode-cn | leetcode | +---:|:----|:----| +242 | [有效的字母异位词](https://leetcode-cn.com/problems/valid-anagram/) | [valid-anagram](https://leetcode.com/problems/valid-anagram/) +49 | [字母异位词分组](https://leetcode-cn.com/problems/group-anagrams/) | [group-anagrams](https://leetcode.com/problems/group-anagrams/) +438 | [找到字符串中所有字母异位词](https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/) | [find-all-anagrams-in-a-string](https://leetcode.com/problems/find-all-anagrams-in-a-string/) +##### palindrome +`#` | leetcode-cn | leetcode | +---:|:----|:----| +125 | [验证回文串](https://leetcode-cn.com/problems/valid-palindrome/) | [valid-palindrome](https://leetcode.com/problems/valid-palindrome/) +680 | [验证回文字符串 Ⅱ](https://leetcode-cn.com/problems/valid-palindrome-ii/) | [valid-palindrome-ii](https://leetcode.com/problems/valid-palindrome-ii/) +5 | [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/) | [longest-palindromic-substring](https://leetcode.com/problems/longest-palindromic-substring/) + +##### subsequence + DP +[正则表达式匹配 详解](https://leetcode-cn.com/problems/regular-expression-matching/solution/ji-yu-guan-fang-ti-jie-gen-xiang-xi-de-jiang-jie-b/) + +`#` | leetcode-cn | leetcode +---:|:----|:---- +1143 | [最长公共子序列](https://leetcode-cn.com/problems/longest-common-subsequence/) | [longest-common-subsequence](https://leetcode.com/problems/longest-common-subsequence/) +72 | [编辑距离](https://leetcode-cn.com/problems/edit-distance/) | [edit-distance](https://leetcode.com/problems/edit-distance/) +10 | [正则表达式匹配](https://leetcode-cn.com/problems/regular-expression-matching/) | [regular-expression-matching](https://leetcode.com/problems/regular-expression-matching/) +44 | [通配符匹配](https://leetcode-cn.com/problems/wildcard-matching/) | [wildcard-matching](https://leetcode.com/problems/wildcard-matching/) +115 | [不同的子序列](https://leetcode-cn.com/problems/distinct-subsequences/) | [distinct-subsequences](https://leetcode.com/problems/distinct-subsequences/) + +##### KMP +[字符串匹配之KMP、BoyerMoore、Sunday算法](https://blog.csdn.net/u012505432/article/details/52210975) + +[字符串匹配暴力法代码示例](https://shimo.im/docs/dQDxQW8yXPXxh3Hg/read) + +[Rabin-Karp 代码示例](https://shimo.im/docs/KXDdkT99TVtXvTXP/read) + +[字符串匹配的KMP算法](http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html) + +[KMP字符串匹配算法1](https://www.bilibili.com/video/av11866460?from=search&seid=17425875345653862171) \ No newline at end of file diff --git "a/Week 07/id_101/[1125]\346\234\200\345\260\217\347\232\204\345\277\205\350\246\201\345\233\242\351\230\237.py" "b/Week 07/id_101/[1125]\346\234\200\345\260\217\347\232\204\345\277\205\350\246\201\345\233\242\351\230\237.py" new file mode 100644 index 000000000..56a264964 --- /dev/null +++ "b/Week 07/id_101/[1125]\346\234\200\345\260\217\347\232\204\345\277\205\350\246\201\345\233\242\351\230\237.py" @@ -0,0 +1,48 @@ +#作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。 +# +# 所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。 +# +# 我们可以用每个人的编号来表示团队中的成员:例如,团队 team = [0, 1, 3] 表示掌握技能分别为 people[0],people[1],和 people[3] 的备选人员。 +# +# 请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按任意顺序返回答案,本题保证答案存在。 +# +# +# +# 示例 1: +# +# 输入:req_skills = ["java","nodejs","reactjs"], people = [["java"],["nodejs"],["nodejs","reactjs"]] +#输出:[0,2] +# +# +# 示例 2: +# +# 输入:req_skills = ["algorithms","math","java","reactjs","csharp","aws"], people = [["algorithms","math","java"],["algorithms","math","reactjs"],["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]] +#输出:[1,2] +# +# +# +# +# 提示: +# +# +# 1 <= req_skills.length <= 16 +# 1 <= people.length <= 60 +# 1 <= people[i].length, req_skills[i].length, people[i][j].length <= 16 +# req_skills 和 people[i] 中的元素分别各不相同 +# req_skills[i][j], people[i][j][k] 都由小写英文字母组成 +# 本题保证「必要团队」一定存在 +# +# Related Topics 位运算 动态规划 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def smallestSufficientTeam(self, req_skills, people): + """ + :type req_skills: List[str] + :type people: List[List[str]] + :rtype: List[int] + """ + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[1143]\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.py" "b/Week 07/id_101/[1143]\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.py" new file mode 100644 index 000000000..2e04531d3 --- /dev/null +++ "b/Week 07/id_101/[1143]\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.py" @@ -0,0 +1,89 @@ +#给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。 +# +# 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 +#例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 +# +# 若这两个字符串没有公共子序列,则返回 0。 +# +# +# +# 示例 1: +# +# 输入:text1 = "abcde", text2 = "ace" +#输出:3 +#解释:最长公共子序列是 "ace",它的长度为 3。 +# +# +# 示例 2: +# +# 输入:text1 = "abc", text2 = "abc" +#输出:3 +#解释:最长公共子序列是 "abc",它的长度为 3。 +# +# +# 示例 3: +# +# 输入:text1 = "abc", text2 = "def" +#输出:0 +#解释:两个字符串没有公共子序列,返回 0。 +# +# +# +# +# 提示: +# +# +# 1 <= text1.length <= 1000 +# 1 <= text2.length <= 1000 +# 输入的字符串只含有小写英文字符。 +# +# Related Topics 动态规划 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def longestCommonSubsequence(self, text1, text2): + """ + :type text1: str + :type text2: str + :rtype: int + """ + """ + if s[i] == t[j] + dp[i+1][j+1] = dp[i][j] + 1 + else + dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]) + dp array size should be len(s)+1 and len(t)+1 + specifically when dealing with string + """ + dp = [[0] * (len(text2)+1) for _ in range(len(text1)+1)] + for i, c in enumerate(text1): + for j, d in enumerate(text2): + dp[i+1][j+1] = 1 + dp[i][j] if c == d else max(dp[i][j+1], dp[i+1][j]) + return dp[-1][-1] + + def longestCommonSubsequenceII(self, text1, text2): + """ + :type text1: str + :type text2: str + :rty + """ + # only needs information of previous row to update current row. + # So we just use a two-row 2D array to save and update the matching results for chars in s1 and s2 + """ + 1: use k ^ 1 and k ^= 1 to switch between dp[0] (row 0) and dp[1] (row 1). + 2: use 1 - i % 2 and i % 2 to switch between dp[0] (row 0) and dp[1] (row 1) + Time: O(m*n), space: O(min(m, n)) + """ + m, n = len(text1), len(text2) + # let second string length smaller + if m < n: + return self.longestCommonSubsequenceII(text2, text1) + dp = [[0] * (n+1) for _ in range(2)] + for i, c in enumerate(text1): + for j, d in enumerate(text2): + dp[1-i%2][j+1] = 1 + dp[i%2][j] if c == d else max(dp[i%2][j+1], dp[1-i%2][j]) + return dp[m%2][-1] + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" "b/Week 07/id_101/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" new file mode 100644 index 000000000..f32bae6ed --- /dev/null +++ "b/Week 07/id_101/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" @@ -0,0 +1,50 @@ +#给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 +# +# 说明:本题中,我们将空字符串定义为有效的回文串。 +# +# 示例 1: +# +# 输入: "A man, a plan, a canal: Panama" +#输出: true +# +# +# 示例 2: +# +# 输入: "race a car" +#输出: false +# +# Related Topics 双指针 字符串 + + + +#leetcode submit region begin(Prohibit modification and deletion) +import re + + +class Solution(object): + def isPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + # regex + s = re.sub(r'[^a-zA-Z0-9]', '', s).lower() + return s[::-1] == s + + def isParlindrome(self, s: str): + """two pointer""" + l, r = 0, len(s)-1 + while l < r: + while l < r and not s[l].isalnum(): + l += 1 + while l < r and not s[r].isalnum(): + r -= 1 + if s[l].lower() != s[r].lower(): + return False + l, r = l+1, r-1 + return True + + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[146]LRU\347\274\223\345\255\230\346\234\272\345\210\266.py" "b/Week 07/id_101/[146]LRU\347\274\223\345\255\230\346\234\272\345\210\266.py" new file mode 100644 index 000000000..1b940105b --- /dev/null +++ "b/Week 07/id_101/[146]LRU\347\274\223\345\255\230\346\234\272\345\210\266.py" @@ -0,0 +1,148 @@ +#运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +# +# 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +#写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +# +# 进阶: +# +# 你是否可以在 O(1) 时间复杂度内完成这两种操作? +# +# 示例: +# +# LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +# +#cache.put(1, 1); +#cache.put(2, 2); +#cache.get(1); // 返回 1 +#cache.put(3, 3); // 该操作会使得密钥 2 作废 +#cache.get(2); // 返回 -1 (未找到) +#cache.put(4, 4); // 该操作会使得密钥 1 作废 +#cache.get(1); // 返回 -1 (未找到) +#cache.get(3); // 返回 3 +#cache.get(4); // 返回 4 +# +# Related Topics 设计 + + + +#leetcode submit region begin(Prohibit modification and deletion) +''' +doubly linked list +''' +class DLinkedNode: + def __init__(self): + self.key = 0 + self.val = 0 + self.prev = None + self.next = None + +class LRUCache(object): + + def __init__(self, capacity): + """ + :type capacity: int + """ + self.cache = {} + self.size = 0 + self.capacity = capacity + self.head, self.tail = DLinkedNode(), DLinkedNode() + self.head.next = self.tail + self.tail.prev = self.head + + + def get(self, key): + """ + :type key: int + :rtype: int + """ + node = self.cache.get(key, None) + if not node: + return -1 + self._move_to_head(node) + return node.val + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: None + """ + node = self.cache.get(key) + if not node: + new_node = DLinkedNode() + new_node.key = key + new_node.val = value + + self.cache[key] = new_node + self._add_node(new_node) + self.size += 1 + if self.size > self.capacity: + # pop tail + tail = self._pop_tail() + del self.cache[tail.key] + self.size -= 1 + else: + # update value + node.val = value + self._move_to_head(node) + + def _add_node(self, node): + node.prev = self.head + node.next = self.head.next + + self.head.next.prev = node + self.head.next = node + + def _remove_node(self, node): + prev_node = node.prev + next_node = node.next + prev_node.next = next_node + next_node.prev = prev_node + + def _move_to_head(self, node): + self._remove_node(node) + self._add_node(node) + + def _pop_tail(self): + node = self.tail.prev + self._remove_node(node) + return node + +''' OrderedDict == LinkedHashMap + get/in/set/move_to_end/popitem == get/containsKey/put/remove in O(1) +''' +from collections import OrderedDict +class LRUCacheII(OrderedDict): + + def __init__(self, capacity): + """ + :type capacity: int + """ + self.capacity = capacity + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key not in self: + return -1 + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: None + """ + if key in self: + self.move_to_end(key) + self[key] = value + if len(self) > self.capacity: + self.popitem(last=False) + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.py" "b/Week 07/id_101/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.py" new file mode 100644 index 000000000..557f3608b --- /dev/null +++ "b/Week 07/id_101/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.py" @@ -0,0 +1,66 @@ +#编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 +# +# +# +# 示例 1: +# +# 输入:00000000000000000000000000001011 +#输出:3 +#解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +# +# +# 示例 2: +# +# 输入:00000000000000000000000010000000 +#输出:1 +#解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +# +# +# 示例 3: +# +# 输入:11111111111111111111111111111101 +#输出:31 +#解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +# +# +# +# 提示: +# +# +# 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +# 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +# +# +# +# +# 进阶: +#如果多次调用这个函数,你将如何优化你的算法? +# Related Topics 位运算 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + cnt = 0 + ''' + same pos of right most 1 in binary(n) is 0 in binary(n-1) + then n & (n-1) can change this bit into 0 + ''' + while n != 0: + n &= (n-1) + cnt += 1 + return cnt + + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + return bin(n).count('1') + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" "b/Week 07/id_101/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" new file mode 100644 index 000000000..d5bd3a338 --- /dev/null +++ "b/Week 07/id_101/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" @@ -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 设计 字典树 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class TrieNode: + def __init__(self): + self.isWord = False + self.children = {} + +class Trie(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = TrieNode() + + + def insert(self, word): + """ + Inserts a word into the trie. + :type word: str + :rtype: None + """ + node = self.root + for c in word: + if c not in node.children: + node.children[c] = TrieNode() + node = node.children[c] + node.isWord = True + + + def search(self, word): + """ + Returns if the word is in the trie. + :type word: str + :rtype: bool + """ + node = self.root + for c in word: + if c not in node.children: + return False + node = node.children[c] + return node.isWord + + + def startsWith(self, prefix): + """ + Returns if there is any word in the trie that starts with the given prefix. + :type prefix: str + :rtype: bool + """ + node = self.root + for c in prefix: + if c not in node.children: + return False + node = node.children[c] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[212]\345\215\225\350\257\215\346\220\234\347\264\242 II.py" "b/Week 07/id_101/[212]\345\215\225\350\257\215\346\220\234\347\264\242 II.py" new file mode 100644 index 000000000..1e1c534f4 --- /dev/null +++ "b/Week 07/id_101/[212]\345\215\225\350\257\215\346\220\234\347\264\242 II.py" @@ -0,0 +1,94 @@ +#给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 +# +# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 +# +# 示例: +# +# 输入: +#words = ["oath","pea","eat","rain"] and board = +#[ +# ['o','a','a','n'], +# ['e','t','a','e'], +# ['i','h','k','r'], +# ['i','f','l','v'] +#] +# +#输出: ["eat","oath"] +# +# 说明: +#你可以假设所有输入都由小写字母 a-z 组成。 +# +# 提示: +# +# +# 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? +# 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 +# +# Related Topics 字典树 回溯算法 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class TrieNode(object): + def __init__(self): + self.isWord = False + self.children = collections.defaultdict(TrieNode) + +class Trie(object): + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for c in word: + node = node.children[c] + node.isWord = True + + def search(self, word): + node = self.root + for c in word: + node = node.children.get(c) + if not node: + return False + return node.isWord + + +dx = [1, 0, -1, 0] +dy = [0, 1, 0, -1] + + +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + res = [] + trie = Trie() + node = trie.root + for word in words: + trie.insert(word) + for i in range(len(board)): + for j in range(len(board[0])): + self.dfs(board, node, i, j, "", res) + return res + + def dfs(self, board, node, i, j, path, res): + if node.isWord: + res.append(path) + node.isWord = False + if 0<=i给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。

+ +

如果不存在最后一个单词,请返回 0 。

+ +

说明:一个单词是指由字母组成,但不包含任何空格的字符串。

+ +

示例:

+ +
输入: "Hello World"
+输出: 5
+
+
Related Topics
  • 字符串
  • \ No newline at end of file diff --git "a/Week 07/id_101/[58]\346\234\200\345\220\216\344\270\200\344\270\252\345\215\225\350\257\215\347\232\204\351\225\277\345\272\246.py" "b/Week 07/id_101/[58]\346\234\200\345\220\216\344\270\200\344\270\252\345\215\225\350\257\215\347\232\204\351\225\277\345\272\246.py" new file mode 100644 index 000000000..0159b896c --- /dev/null +++ "b/Week 07/id_101/[58]\346\234\200\345\220\216\344\270\200\344\270\252\345\215\225\350\257\215\347\232\204\351\225\277\345\272\246.py" @@ -0,0 +1,48 @@ +#给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。 +# +# 如果不存在最后一个单词,请返回 0 。 +# +# 说明:一个单词是指由字母组成,但不包含任何空格的字符串。 +# +# 示例: +# +# 输入: "Hello World" +#输出: 5 +# +# Related Topics 字符串 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def lengthOfLastWord(self, s): + """ + :type s: str + :rtype: int + """ + # trim all right spaces + # split by space + # get last part of len + return len(s.rstrip().split(" ")[-1]) + + def lengthOfLastWordII(self, s): + """ + + :param s: + :type s: + :return: + :rtype: + """ + # skip trailing space + i = len(s) - 1 + while i >= 0 and s[i] == " ": + i -= 1 + # iterate last word + j = i + while j >= 0 and s[j] != " ": + j -= 1 + return i - j + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[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.py" "b/Week 07/id_101/[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.py" new file mode 100644 index 000000000..90baf7da5 --- /dev/null +++ "b/Week 07/id_101/[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.py" @@ -0,0 +1,44 @@ +#给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。 +# +# 示例 1: +# +# +#输入: "aba" +#输出: True +# +# +# 示例 2: +# +# +#输入: "abca" +#输出: True +#解释: 你可以删除c字符。 +# +# +# 注意: +# +# +# 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。 +# +# Related Topics 字符串 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def validPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + # two pointer, whenever mismatch, exclude char at left or right pointer, and keep comparing remaining substrings + l, r = 0, len(s)-1 + while l < r: + if s[l] != s[r]: + one, two = s[l:r], s[l+1:r+1] + return one==one[::-1] or two==two[::-1] + l, r = l+1, r-1 + return True + + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[709]\350\275\254\346\215\242\346\210\220\345\260\217\345\206\231\345\255\227\346\257\215.py" "b/Week 07/id_101/[709]\350\275\254\346\215\242\346\210\220\345\260\217\345\206\231\345\255\227\346\257\215.py" new file mode 100644 index 000000000..7d27f46d1 --- /dev/null +++ "b/Week 07/id_101/[709]\350\275\254\346\215\242\346\210\220\345\260\217\345\206\231\345\255\227\346\257\215.py" @@ -0,0 +1,43 @@ +#实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。 +# +# +# +# 示例 1: +# +# +#输入: "Hello" +#输出: "hello" +# +# 示例 2: +# +# +#输入: "here" +#输出: "here" +# +# 示例 3: +# +# +#输入: "LOVELY" +#输出: "lovely" +# +# Related Topics 字符串 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def toLowerCase(self, str): + """ + :type str: str + :rtype: str + """ + return str.lower() + + def toLowerCase(self, str): + """ + :type str: str + :rtype: str + """ + return "".join(chr(ord(c) + 32) if "A" <= c <= "Z" else c for c in str) + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" "b/Week 07/id_101/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" new file mode 100644 index 000000000..c641477f0 --- /dev/null +++ "b/Week 07/id_101/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" @@ -0,0 +1,38 @@ +#给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头。 S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。 +# +# J 中的字母不重复,J 和 S中的所有字符都是字母。字母区分大小写,因此"a"和"A"是不同类型的石头。 +# +# 示例 1: +# +# 输入: J = "aA", S = "aAAbbbb" +#输出: 3 +# +# +# 示例 2: +# +# 输入: J = "z", S = "ZZ" +#输出: 0 +# +# +# 注意: +# +# +# S 和 J 最多含有50个字母。 +# J 中的字符不重复。 +# +# Related Topics 哈希表 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def numJewelsInStones(self, J, S): + """ + :type J: str + :type S: str + :rtype: int + """ + set_J = set(J) + return sum([1 for c in S if c in set_J]) + +#leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 07/id_101/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260 (atoi).py" "b/Week 07/id_101/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260 (atoi).py" new file mode 100644 index 000000000..6896de8ef --- /dev/null +++ "b/Week 07/id_101/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260 (atoi).py" @@ -0,0 +1,82 @@ +#请你来实现一个 atoi 函数,使其能将字符串转换成整数。 +# +# 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。 +# +# 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。 +# +# 该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。 +# +# 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。 +# +# 在任何情况下,若函数不能进行有效的转换时,请返回 0。 +# +# 说明: +# +# 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。 +# +# 示例 1: +# +# 输入: "42" +#输出: 42 +# +# +# 示例 2: +# +# 输入: " -42" +#输出: -42 +#解释: 第一个非空白字符为 '-', 它是一个负号。 +#  我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 +# +# +# 示例 3: +# +# 输入: "4193 with words" +#输出: 4193 +#解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。 +# +# +# 示例 4: +# +# 输入: "words and 987" +#输出: 0 +#解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 +# 因此无法执行有效的转换。 +# +# 示例 5: +# +# 输入: "-91283472332" +#输出: -2147483648 +#解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 +#  因此返回 INT_MIN (−231) 。 +# +# Related Topics 数学 字符串 + + + +#leetcode submit region begin(Prohibit modification and deletion) +import re + + +class Solution(object): + def myAtoi(self, str): + """ + :type str: str + :rtype: int + """ + # use regex and strip to trim space + cand = re.findall('^[\+\-]?0*\d+', str.strip()) + + if cand: + num = int(cand[0]) + MAX_INT = 2 ** 31 - 1 + MIN_INT = - 2 ** 31 + if num < MIN_INT: + return MIN_INT + elif num > MAX_INT: + return MAX_INT + else: + return num + else: + return 0 + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_101/all.json b/Week 07/id_101/all.json new file mode 100644 index 000000000..858cdf760 --- /dev/null +++ b/Week 07/id_101/all.json @@ -0,0 +1 @@ +[{"formTitle":"[1]两数之和","frontendQuestionId":"1","leaf":true,"level":1,"nodeType":"def","questionId":"1","status":"","title":"两数之和","titleSlug":"two-sum"},{"formTitle":"[2]两数相加","frontendQuestionId":"2","leaf":true,"level":2,"nodeType":"def","questionId":"2","status":"","title":"两数相加","titleSlug":"add-two-numbers"},{"formTitle":"[3]无重复字符的最长子串","frontendQuestionId":"3","leaf":true,"level":2,"nodeType":"def","questionId":"3","status":"","title":"无重复字符的最长子串","titleSlug":"longest-substring-without-repeating-characters"},{"formTitle":"[4]寻找两个有序数组的中位数","frontendQuestionId":"4","leaf":true,"level":3,"nodeType":"def","questionId":"4","status":"","title":"寻找两个有序数组的中位数","titleSlug":"median-of-two-sorted-arrays"},{"formTitle":"[5]最长回文子串","frontendQuestionId":"5","leaf":true,"level":2,"nodeType":"def","questionId":"5","status":"","title":"最长回文子串","titleSlug":"longest-palindromic-substring"},{"formTitle":"[6]Z 字形变换","frontendQuestionId":"6","leaf":true,"level":2,"nodeType":"def","questionId":"6","status":"","title":"Z 字形变换","titleSlug":"zigzag-conversion"},{"formTitle":"[7]整数反转","frontendQuestionId":"7","leaf":true,"level":1,"nodeType":"def","questionId":"7","status":"","title":"整数反转","titleSlug":"reverse-integer"},{"formTitle":"[8]字符串转换整数 (atoi)","frontendQuestionId":"8","leaf":true,"level":2,"nodeType":"def","questionId":"8","status":"","title":"字符串转换整数 (atoi)","titleSlug":"string-to-integer-atoi"},{"formTitle":"[9]回文数","frontendQuestionId":"9","leaf":true,"level":1,"nodeType":"def","questionId":"9","status":"","title":"回文数","titleSlug":"palindrome-number"},{"formTitle":"[10]正则表达式匹配","frontendQuestionId":"10","leaf":true,"level":3,"nodeType":"def","questionId":"10","status":"","title":"正则表达式匹配","titleSlug":"regular-expression-matching"},{"formTitle":"[11]盛最多水的容器","frontendQuestionId":"11","leaf":true,"level":2,"nodeType":"def","questionId":"11","status":"","title":"盛最多水的容器","titleSlug":"container-with-most-water"},{"formTitle":"[12]整数转罗马数字","frontendQuestionId":"12","leaf":true,"level":2,"nodeType":"def","questionId":"12","status":"","title":"整数转罗马数字","titleSlug":"integer-to-roman"},{"formTitle":"[13]罗马数字转整数","frontendQuestionId":"13","leaf":true,"level":1,"nodeType":"def","questionId":"13","status":"","title":"罗马数字转整数","titleSlug":"roman-to-integer"},{"formTitle":"[14]最长公共前缀","frontendQuestionId":"14","leaf":true,"level":1,"nodeType":"def","questionId":"14","status":"","title":"最长公共前缀","titleSlug":"longest-common-prefix"},{"formTitle":"[15]三数之和","frontendQuestionId":"15","leaf":true,"level":2,"nodeType":"def","questionId":"15","status":"","title":"三数之和","titleSlug":"3sum"},{"formTitle":"[16]最接近的三数之和","frontendQuestionId":"16","leaf":true,"level":2,"nodeType":"def","questionId":"16","status":"","title":"最接近的三数之和","titleSlug":"3sum-closest"},{"formTitle":"[17]电话号码的字母组合","frontendQuestionId":"17","leaf":true,"level":2,"nodeType":"def","questionId":"17","status":"","title":"电话号码的字母组合","titleSlug":"letter-combinations-of-a-phone-number"},{"formTitle":"[18]四数之和","frontendQuestionId":"18","leaf":true,"level":2,"nodeType":"def","questionId":"18","status":"","title":"四数之和","titleSlug":"4sum"},{"formTitle":"[19]删除链表的倒数第N个节点","frontendQuestionId":"19","leaf":true,"level":2,"nodeType":"def","questionId":"19","status":"","title":"删除链表的倒数第N个节点","titleSlug":"remove-nth-node-from-end-of-list"},{"formTitle":"[20]有效的括号","frontendQuestionId":"20","leaf":true,"level":1,"nodeType":"def","questionId":"20","status":"","title":"有效的括号","titleSlug":"valid-parentheses"},{"formTitle":"[21]合并两个有序链表","frontendQuestionId":"21","leaf":true,"level":1,"nodeType":"def","questionId":"21","status":"","title":"合并两个有序链表","titleSlug":"merge-two-sorted-lists"},{"formTitle":"[22]括号生成","frontendQuestionId":"22","leaf":true,"level":2,"nodeType":"def","questionId":"22","status":"","title":"括号生成","titleSlug":"generate-parentheses"},{"formTitle":"[23]合并K个排序链表","frontendQuestionId":"23","leaf":true,"level":3,"nodeType":"def","questionId":"23","status":"","title":"合并K个排序链表","titleSlug":"merge-k-sorted-lists"},{"formTitle":"[24]两两交换链表中的节点","frontendQuestionId":"24","leaf":true,"level":2,"nodeType":"def","questionId":"24","status":"","title":"两两交换链表中的节点","titleSlug":"swap-nodes-in-pairs"},{"formTitle":"[25]K 个一组翻转链表","frontendQuestionId":"25","leaf":true,"level":3,"nodeType":"def","questionId":"25","status":"","title":"K 个一组翻转链表","titleSlug":"reverse-nodes-in-k-group"},{"formTitle":"[26]删除排序数组中的重复项","frontendQuestionId":"26","leaf":true,"level":1,"nodeType":"def","questionId":"26","status":"","title":"删除排序数组中的重复项","titleSlug":"remove-duplicates-from-sorted-array"},{"formTitle":"[27]移除元素","frontendQuestionId":"27","leaf":true,"level":1,"nodeType":"def","questionId":"27","status":"","title":"移除元素","titleSlug":"remove-element"},{"formTitle":"[28]实现 strStr()","frontendQuestionId":"28","leaf":true,"level":1,"nodeType":"def","questionId":"28","status":"","title":"实现 strStr()","titleSlug":"implement-strstr"},{"formTitle":"[29]两数相除","frontendQuestionId":"29","leaf":true,"level":2,"nodeType":"def","questionId":"29","status":"","title":"两数相除","titleSlug":"divide-two-integers"},{"formTitle":"[30]串联所有单词的子串","frontendQuestionId":"30","leaf":true,"level":3,"nodeType":"def","questionId":"30","status":"","title":"串联所有单词的子串","titleSlug":"substring-with-concatenation-of-all-words"},{"formTitle":"[31]下一个排列","frontendQuestionId":"31","leaf":true,"level":2,"nodeType":"def","questionId":"31","status":"","title":"下一个排列","titleSlug":"next-permutation"},{"formTitle":"[32]最长有效括号","frontendQuestionId":"32","leaf":true,"level":3,"nodeType":"def","questionId":"32","status":"","title":"最长有效括号","titleSlug":"longest-valid-parentheses"},{"formTitle":"[33]搜索旋转排序数组","frontendQuestionId":"33","leaf":true,"level":2,"nodeType":"def","questionId":"33","status":"","title":"搜索旋转排序数组","titleSlug":"search-in-rotated-sorted-array"},{"formTitle":"[34]在排序数组中查找元素的第一个和最后一个位置","frontendQuestionId":"34","leaf":true,"level":2,"nodeType":"def","questionId":"34","status":"","title":"在排序数组中查找元素的第一个和最后一个位置","titleSlug":"find-first-and-last-position-of-element-in-sorted-array"},{"formTitle":"[35]搜索插入位置","frontendQuestionId":"35","leaf":true,"level":1,"nodeType":"def","questionId":"35","status":"","title":"搜索插入位置","titleSlug":"search-insert-position"},{"formTitle":"[36]有效的数独","frontendQuestionId":"36","leaf":true,"level":2,"nodeType":"def","questionId":"36","status":"","title":"有效的数独","titleSlug":"valid-sudoku"},{"formTitle":"[37]解数独","frontendQuestionId":"37","leaf":true,"level":3,"nodeType":"def","questionId":"37","status":"","title":"解数独","titleSlug":"sudoku-solver"},{"formTitle":"[38]报数","frontendQuestionId":"38","leaf":true,"level":1,"nodeType":"def","questionId":"38","status":"","title":"报数","titleSlug":"count-and-say"},{"formTitle":"[39]组合总和","frontendQuestionId":"39","leaf":true,"level":2,"nodeType":"def","questionId":"39","status":"","title":"组合总和","titleSlug":"combination-sum"},{"formTitle":"[40]组合总和 II","frontendQuestionId":"40","leaf":true,"level":2,"nodeType":"def","questionId":"40","status":"","title":"组合总和 II","titleSlug":"combination-sum-ii"},{"formTitle":"[41]缺失的第一个正数","frontendQuestionId":"41","leaf":true,"level":3,"nodeType":"def","questionId":"41","status":"","title":"缺失的第一个正数","titleSlug":"first-missing-positive"},{"formTitle":"[42]接雨水","frontendQuestionId":"42","leaf":true,"level":3,"nodeType":"def","questionId":"42","status":"","title":"接雨水","titleSlug":"trapping-rain-water"},{"formTitle":"[43]字符串相乘","frontendQuestionId":"43","leaf":true,"level":2,"nodeType":"def","questionId":"43","status":"","title":"字符串相乘","titleSlug":"multiply-strings"},{"formTitle":"[44]通配符匹配","frontendQuestionId":"44","leaf":true,"level":3,"nodeType":"def","questionId":"44","status":"","title":"通配符匹配","titleSlug":"wildcard-matching"},{"formTitle":"[45]跳跃游戏 II","frontendQuestionId":"45","leaf":true,"level":3,"nodeType":"def","questionId":"45","status":"","title":"跳跃游戏 II","titleSlug":"jump-game-ii"},{"formTitle":"[46]全排列","frontendQuestionId":"46","leaf":true,"level":2,"nodeType":"def","questionId":"46","status":"","title":"全排列","titleSlug":"permutations"},{"formTitle":"[47]全排列 II","frontendQuestionId":"47","leaf":true,"level":2,"nodeType":"def","questionId":"47","status":"","title":"全排列 II","titleSlug":"permutations-ii"},{"formTitle":"[48]旋转图像","frontendQuestionId":"48","leaf":true,"level":2,"nodeType":"def","questionId":"48","status":"","title":"旋转图像","titleSlug":"rotate-image"},{"formTitle":"[49]字母异位词分组","frontendQuestionId":"49","leaf":true,"level":2,"nodeType":"def","questionId":"49","status":"","title":"字母异位词分组","titleSlug":"group-anagrams"},{"formTitle":"[50]Pow(x, n)","frontendQuestionId":"50","leaf":true,"level":2,"nodeType":"def","questionId":"50","status":"","title":"Pow(x, n)","titleSlug":"powx-n"},{"formTitle":"[51]N皇后","frontendQuestionId":"51","leaf":true,"level":3,"nodeType":"def","questionId":"51","status":"","title":"N皇后","titleSlug":"n-queens"},{"formTitle":"[52]N皇后 II","frontendQuestionId":"52","leaf":true,"level":3,"nodeType":"def","questionId":"52","status":"","title":"N皇后 II","titleSlug":"n-queens-ii"},{"formTitle":"[53]最大子序和","frontendQuestionId":"53","leaf":true,"level":1,"nodeType":"def","questionId":"53","status":"","title":"最大子序和","titleSlug":"maximum-subarray"},{"formTitle":"[54]螺旋矩阵","frontendQuestionId":"54","leaf":true,"level":2,"nodeType":"def","questionId":"54","status":"","title":"螺旋矩阵","titleSlug":"spiral-matrix"},{"formTitle":"[55]跳跃游戏","frontendQuestionId":"55","leaf":true,"level":2,"nodeType":"def","questionId":"55","status":"","title":"跳跃游戏","titleSlug":"jump-game"},{"formTitle":"[56]合并区间","frontendQuestionId":"56","leaf":true,"level":2,"nodeType":"def","questionId":"56","status":"ac","title":"合并区间","titleSlug":"merge-intervals"},{"formTitle":"[57]插入区间","frontendQuestionId":"57","leaf":true,"level":3,"nodeType":"def","questionId":"57","status":"","title":"插入区间","titleSlug":"insert-interval"},{"formTitle":"[58]最后一个单词的长度","frontendQuestionId":"58","leaf":true,"level":1,"nodeType":"def","questionId":"58","status":"ac","title":"最后一个单词的长度","titleSlug":"length-of-last-word"},{"formTitle":"[59]螺旋矩阵 II","frontendQuestionId":"59","leaf":true,"level":2,"nodeType":"def","questionId":"59","status":"","title":"螺旋矩阵 II","titleSlug":"spiral-matrix-ii"},{"formTitle":"[60]第k个排列","frontendQuestionId":"60","leaf":true,"level":2,"nodeType":"def","questionId":"60","status":"","title":"第k个排列","titleSlug":"permutation-sequence"},{"formTitle":"[61]旋转链表","frontendQuestionId":"61","leaf":true,"level":2,"nodeType":"def","questionId":"61","status":"","title":"旋转链表","titleSlug":"rotate-list"},{"formTitle":"[62]不同路径","frontendQuestionId":"62","leaf":true,"level":2,"nodeType":"def","questionId":"62","status":"","title":"不同路径","titleSlug":"unique-paths"},{"formTitle":"[63]不同路径 II","frontendQuestionId":"63","leaf":true,"level":2,"nodeType":"def","questionId":"63","status":"","title":"不同路径 II","titleSlug":"unique-paths-ii"},{"formTitle":"[64]最小路径和","frontendQuestionId":"64","leaf":true,"level":2,"nodeType":"def","questionId":"64","status":"","title":"最小路径和","titleSlug":"minimum-path-sum"},{"formTitle":"[65]有效数字","frontendQuestionId":"65","leaf":true,"level":3,"nodeType":"def","questionId":"65","status":"","title":"有效数字","titleSlug":"valid-number"},{"formTitle":"[66]加一","frontendQuestionId":"66","leaf":true,"level":1,"nodeType":"def","questionId":"66","status":"","title":"加一","titleSlug":"plus-one"},{"formTitle":"[67]二进制求和","frontendQuestionId":"67","leaf":true,"level":1,"nodeType":"def","questionId":"67","status":"","title":"二进制求和","titleSlug":"add-binary"},{"formTitle":"[68]文本左右对齐","frontendQuestionId":"68","leaf":true,"level":3,"nodeType":"def","questionId":"68","status":"","title":"文本左右对齐","titleSlug":"text-justification"},{"formTitle":"[69]x 的平方根","frontendQuestionId":"69","leaf":true,"level":1,"nodeType":"def","questionId":"69","status":"","title":"x 的平方根","titleSlug":"sqrtx"},{"formTitle":"[70]爬楼梯","frontendQuestionId":"70","leaf":true,"level":1,"nodeType":"def","questionId":"70","status":"","title":"爬楼梯","titleSlug":"climbing-stairs"},{"formTitle":"[71]简化路径","frontendQuestionId":"71","leaf":true,"level":2,"nodeType":"def","questionId":"71","status":"","title":"简化路径","titleSlug":"simplify-path"},{"formTitle":"[72]编辑距离","frontendQuestionId":"72","leaf":true,"level":3,"nodeType":"def","questionId":"72","status":"","title":"编辑距离","titleSlug":"edit-distance"},{"formTitle":"[73]矩阵置零","frontendQuestionId":"73","leaf":true,"level":2,"nodeType":"def","questionId":"73","status":"","title":"矩阵置零","titleSlug":"set-matrix-zeroes"},{"formTitle":"[74]搜索二维矩阵","frontendQuestionId":"74","leaf":true,"level":2,"nodeType":"def","questionId":"74","status":"","title":"搜索二维矩阵","titleSlug":"search-a-2d-matrix"},{"formTitle":"[75]颜色分类","frontendQuestionId":"75","leaf":true,"level":2,"nodeType":"def","questionId":"75","status":"","title":"颜色分类","titleSlug":"sort-colors"},{"formTitle":"[76]最小覆盖子串","frontendQuestionId":"76","leaf":true,"level":3,"nodeType":"def","questionId":"76","status":"","title":"最小覆盖子串","titleSlug":"minimum-window-substring"},{"formTitle":"[77]组合","frontendQuestionId":"77","leaf":true,"level":2,"nodeType":"def","questionId":"77","status":"","title":"组合","titleSlug":"combinations"},{"formTitle":"[78]子集","frontendQuestionId":"78","leaf":true,"level":2,"nodeType":"def","questionId":"78","status":"","title":"子集","titleSlug":"subsets"},{"formTitle":"[79]单词搜索","frontendQuestionId":"79","leaf":true,"level":2,"nodeType":"def","questionId":"79","status":"","title":"单词搜索","titleSlug":"word-search"},{"formTitle":"[80]删除排序数组中的重复项 II","frontendQuestionId":"80","leaf":true,"level":2,"nodeType":"def","questionId":"80","status":"","title":"删除排序数组中的重复项 II","titleSlug":"remove-duplicates-from-sorted-array-ii"},{"formTitle":"[81]搜索旋转排序数组 II","frontendQuestionId":"81","leaf":true,"level":2,"nodeType":"def","questionId":"81","status":"","title":"搜索旋转排序数组 II","titleSlug":"search-in-rotated-sorted-array-ii"},{"formTitle":"[82]删除排序链表中的重复元素 II","frontendQuestionId":"82","leaf":true,"level":2,"nodeType":"def","questionId":"82","status":"","title":"删除排序链表中的重复元素 II","titleSlug":"remove-duplicates-from-sorted-list-ii"},{"formTitle":"[83]删除排序链表中的重复元素","frontendQuestionId":"83","leaf":true,"level":1,"nodeType":"def","questionId":"83","status":"","title":"删除排序链表中的重复元素","titleSlug":"remove-duplicates-from-sorted-list"},{"formTitle":"[84]柱状图中最大的矩形","frontendQuestionId":"84","leaf":true,"level":3,"nodeType":"def","questionId":"84","status":"","title":"柱状图中最大的矩形","titleSlug":"largest-rectangle-in-histogram"},{"formTitle":"[85]最大矩形","frontendQuestionId":"85","leaf":true,"level":3,"nodeType":"def","questionId":"85","status":"","title":"最大矩形","titleSlug":"maximal-rectangle"},{"formTitle":"[86]分隔链表","frontendQuestionId":"86","leaf":true,"level":2,"nodeType":"def","questionId":"86","status":"","title":"分隔链表","titleSlug":"partition-list"},{"formTitle":"[87]扰乱字符串","frontendQuestionId":"87","leaf":true,"level":3,"nodeType":"def","questionId":"87","status":"","title":"扰乱字符串","titleSlug":"scramble-string"},{"formTitle":"[88]合并两个有序数组","frontendQuestionId":"88","leaf":true,"level":1,"nodeType":"def","questionId":"88","status":"","title":"合并两个有序数组","titleSlug":"merge-sorted-array"},{"formTitle":"[89]格雷编码","frontendQuestionId":"89","leaf":true,"level":2,"nodeType":"def","questionId":"89","status":"","title":"格雷编码","titleSlug":"gray-code"},{"formTitle":"[90]子集 II","frontendQuestionId":"90","leaf":true,"level":2,"nodeType":"def","questionId":"90","status":"","title":"子集 II","titleSlug":"subsets-ii"},{"formTitle":"[91]解码方法","frontendQuestionId":"91","leaf":true,"level":2,"nodeType":"def","questionId":"91","status":"","title":"解码方法","titleSlug":"decode-ways"},{"formTitle":"[92]反转链表 II","frontendQuestionId":"92","leaf":true,"level":2,"nodeType":"def","questionId":"92","status":"","title":"反转链表 II","titleSlug":"reverse-linked-list-ii"},{"formTitle":"[93]复原IP地址","frontendQuestionId":"93","leaf":true,"level":2,"nodeType":"def","questionId":"93","status":"","title":"复原IP地址","titleSlug":"restore-ip-addresses"},{"formTitle":"[94]二叉树的中序遍历","frontendQuestionId":"94","leaf":true,"level":2,"nodeType":"def","questionId":"94","status":"","title":"二叉树的中序遍历","titleSlug":"binary-tree-inorder-traversal"},{"formTitle":"[95]不同的二叉搜索树 II","frontendQuestionId":"95","leaf":true,"level":2,"nodeType":"def","questionId":"95","status":"","title":"不同的二叉搜索树 II","titleSlug":"unique-binary-search-trees-ii"},{"formTitle":"[96]不同的二叉搜索树","frontendQuestionId":"96","leaf":true,"level":2,"nodeType":"def","questionId":"96","status":"","title":"不同的二叉搜索树","titleSlug":"unique-binary-search-trees"},{"formTitle":"[97]交错字符串","frontendQuestionId":"97","leaf":true,"level":3,"nodeType":"def","questionId":"97","status":"","title":"交错字符串","titleSlug":"interleaving-string"},{"formTitle":"[98]验证二叉搜索树","frontendQuestionId":"98","leaf":true,"level":2,"nodeType":"def","questionId":"98","status":"","title":"验证二叉搜索树","titleSlug":"validate-binary-search-tree"},{"formTitle":"[99]恢复二叉搜索树","frontendQuestionId":"99","leaf":true,"level":3,"nodeType":"def","questionId":"99","status":"","title":"恢复二叉搜索树","titleSlug":"recover-binary-search-tree"},{"formTitle":"[100]相同的树","frontendQuestionId":"100","leaf":true,"level":1,"nodeType":"def","questionId":"100","status":"","title":"相同的树","titleSlug":"same-tree"},{"formTitle":"[101]对称二叉树","frontendQuestionId":"101","leaf":true,"level":1,"nodeType":"def","questionId":"101","status":"","title":"对称二叉树","titleSlug":"symmetric-tree"},{"formTitle":"[102]二叉树的层次遍历","frontendQuestionId":"102","leaf":true,"level":2,"nodeType":"def","questionId":"102","status":"","title":"二叉树的层次遍历","titleSlug":"binary-tree-level-order-traversal"},{"formTitle":"[103]二叉树的锯齿形层次遍历","frontendQuestionId":"103","leaf":true,"level":2,"nodeType":"def","questionId":"103","status":"","title":"二叉树的锯齿形层次遍历","titleSlug":"binary-tree-zigzag-level-order-traversal"},{"formTitle":"[104]二叉树的最大深度","frontendQuestionId":"104","leaf":true,"level":1,"nodeType":"def","questionId":"104","status":"","title":"二叉树的最大深度","titleSlug":"maximum-depth-of-binary-tree"},{"formTitle":"[105]从前序与中序遍历序列构造二叉树","frontendQuestionId":"105","leaf":true,"level":2,"nodeType":"def","questionId":"105","status":"","title":"从前序与中序遍历序列构造二叉树","titleSlug":"construct-binary-tree-from-preorder-and-inorder-traversal"},{"formTitle":"[106]从中序与后序遍历序列构造二叉树","frontendQuestionId":"106","leaf":true,"level":2,"nodeType":"def","questionId":"106","status":"","title":"从中序与后序遍历序列构造二叉树","titleSlug":"construct-binary-tree-from-inorder-and-postorder-traversal"},{"formTitle":"[107]二叉树的层次遍历 II","frontendQuestionId":"107","leaf":true,"level":1,"nodeType":"def","questionId":"107","status":"","title":"二叉树的层次遍历 II","titleSlug":"binary-tree-level-order-traversal-ii"},{"formTitle":"[108]将有序数组转换为二叉搜索树","frontendQuestionId":"108","leaf":true,"level":1,"nodeType":"def","questionId":"108","status":"","title":"将有序数组转换为二叉搜索树","titleSlug":"convert-sorted-array-to-binary-search-tree"},{"formTitle":"[109]有序链表转换二叉搜索树","frontendQuestionId":"109","leaf":true,"level":2,"nodeType":"def","questionId":"109","status":"","title":"有序链表转换二叉搜索树","titleSlug":"convert-sorted-list-to-binary-search-tree"},{"formTitle":"[110]平衡二叉树","frontendQuestionId":"110","leaf":true,"level":1,"nodeType":"def","questionId":"110","status":"","title":"平衡二叉树","titleSlug":"balanced-binary-tree"},{"formTitle":"[111]二叉树的最小深度","frontendQuestionId":"111","leaf":true,"level":1,"nodeType":"def","questionId":"111","status":"","title":"二叉树的最小深度","titleSlug":"minimum-depth-of-binary-tree"},{"formTitle":"[112]路径总和","frontendQuestionId":"112","leaf":true,"level":1,"nodeType":"def","questionId":"112","status":"","title":"路径总和","titleSlug":"path-sum"},{"formTitle":"[113]路径总和 II","frontendQuestionId":"113","leaf":true,"level":2,"nodeType":"def","questionId":"113","status":"","title":"路径总和 II","titleSlug":"path-sum-ii"},{"formTitle":"[114]二叉树展开为链表","frontendQuestionId":"114","leaf":true,"level":2,"nodeType":"def","questionId":"114","status":"","title":"二叉树展开为链表","titleSlug":"flatten-binary-tree-to-linked-list"},{"formTitle":"[115]不同的子序列","frontendQuestionId":"115","leaf":true,"level":3,"nodeType":"def","questionId":"115","status":"","title":"不同的子序列","titleSlug":"distinct-subsequences"},{"formTitle":"[116]填充每个节点的下一个右侧节点指针","frontendQuestionId":"116","leaf":true,"level":2,"nodeType":"def","questionId":"116","status":"","title":"填充每个节点的下一个右侧节点指针","titleSlug":"populating-next-right-pointers-in-each-node"},{"formTitle":"[117]填充每个节点的下一个右侧节点指针 II","frontendQuestionId":"117","leaf":true,"level":2,"nodeType":"def","questionId":"117","status":"","title":"填充每个节点的下一个右侧节点指针 II","titleSlug":"populating-next-right-pointers-in-each-node-ii"},{"formTitle":"[118]杨辉三角","frontendQuestionId":"118","leaf":true,"level":1,"nodeType":"def","questionId":"118","status":"","title":"杨辉三角","titleSlug":"pascals-triangle"},{"formTitle":"[119]杨辉三角 II","frontendQuestionId":"119","leaf":true,"level":1,"nodeType":"def","questionId":"119","status":"","title":"杨辉三角 II","titleSlug":"pascals-triangle-ii"},{"formTitle":"[120]三角形最小路径和","frontendQuestionId":"120","leaf":true,"level":2,"nodeType":"def","questionId":"120","status":"","title":"三角形最小路径和","titleSlug":"triangle"},{"formTitle":"[121]买卖股票的最佳时机","frontendQuestionId":"121","leaf":true,"level":1,"nodeType":"def","questionId":"121","status":"","title":"买卖股票的最佳时机","titleSlug":"best-time-to-buy-and-sell-stock"},{"formTitle":"[122]买卖股票的最佳时机 II","frontendQuestionId":"122","leaf":true,"level":1,"nodeType":"def","questionId":"122","status":"","title":"买卖股票的最佳时机 II","titleSlug":"best-time-to-buy-and-sell-stock-ii"},{"formTitle":"[123]买卖股票的最佳时机 III","frontendQuestionId":"123","leaf":true,"level":3,"nodeType":"def","questionId":"123","status":"","title":"买卖股票的最佳时机 III","titleSlug":"best-time-to-buy-and-sell-stock-iii"},{"formTitle":"[124]二叉树中的最大路径和","frontendQuestionId":"124","leaf":true,"level":3,"nodeType":"def","questionId":"124","status":"","title":"二叉树中的最大路径和","titleSlug":"binary-tree-maximum-path-sum"},{"formTitle":"[125]验证回文串","frontendQuestionId":"125","leaf":true,"level":1,"nodeType":"def","questionId":"125","status":"","title":"验证回文串","titleSlug":"valid-palindrome"},{"formTitle":"[126]单词接龙 II","frontendQuestionId":"126","leaf":true,"level":3,"nodeType":"def","questionId":"126","status":"","title":"单词接龙 II","titleSlug":"word-ladder-ii"},{"formTitle":"[127]单词接龙","frontendQuestionId":"127","leaf":true,"level":2,"nodeType":"def","questionId":"127","status":"","title":"单词接龙","titleSlug":"word-ladder"},{"formTitle":"[128]最长连续序列","frontendQuestionId":"128","leaf":true,"level":3,"nodeType":"def","questionId":"128","status":"","title":"最长连续序列","titleSlug":"longest-consecutive-sequence"},{"formTitle":"[129]求根到叶子节点数字之和","frontendQuestionId":"129","leaf":true,"level":2,"nodeType":"def","questionId":"129","status":"","title":"求根到叶子节点数字之和","titleSlug":"sum-root-to-leaf-numbers"},{"formTitle":"[130]被围绕的区域","frontendQuestionId":"130","leaf":true,"level":2,"nodeType":"def","questionId":"130","status":"","title":"被围绕的区域","titleSlug":"surrounded-regions"},{"formTitle":"[131]分割回文串","frontendQuestionId":"131","leaf":true,"level":2,"nodeType":"def","questionId":"131","status":"","title":"分割回文串","titleSlug":"palindrome-partitioning"},{"formTitle":"[132]分割回文串 II","frontendQuestionId":"132","leaf":true,"level":3,"nodeType":"def","questionId":"132","status":"","title":"分割回文串 II","titleSlug":"palindrome-partitioning-ii"},{"formTitle":"[133]克隆图","frontendQuestionId":"133","leaf":true,"level":2,"nodeType":"def","questionId":"133","status":"","title":"克隆图","titleSlug":"clone-graph"},{"formTitle":"[134]加油站","frontendQuestionId":"134","leaf":true,"level":2,"nodeType":"def","questionId":"134","status":"","title":"加油站","titleSlug":"gas-station"},{"formTitle":"[135]分发糖果","frontendQuestionId":"135","leaf":true,"level":3,"nodeType":"def","questionId":"135","status":"","title":"分发糖果","titleSlug":"candy"},{"formTitle":"[136]只出现一次的数字","frontendQuestionId":"136","leaf":true,"level":1,"nodeType":"def","questionId":"136","status":"","title":"只出现一次的数字","titleSlug":"single-number"},{"formTitle":"[137]只出现一次的数字 II","frontendQuestionId":"137","leaf":true,"level":2,"nodeType":"def","questionId":"137","status":"","title":"只出现一次的数字 II","titleSlug":"single-number-ii"},{"formTitle":"[138]复制带随机指针的链表","frontendQuestionId":"138","leaf":true,"level":2,"nodeType":"def","questionId":"138","status":"","title":"复制带随机指针的链表","titleSlug":"copy-list-with-random-pointer"},{"formTitle":"[139]单词拆分","frontendQuestionId":"139","leaf":true,"level":2,"nodeType":"def","questionId":"139","status":"","title":"单词拆分","titleSlug":"word-break"},{"formTitle":"[140]单词拆分 II","frontendQuestionId":"140","leaf":true,"level":3,"nodeType":"def","questionId":"140","status":"","title":"单词拆分 II","titleSlug":"word-break-ii"},{"formTitle":"[141]环形链表","frontendQuestionId":"141","leaf":true,"level":1,"nodeType":"def","questionId":"141","status":"","title":"环形链表","titleSlug":"linked-list-cycle"},{"formTitle":"[142]环形链表 II","frontendQuestionId":"142","leaf":true,"level":2,"nodeType":"def","questionId":"142","status":"","title":"环形链表 II","titleSlug":"linked-list-cycle-ii"},{"formTitle":"[143]重排链表","frontendQuestionId":"143","leaf":true,"level":2,"nodeType":"def","questionId":"143","status":"","title":"重排链表","titleSlug":"reorder-list"},{"formTitle":"[144]二叉树的前序遍历","frontendQuestionId":"144","leaf":true,"level":2,"nodeType":"def","questionId":"144","status":"","title":"二叉树的前序遍历","titleSlug":"binary-tree-preorder-traversal"},{"formTitle":"[145]二叉树的后序遍历","frontendQuestionId":"145","leaf":true,"level":3,"nodeType":"def","questionId":"145","status":"","title":"二叉树的后序遍历","titleSlug":"binary-tree-postorder-traversal"},{"formTitle":"[146]LRU缓存机制","frontendQuestionId":"146","leaf":true,"level":2,"nodeType":"def","questionId":"146","status":"ac","title":"LRU缓存机制","titleSlug":"lru-cache"},{"formTitle":"[147]对链表进行插入排序","frontendQuestionId":"147","leaf":true,"level":2,"nodeType":"def","questionId":"147","status":"","title":"对链表进行插入排序","titleSlug":"insertion-sort-list"},{"formTitle":"[148]排序链表","frontendQuestionId":"148","leaf":true,"level":2,"nodeType":"def","questionId":"148","status":"","title":"排序链表","titleSlug":"sort-list"},{"formTitle":"[149]直线上最多的点数","frontendQuestionId":"149","leaf":true,"level":3,"nodeType":"def","questionId":"149","status":"","title":"直线上最多的点数","titleSlug":"max-points-on-a-line"},{"formTitle":"[150]逆波兰表达式求值","frontendQuestionId":"150","leaf":true,"level":2,"nodeType":"def","questionId":"150","status":"","title":"逆波兰表达式求值","titleSlug":"evaluate-reverse-polish-notation"},{"formTitle":"[151]翻转字符串里的单词","frontendQuestionId":"151","leaf":true,"level":2,"nodeType":"def","questionId":"151","status":"","title":"翻转字符串里的单词","titleSlug":"reverse-words-in-a-string"},{"formTitle":"[152]乘积最大子序列","frontendQuestionId":"152","leaf":true,"level":2,"nodeType":"def","questionId":"152","status":"","title":"乘积最大子序列","titleSlug":"maximum-product-subarray"},{"formTitle":"[153]寻找旋转排序数组中的最小值","frontendQuestionId":"153","leaf":true,"level":2,"nodeType":"def","questionId":"153","status":"","title":"寻找旋转排序数组中的最小值","titleSlug":"find-minimum-in-rotated-sorted-array"},{"formTitle":"[154]寻找旋转排序数组中的最小值 II","frontendQuestionId":"154","leaf":true,"level":3,"nodeType":"def","questionId":"154","status":"","title":"寻找旋转排序数组中的最小值 II","titleSlug":"find-minimum-in-rotated-sorted-array-ii"},{"formTitle":"[155]最小栈","frontendQuestionId":"155","leaf":true,"level":1,"nodeType":"def","questionId":"155","status":"","title":"最小栈","titleSlug":"min-stack"},{"formTitle":"[156]上下翻转二叉树","frontendQuestionId":"156","leaf":true,"level":2,"nodeType":"def","questionId":"156","status":"lock","title":"上下翻转二叉树","titleSlug":"binary-tree-upside-down"},{"formTitle":"[157]用 Read4 读取 N 个字符","frontendQuestionId":"157","leaf":true,"level":1,"nodeType":"def","questionId":"157","status":"lock","title":"用 Read4 读取 N 个字符","titleSlug":"read-n-characters-given-read4"},{"formTitle":"[158]用 Read4 读取 N 个字符 II","frontendQuestionId":"158","leaf":true,"level":3,"nodeType":"def","questionId":"158","status":"lock","title":"用 Read4 读取 N 个字符 II","titleSlug":"read-n-characters-given-read4-ii-call-multiple-times"},{"formTitle":"[159]至多包含两个不同字符的最长子串","frontendQuestionId":"159","leaf":true,"level":2,"nodeType":"def","questionId":"159","status":"lock","title":"至多包含两个不同字符的最长子串","titleSlug":"longest-substring-with-at-most-two-distinct-characters"},{"formTitle":"[160]相交链表","frontendQuestionId":"160","leaf":true,"level":1,"nodeType":"def","questionId":"160","status":"","title":"相交链表","titleSlug":"intersection-of-two-linked-lists"},{"formTitle":"[161]相隔为 1 的编辑距离","frontendQuestionId":"161","leaf":true,"level":2,"nodeType":"def","questionId":"161","status":"lock","title":"相隔为 1 的编辑距离","titleSlug":"one-edit-distance"},{"formTitle":"[162]寻找峰值","frontendQuestionId":"162","leaf":true,"level":2,"nodeType":"def","questionId":"162","status":"","title":"寻找峰值","titleSlug":"find-peak-element"},{"formTitle":"[163]缺失的区间","frontendQuestionId":"163","leaf":true,"level":2,"nodeType":"def","questionId":"163","status":"lock","title":"缺失的区间","titleSlug":"missing-ranges"},{"formTitle":"[164]最大间距","frontendQuestionId":"164","leaf":true,"level":3,"nodeType":"def","questionId":"164","status":"","title":"最大间距","titleSlug":"maximum-gap"},{"formTitle":"[165]比较版本号","frontendQuestionId":"165","leaf":true,"level":2,"nodeType":"def","questionId":"165","status":"","title":"比较版本号","titleSlug":"compare-version-numbers"},{"formTitle":"[166]分数到小数","frontendQuestionId":"166","leaf":true,"level":2,"nodeType":"def","questionId":"166","status":"","title":"分数到小数","titleSlug":"fraction-to-recurring-decimal"},{"formTitle":"[167]两数之和 II - 输入有序数组","frontendQuestionId":"167","leaf":true,"level":1,"nodeType":"def","questionId":"167","status":"","title":"两数之和 II - 输入有序数组","titleSlug":"two-sum-ii-input-array-is-sorted"},{"formTitle":"[168]Excel表列名称","frontendQuestionId":"168","leaf":true,"level":1,"nodeType":"def","questionId":"168","status":"","title":"Excel表列名称","titleSlug":"excel-sheet-column-title"},{"formTitle":"[169]多数元素","frontendQuestionId":"169","leaf":true,"level":1,"nodeType":"def","questionId":"169","status":"","title":"多数元素","titleSlug":"majority-element"},{"formTitle":"[170]两数之和 III - 数据结构设计","frontendQuestionId":"170","leaf":true,"level":1,"nodeType":"def","questionId":"170","status":"lock","title":"两数之和 III - 数据结构设计","titleSlug":"two-sum-iii-data-structure-design"},{"formTitle":"[171]Excel表列序号","frontendQuestionId":"171","leaf":true,"level":1,"nodeType":"def","questionId":"171","status":"","title":"Excel表列序号","titleSlug":"excel-sheet-column-number"},{"formTitle":"[172]阶乘后的零","frontendQuestionId":"172","leaf":true,"level":1,"nodeType":"def","questionId":"172","status":"","title":"阶乘后的零","titleSlug":"factorial-trailing-zeroes"},{"formTitle":"[173]二叉搜索树迭代器","frontendQuestionId":"173","leaf":true,"level":2,"nodeType":"def","questionId":"173","status":"","title":"二叉搜索树迭代器","titleSlug":"binary-search-tree-iterator"},{"formTitle":"[174]地下城游戏","frontendQuestionId":"174","leaf":true,"level":3,"nodeType":"def","questionId":"174","status":"","title":"地下城游戏","titleSlug":"dungeon-game"},{"formTitle":"[175]组合两个表","frontendQuestionId":"175","leaf":true,"level":1,"nodeType":"def","questionId":"175","status":"","title":"组合两个表","titleSlug":"combine-two-tables"},{"formTitle":"[176]第二高的薪水","frontendQuestionId":"176","leaf":true,"level":1,"nodeType":"def","questionId":"176","status":"","title":"第二高的薪水","titleSlug":"second-highest-salary"},{"formTitle":"[177]第N高的薪水","frontendQuestionId":"177","leaf":true,"level":2,"nodeType":"def","questionId":"177","status":"","title":"第N高的薪水","titleSlug":"nth-highest-salary"},{"formTitle":"[178]分数排名","frontendQuestionId":"178","leaf":true,"level":2,"nodeType":"def","questionId":"178","status":"","title":"分数排名","titleSlug":"rank-scores"},{"formTitle":"[179]最大数","frontendQuestionId":"179","leaf":true,"level":2,"nodeType":"def","questionId":"179","status":"","title":"最大数","titleSlug":"largest-number"},{"formTitle":"[180]连续出现的数字","frontendQuestionId":"180","leaf":true,"level":2,"nodeType":"def","questionId":"180","status":"","title":"连续出现的数字","titleSlug":"consecutive-numbers"},{"formTitle":"[181]超过经理收入的员工","frontendQuestionId":"181","leaf":true,"level":1,"nodeType":"def","questionId":"181","status":"","title":"超过经理收入的员工","titleSlug":"employees-earning-more-than-their-managers"},{"formTitle":"[182]查找重复的电子邮箱","frontendQuestionId":"182","leaf":true,"level":1,"nodeType":"def","questionId":"182","status":"","title":"查找重复的电子邮箱","titleSlug":"duplicate-emails"},{"formTitle":"[183]从不订购的客户","frontendQuestionId":"183","leaf":true,"level":1,"nodeType":"def","questionId":"183","status":"","title":"从不订购的客户","titleSlug":"customers-who-never-order"},{"formTitle":"[184]部门工资最高的员工","frontendQuestionId":"184","leaf":true,"level":2,"nodeType":"def","questionId":"184","status":"","title":"部门工资最高的员工","titleSlug":"department-highest-salary"},{"formTitle":"[185]部门工资前三高的所有员工","frontendQuestionId":"185","leaf":true,"level":3,"nodeType":"def","questionId":"185","status":"","title":"部门工资前三高的所有员工","titleSlug":"department-top-three-salaries"},{"formTitle":"[186]翻转字符串里的单词 II","frontendQuestionId":"186","leaf":true,"level":2,"nodeType":"def","questionId":"186","status":"lock","title":"翻转字符串里的单词 II","titleSlug":"reverse-words-in-a-string-ii"},{"formTitle":"[187]重复的DNA序列","frontendQuestionId":"187","leaf":true,"level":2,"nodeType":"def","questionId":"187","status":"","title":"重复的DNA序列","titleSlug":"repeated-dna-sequences"},{"formTitle":"[188]买卖股票的最佳时机 IV","frontendQuestionId":"188","leaf":true,"level":3,"nodeType":"def","questionId":"188","status":"","title":"买卖股票的最佳时机 IV","titleSlug":"best-time-to-buy-and-sell-stock-iv"},{"formTitle":"[189]旋转数组","frontendQuestionId":"189","leaf":true,"level":1,"nodeType":"def","questionId":"189","status":"","title":"旋转数组","titleSlug":"rotate-array"},{"formTitle":"[190]颠倒二进制位","frontendQuestionId":"190","leaf":true,"level":1,"nodeType":"def","questionId":"190","status":"","title":"颠倒二进制位","titleSlug":"reverse-bits"},{"formTitle":"[191]位1的个数","frontendQuestionId":"191","leaf":true,"level":1,"nodeType":"def","questionId":"191","status":"ac","title":"位1的个数","titleSlug":"number-of-1-bits"},{"formTitle":"[192]统计词频","frontendQuestionId":"192","leaf":true,"level":2,"nodeType":"def","questionId":"192","status":"","title":"统计词频","titleSlug":"word-frequency"},{"formTitle":"[193]有效电话号码","frontendQuestionId":"193","leaf":true,"level":1,"nodeType":"def","questionId":"193","status":"","title":"有效电话号码","titleSlug":"valid-phone-numbers"},{"formTitle":"[194]转置文件","frontendQuestionId":"194","leaf":true,"level":2,"nodeType":"def","questionId":"194","status":"","title":"转置文件","titleSlug":"transpose-file"},{"formTitle":"[195]第十行","frontendQuestionId":"195","leaf":true,"level":1,"nodeType":"def","questionId":"195","status":"","title":"第十行","titleSlug":"tenth-line"},{"formTitle":"[196]删除重复的电子邮箱","frontendQuestionId":"196","leaf":true,"level":1,"nodeType":"def","questionId":"196","status":"","title":"删除重复的电子邮箱","titleSlug":"delete-duplicate-emails"},{"formTitle":"[197]上升的温度","frontendQuestionId":"197","leaf":true,"level":1,"nodeType":"def","questionId":"197","status":"","title":"上升的温度","titleSlug":"rising-temperature"},{"formTitle":"[198]打家劫舍","frontendQuestionId":"198","leaf":true,"level":1,"nodeType":"def","questionId":"198","status":"","title":"打家劫舍","titleSlug":"house-robber"},{"formTitle":"[199]二叉树的右视图","frontendQuestionId":"199","leaf":true,"level":2,"nodeType":"def","questionId":"199","status":"","title":"二叉树的右视图","titleSlug":"binary-tree-right-side-view"},{"formTitle":"[200]岛屿数量","frontendQuestionId":"200","leaf":true,"level":2,"nodeType":"def","questionId":"200","status":"","title":"岛屿数量","titleSlug":"number-of-islands"},{"formTitle":"[201]数字范围按位与","frontendQuestionId":"201","leaf":true,"level":2,"nodeType":"def","questionId":"201","status":"","title":"数字范围按位与","titleSlug":"bitwise-and-of-numbers-range"},{"formTitle":"[202]快乐数","frontendQuestionId":"202","leaf":true,"level":1,"nodeType":"def","questionId":"202","status":"","title":"快乐数","titleSlug":"happy-number"},{"formTitle":"[203]移除链表元素","frontendQuestionId":"203","leaf":true,"level":1,"nodeType":"def","questionId":"203","status":"","title":"移除链表元素","titleSlug":"remove-linked-list-elements"},{"formTitle":"[204]计数质数","frontendQuestionId":"204","leaf":true,"level":1,"nodeType":"def","questionId":"204","status":"","title":"计数质数","titleSlug":"count-primes"},{"formTitle":"[205]同构字符串","frontendQuestionId":"205","leaf":true,"level":1,"nodeType":"def","questionId":"205","status":"","title":"同构字符串","titleSlug":"isomorphic-strings"},{"formTitle":"[206]反转链表","frontendQuestionId":"206","leaf":true,"level":1,"nodeType":"def","questionId":"206","status":"","title":"反转链表","titleSlug":"reverse-linked-list"},{"formTitle":"[207]课程表","frontendQuestionId":"207","leaf":true,"level":2,"nodeType":"def","questionId":"207","status":"","title":"课程表","titleSlug":"course-schedule"},{"formTitle":"[208]实现 Trie (前缀树)","frontendQuestionId":"208","leaf":true,"level":2,"nodeType":"def","questionId":"208","status":"ac","title":"实现 Trie (前缀树)","titleSlug":"implement-trie-prefix-tree"},{"formTitle":"[209]长度最小的子数组","frontendQuestionId":"209","leaf":true,"level":2,"nodeType":"def","questionId":"209","status":"","title":"长度最小的子数组","titleSlug":"minimum-size-subarray-sum"},{"formTitle":"[210]课程表 II","frontendQuestionId":"210","leaf":true,"level":2,"nodeType":"def","questionId":"210","status":"","title":"课程表 II","titleSlug":"course-schedule-ii"},{"formTitle":"[211]添加与搜索单词 - 数据结构设计","frontendQuestionId":"211","leaf":true,"level":2,"nodeType":"def","questionId":"211","status":"","title":"添加与搜索单词 - 数据结构设计","titleSlug":"add-and-search-word-data-structure-design"},{"formTitle":"[212]单词搜索 II","frontendQuestionId":"212","leaf":true,"level":3,"nodeType":"def","questionId":"212","status":"ac","title":"单词搜索 II","titleSlug":"word-search-ii"},{"formTitle":"[213]打家劫舍 II","frontendQuestionId":"213","leaf":true,"level":2,"nodeType":"def","questionId":"213","status":"","title":"打家劫舍 II","titleSlug":"house-robber-ii"},{"formTitle":"[214]最短回文串","frontendQuestionId":"214","leaf":true,"level":3,"nodeType":"def","questionId":"214","status":"","title":"最短回文串","titleSlug":"shortest-palindrome"},{"formTitle":"[215]数组中的第K个最大元素","frontendQuestionId":"215","leaf":true,"level":2,"nodeType":"def","questionId":"215","status":"","title":"数组中的第K个最大元素","titleSlug":"kth-largest-element-in-an-array"},{"formTitle":"[216]组合总和 III","frontendQuestionId":"216","leaf":true,"level":2,"nodeType":"def","questionId":"216","status":"","title":"组合总和 III","titleSlug":"combination-sum-iii"},{"formTitle":"[217]存在重复元素","frontendQuestionId":"217","leaf":true,"level":1,"nodeType":"def","questionId":"217","status":"","title":"存在重复元素","titleSlug":"contains-duplicate"},{"formTitle":"[218]天际线问题","frontendQuestionId":"218","leaf":true,"level":3,"nodeType":"def","questionId":"218","status":"","title":"天际线问题","titleSlug":"the-skyline-problem"},{"formTitle":"[219]存在重复元素 II","frontendQuestionId":"219","leaf":true,"level":1,"nodeType":"def","questionId":"219","status":"","title":"存在重复元素 II","titleSlug":"contains-duplicate-ii"},{"formTitle":"[220]存在重复元素 III","frontendQuestionId":"220","leaf":true,"level":2,"nodeType":"def","questionId":"220","status":"","title":"存在重复元素 III","titleSlug":"contains-duplicate-iii"},{"formTitle":"[221]最大正方形","frontendQuestionId":"221","leaf":true,"level":2,"nodeType":"def","questionId":"221","status":"","title":"最大正方形","titleSlug":"maximal-square"},{"formTitle":"[222]完全二叉树的节点个数","frontendQuestionId":"222","leaf":true,"level":2,"nodeType":"def","questionId":"222","status":"","title":"完全二叉树的节点个数","titleSlug":"count-complete-tree-nodes"},{"formTitle":"[223]矩形面积","frontendQuestionId":"223","leaf":true,"level":2,"nodeType":"def","questionId":"223","status":"","title":"矩形面积","titleSlug":"rectangle-area"},{"formTitle":"[224]基本计算器","frontendQuestionId":"224","leaf":true,"level":3,"nodeType":"def","questionId":"224","status":"","title":"基本计算器","titleSlug":"basic-calculator"},{"formTitle":"[225]用队列实现栈","frontendQuestionId":"225","leaf":true,"level":1,"nodeType":"def","questionId":"225","status":"","title":"用队列实现栈","titleSlug":"implement-stack-using-queues"},{"formTitle":"[226]翻转二叉树","frontendQuestionId":"226","leaf":true,"level":1,"nodeType":"def","questionId":"226","status":"","title":"翻转二叉树","titleSlug":"invert-binary-tree"},{"formTitle":"[227]基本计算器 II","frontendQuestionId":"227","leaf":true,"level":2,"nodeType":"def","questionId":"227","status":"","title":"基本计算器 II","titleSlug":"basic-calculator-ii"},{"formTitle":"[228]汇总区间","frontendQuestionId":"228","leaf":true,"level":2,"nodeType":"def","questionId":"228","status":"","title":"汇总区间","titleSlug":"summary-ranges"},{"formTitle":"[229]求众数 II","frontendQuestionId":"229","leaf":true,"level":2,"nodeType":"def","questionId":"229","status":"","title":"求众数 II","titleSlug":"majority-element-ii"},{"formTitle":"[230]二叉搜索树中第K小的元素","frontendQuestionId":"230","leaf":true,"level":2,"nodeType":"def","questionId":"230","status":"","title":"二叉搜索树中第K小的元素","titleSlug":"kth-smallest-element-in-a-bst"},{"formTitle":"[231]2的幂","frontendQuestionId":"231","leaf":true,"level":1,"nodeType":"def","questionId":"231","status":"","title":"2的幂","titleSlug":"power-of-two"},{"formTitle":"[232]用栈实现队列","frontendQuestionId":"232","leaf":true,"level":1,"nodeType":"def","questionId":"232","status":"","title":"用栈实现队列","titleSlug":"implement-queue-using-stacks"},{"formTitle":"[233]数字 1 的个数","frontendQuestionId":"233","leaf":true,"level":3,"nodeType":"def","questionId":"233","status":"","title":"数字 1 的个数","titleSlug":"number-of-digit-one"},{"formTitle":"[234]回文链表","frontendQuestionId":"234","leaf":true,"level":1,"nodeType":"def","questionId":"234","status":"","title":"回文链表","titleSlug":"palindrome-linked-list"},{"formTitle":"[235]二叉搜索树的最近公共祖先","frontendQuestionId":"235","leaf":true,"level":1,"nodeType":"def","questionId":"235","status":"","title":"二叉搜索树的最近公共祖先","titleSlug":"lowest-common-ancestor-of-a-binary-search-tree"},{"formTitle":"[236]二叉树的最近公共祖先","frontendQuestionId":"236","leaf":true,"level":2,"nodeType":"def","questionId":"236","status":"","title":"二叉树的最近公共祖先","titleSlug":"lowest-common-ancestor-of-a-binary-tree"},{"formTitle":"[237]删除链表中的节点","frontendQuestionId":"237","leaf":true,"level":1,"nodeType":"def","questionId":"237","status":"","title":"删除链表中的节点","titleSlug":"delete-node-in-a-linked-list"},{"formTitle":"[238]除自身以外数组的乘积","frontendQuestionId":"238","leaf":true,"level":2,"nodeType":"def","questionId":"238","status":"","title":"除自身以外数组的乘积","titleSlug":"product-of-array-except-self"},{"formTitle":"[239]滑动窗口最大值","frontendQuestionId":"239","leaf":true,"level":3,"nodeType":"def","questionId":"239","status":"","title":"滑动窗口最大值","titleSlug":"sliding-window-maximum"},{"formTitle":"[240]搜索二维矩阵 II","frontendQuestionId":"240","leaf":true,"level":2,"nodeType":"def","questionId":"240","status":"","title":"搜索二维矩阵 II","titleSlug":"search-a-2d-matrix-ii"},{"formTitle":"[241]为运算表达式设计优先级","frontendQuestionId":"241","leaf":true,"level":2,"nodeType":"def","questionId":"241","status":"","title":"为运算表达式设计优先级","titleSlug":"different-ways-to-add-parentheses"},{"formTitle":"[242]有效的字母异位词","frontendQuestionId":"242","leaf":true,"level":1,"nodeType":"def","questionId":"242","status":"","title":"有效的字母异位词","titleSlug":"valid-anagram"},{"formTitle":"[243]最短单词距离","frontendQuestionId":"243","leaf":true,"level":1,"nodeType":"def","questionId":"243","status":"lock","title":"最短单词距离","titleSlug":"shortest-word-distance"},{"formTitle":"[244]最短单词距离 II","frontendQuestionId":"244","leaf":true,"level":2,"nodeType":"def","questionId":"244","status":"lock","title":"最短单词距离 II","titleSlug":"shortest-word-distance-ii"},{"formTitle":"[245]最短单词距离 III","frontendQuestionId":"245","leaf":true,"level":2,"nodeType":"def","questionId":"245","status":"lock","title":"最短单词距离 III","titleSlug":"shortest-word-distance-iii"},{"formTitle":"[246]中心对称数","frontendQuestionId":"246","leaf":true,"level":1,"nodeType":"def","questionId":"246","status":"lock","title":"中心对称数","titleSlug":"strobogrammatic-number"},{"formTitle":"[247]中心对称数 II","frontendQuestionId":"247","leaf":true,"level":2,"nodeType":"def","questionId":"247","status":"lock","title":"中心对称数 II","titleSlug":"strobogrammatic-number-ii"},{"formTitle":"[248]中心对称数 III","frontendQuestionId":"248","leaf":true,"level":3,"nodeType":"def","questionId":"248","status":"lock","title":"中心对称数 III","titleSlug":"strobogrammatic-number-iii"},{"formTitle":"[249]移位字符串分组","frontendQuestionId":"249","leaf":true,"level":2,"nodeType":"def","questionId":"249","status":"lock","title":"移位字符串分组","titleSlug":"group-shifted-strings"},{"formTitle":"[250]统计同值子树","frontendQuestionId":"250","leaf":true,"level":2,"nodeType":"def","questionId":"250","status":"lock","title":"统计同值子树","titleSlug":"count-univalue-subtrees"},{"formTitle":"[251]展开二维向量","frontendQuestionId":"251","leaf":true,"level":2,"nodeType":"def","questionId":"251","status":"lock","title":"展开二维向量","titleSlug":"flatten-2d-vector"},{"formTitle":"[252]会议室","frontendQuestionId":"252","leaf":true,"level":1,"nodeType":"def","questionId":"252","status":"lock","title":"会议室","titleSlug":"meeting-rooms"},{"formTitle":"[253]会议室 II","frontendQuestionId":"253","leaf":true,"level":2,"nodeType":"def","questionId":"253","status":"lock","title":"会议室 II","titleSlug":"meeting-rooms-ii"},{"formTitle":"[254]因子的组合","frontendQuestionId":"254","leaf":true,"level":2,"nodeType":"def","questionId":"254","status":"lock","title":"因子的组合","titleSlug":"factor-combinations"},{"formTitle":"[255]验证前序遍历序列二叉搜索树","frontendQuestionId":"255","leaf":true,"level":2,"nodeType":"def","questionId":"255","status":"lock","title":"验证前序遍历序列二叉搜索树","titleSlug":"verify-preorder-sequence-in-binary-search-tree"},{"formTitle":"[256]粉刷房子","frontendQuestionId":"256","leaf":true,"level":1,"nodeType":"def","questionId":"256","status":"lock","title":"粉刷房子","titleSlug":"paint-house"},{"formTitle":"[257]二叉树的所有路径","frontendQuestionId":"257","leaf":true,"level":1,"nodeType":"def","questionId":"257","status":"","title":"二叉树的所有路径","titleSlug":"binary-tree-paths"},{"formTitle":"[258]各位相加","frontendQuestionId":"258","leaf":true,"level":1,"nodeType":"def","questionId":"258","status":"","title":"各位相加","titleSlug":"add-digits"},{"formTitle":"[259]较小的三数之和","frontendQuestionId":"259","leaf":true,"level":2,"nodeType":"def","questionId":"259","status":"lock","title":"较小的三数之和","titleSlug":"3sum-smaller"},{"formTitle":"[260]只出现一次的数字 III","frontendQuestionId":"260","leaf":true,"level":2,"nodeType":"def","questionId":"260","status":"","title":"只出现一次的数字 III","titleSlug":"single-number-iii"},{"formTitle":"[261]以图判树","frontendQuestionId":"261","leaf":true,"level":2,"nodeType":"def","questionId":"261","status":"lock","title":"以图判树","titleSlug":"graph-valid-tree"},{"formTitle":"[262]行程和用户","frontendQuestionId":"262","leaf":true,"level":3,"nodeType":"def","questionId":"262","status":"","title":"行程和用户","titleSlug":"trips-and-users"},{"formTitle":"[263]丑数","frontendQuestionId":"263","leaf":true,"level":1,"nodeType":"def","questionId":"263","status":"","title":"丑数","titleSlug":"ugly-number"},{"formTitle":"[264]丑数 II","frontendQuestionId":"264","leaf":true,"level":2,"nodeType":"def","questionId":"264","status":"","title":"丑数 II","titleSlug":"ugly-number-ii"},{"formTitle":"[265]粉刷房子 II","frontendQuestionId":"265","leaf":true,"level":3,"nodeType":"def","questionId":"265","status":"lock","title":"粉刷房子 II","titleSlug":"paint-house-ii"},{"formTitle":"[266]回文排列","frontendQuestionId":"266","leaf":true,"level":1,"nodeType":"def","questionId":"266","status":"lock","title":"回文排列","titleSlug":"palindrome-permutation"},{"formTitle":"[267]回文排列 II","frontendQuestionId":"267","leaf":true,"level":2,"nodeType":"def","questionId":"267","status":"lock","title":"回文排列 II","titleSlug":"palindrome-permutation-ii"},{"formTitle":"[268]缺失数字","frontendQuestionId":"268","leaf":true,"level":1,"nodeType":"def","questionId":"268","status":"","title":"缺失数字","titleSlug":"missing-number"},{"formTitle":"[269]火星词典","frontendQuestionId":"269","leaf":true,"level":3,"nodeType":"def","questionId":"269","status":"lock","title":"火星词典","titleSlug":"alien-dictionary"},{"formTitle":"[270]最接近的二叉搜索树值","frontendQuestionId":"270","leaf":true,"level":1,"nodeType":"def","questionId":"270","status":"lock","title":"最接近的二叉搜索树值","titleSlug":"closest-binary-search-tree-value"},{"formTitle":"[271]字符串的编码与解码","frontendQuestionId":"271","leaf":true,"level":2,"nodeType":"def","questionId":"271","status":"lock","title":"字符串的编码与解码","titleSlug":"encode-and-decode-strings"},{"formTitle":"[272]最接近的二叉搜索树值 II","frontendQuestionId":"272","leaf":true,"level":3,"nodeType":"def","questionId":"272","status":"lock","title":"最接近的二叉搜索树值 II","titleSlug":"closest-binary-search-tree-value-ii"},{"formTitle":"[273]整数转换英文表示","frontendQuestionId":"273","leaf":true,"level":3,"nodeType":"def","questionId":"273","status":"","title":"整数转换英文表示","titleSlug":"integer-to-english-words"},{"formTitle":"[274]H指数","frontendQuestionId":"274","leaf":true,"level":2,"nodeType":"def","questionId":"274","status":"","title":"H指数","titleSlug":"h-index"},{"formTitle":"[275]H指数 II","frontendQuestionId":"275","leaf":true,"level":2,"nodeType":"def","questionId":"275","status":"","title":"H指数 II","titleSlug":"h-index-ii"},{"formTitle":"[276]栅栏涂色","frontendQuestionId":"276","leaf":true,"level":1,"nodeType":"def","questionId":"276","status":"lock","title":"栅栏涂色","titleSlug":"paint-fence"},{"formTitle":"[277]搜寻名人","frontendQuestionId":"277","leaf":true,"level":2,"nodeType":"def","questionId":"277","status":"lock","title":"搜寻名人","titleSlug":"find-the-celebrity"},{"formTitle":"[278]第一个错误的版本","frontendQuestionId":"278","leaf":true,"level":1,"nodeType":"def","questionId":"278","status":"","title":"第一个错误的版本","titleSlug":"first-bad-version"},{"formTitle":"[279]完全平方数","frontendQuestionId":"279","leaf":true,"level":2,"nodeType":"def","questionId":"279","status":"","title":"完全平方数","titleSlug":"perfect-squares"},{"formTitle":"[280]摆动排序","frontendQuestionId":"280","leaf":true,"level":2,"nodeType":"def","questionId":"280","status":"lock","title":"摆动排序","titleSlug":"wiggle-sort"},{"formTitle":"[281]锯齿迭代器","frontendQuestionId":"281","leaf":true,"level":2,"nodeType":"def","questionId":"281","status":"lock","title":"锯齿迭代器","titleSlug":"zigzag-iterator"},{"formTitle":"[282]给表达式添加运算符","frontendQuestionId":"282","leaf":true,"level":3,"nodeType":"def","questionId":"282","status":"","title":"给表达式添加运算符","titleSlug":"expression-add-operators"},{"formTitle":"[283]移动零","frontendQuestionId":"283","leaf":true,"level":1,"nodeType":"def","questionId":"283","status":"","title":"移动零","titleSlug":"move-zeroes"},{"formTitle":"[284]顶端迭代器","frontendQuestionId":"284","leaf":true,"level":2,"nodeType":"def","questionId":"284","status":"","title":"顶端迭代器","titleSlug":"peeking-iterator"},{"formTitle":"[285]二叉搜索树中的顺序后继","frontendQuestionId":"285","leaf":true,"level":2,"nodeType":"def","questionId":"285","status":"lock","title":"二叉搜索树中的顺序后继","titleSlug":"inorder-successor-in-bst"},{"formTitle":"[286]墙与门","frontendQuestionId":"286","leaf":true,"level":2,"nodeType":"def","questionId":"286","status":"lock","title":"墙与门","titleSlug":"walls-and-gates"},{"formTitle":"[287]寻找重复数","frontendQuestionId":"287","leaf":true,"level":2,"nodeType":"def","questionId":"287","status":"","title":"寻找重复数","titleSlug":"find-the-duplicate-number"},{"formTitle":"[288]单词的唯一缩写","frontendQuestionId":"288","leaf":true,"level":2,"nodeType":"def","questionId":"288","status":"lock","title":"单词的唯一缩写","titleSlug":"unique-word-abbreviation"},{"formTitle":"[289]生命游戏","frontendQuestionId":"289","leaf":true,"level":2,"nodeType":"def","questionId":"289","status":"","title":"生命游戏","titleSlug":"game-of-life"},{"formTitle":"[290]单词规律","frontendQuestionId":"290","leaf":true,"level":1,"nodeType":"def","questionId":"290","status":"","title":"单词规律","titleSlug":"word-pattern"},{"formTitle":"[291]单词规律 II","frontendQuestionId":"291","leaf":true,"level":3,"nodeType":"def","questionId":"291","status":"lock","title":"单词规律 II","titleSlug":"word-pattern-ii"},{"formTitle":"[292]Nim 游戏","frontendQuestionId":"292","leaf":true,"level":1,"nodeType":"def","questionId":"292","status":"","title":"Nim 游戏","titleSlug":"nim-game"},{"formTitle":"[293]翻转游戏","frontendQuestionId":"293","leaf":true,"level":1,"nodeType":"def","questionId":"293","status":"lock","title":"翻转游戏","titleSlug":"flip-game"},{"formTitle":"[294]翻转游戏 II","frontendQuestionId":"294","leaf":true,"level":2,"nodeType":"def","questionId":"294","status":"lock","title":"翻转游戏 II","titleSlug":"flip-game-ii"},{"formTitle":"[295]数据流的中位数","frontendQuestionId":"295","leaf":true,"level":3,"nodeType":"def","questionId":"295","status":"","title":"数据流的中位数","titleSlug":"find-median-from-data-stream"},{"formTitle":"[296]最佳的碰头地点","frontendQuestionId":"296","leaf":true,"level":3,"nodeType":"def","questionId":"296","status":"lock","title":"最佳的碰头地点","titleSlug":"best-meeting-point"},{"formTitle":"[297]二叉树的序列化与反序列化","frontendQuestionId":"297","leaf":true,"level":3,"nodeType":"def","questionId":"297","status":"","title":"二叉树的序列化与反序列化","titleSlug":"serialize-and-deserialize-binary-tree"},{"formTitle":"[298]二叉树最长连续序列","frontendQuestionId":"298","leaf":true,"level":2,"nodeType":"def","questionId":"298","status":"lock","title":"二叉树最长连续序列","titleSlug":"binary-tree-longest-consecutive-sequence"},{"formTitle":"[299]猜数字游戏","frontendQuestionId":"299","leaf":true,"level":1,"nodeType":"def","questionId":"299","status":"","title":"猜数字游戏","titleSlug":"bulls-and-cows"},{"formTitle":"[300]最长上升子序列","frontendQuestionId":"300","leaf":true,"level":2,"nodeType":"def","questionId":"300","status":"","title":"最长上升子序列","titleSlug":"longest-increasing-subsequence"},{"formTitle":"[301]删除无效的括号","frontendQuestionId":"301","leaf":true,"level":3,"nodeType":"def","questionId":"301","status":"","title":"删除无效的括号","titleSlug":"remove-invalid-parentheses"},{"formTitle":"[302]包含全部黑色像素的最小矩形","frontendQuestionId":"302","leaf":true,"level":3,"nodeType":"def","questionId":"302","status":"lock","title":"包含全部黑色像素的最小矩形","titleSlug":"smallest-rectangle-enclosing-black-pixels"},{"formTitle":"[303]区域和检索 - 数组不可变","frontendQuestionId":"303","leaf":true,"level":1,"nodeType":"def","questionId":"303","status":"","title":"区域和检索 - 数组不可变","titleSlug":"range-sum-query-immutable"},{"formTitle":"[304]二维区域和检索 - 矩阵不可变","frontendQuestionId":"304","leaf":true,"level":2,"nodeType":"def","questionId":"304","status":"","title":"二维区域和检索 - 矩阵不可变","titleSlug":"range-sum-query-2d-immutable"},{"formTitle":"[305]岛屿数量 II","frontendQuestionId":"305","leaf":true,"level":3,"nodeType":"def","questionId":"305","status":"lock","title":"岛屿数量 II","titleSlug":"number-of-islands-ii"},{"formTitle":"[306]累加数","frontendQuestionId":"306","leaf":true,"level":2,"nodeType":"def","questionId":"306","status":"","title":"累加数","titleSlug":"additive-number"},{"formTitle":"[307]区域和检索 - 数组可修改","frontendQuestionId":"307","leaf":true,"level":2,"nodeType":"def","questionId":"307","status":"","title":"区域和检索 - 数组可修改","titleSlug":"range-sum-query-mutable"},{"formTitle":"[308]二维区域和检索 - 可变","frontendQuestionId":"308","leaf":true,"level":3,"nodeType":"def","questionId":"308","status":"lock","title":"二维区域和检索 - 可变","titleSlug":"range-sum-query-2d-mutable"},{"formTitle":"[309]最佳买卖股票时机含冷冻期","frontendQuestionId":"309","leaf":true,"level":2,"nodeType":"def","questionId":"309","status":"","title":"最佳买卖股票时机含冷冻期","titleSlug":"best-time-to-buy-and-sell-stock-with-cooldown"},{"formTitle":"[310]最小高度树","frontendQuestionId":"310","leaf":true,"level":2,"nodeType":"def","questionId":"310","status":"","title":"最小高度树","titleSlug":"minimum-height-trees"},{"formTitle":"[311]稀疏矩阵的乘法","frontendQuestionId":"311","leaf":true,"level":2,"nodeType":"def","questionId":"311","status":"lock","title":"稀疏矩阵的乘法","titleSlug":"sparse-matrix-multiplication"},{"formTitle":"[312]戳气球","frontendQuestionId":"312","leaf":true,"level":3,"nodeType":"def","questionId":"312","status":"","title":"戳气球","titleSlug":"burst-balloons"},{"formTitle":"[313]超级丑数","frontendQuestionId":"313","leaf":true,"level":2,"nodeType":"def","questionId":"313","status":"","title":"超级丑数","titleSlug":"super-ugly-number"},{"formTitle":"[314]二叉树的垂直遍历","frontendQuestionId":"314","leaf":true,"level":2,"nodeType":"def","questionId":"314","status":"lock","title":"二叉树的垂直遍历","titleSlug":"binary-tree-vertical-order-traversal"},{"formTitle":"[315]计算右侧小于当前元素的个数","frontendQuestionId":"315","leaf":true,"level":3,"nodeType":"def","questionId":"315","status":"","title":"计算右侧小于当前元素的个数","titleSlug":"count-of-smaller-numbers-after-self"},{"formTitle":"[316]去除重复字母","frontendQuestionId":"316","leaf":true,"level":3,"nodeType":"def","questionId":"316","status":"","title":"去除重复字母","titleSlug":"remove-duplicate-letters"},{"formTitle":"[317]离建筑物最近的距离","frontendQuestionId":"317","leaf":true,"level":3,"nodeType":"def","questionId":"317","status":"lock","title":"离建筑物最近的距离","titleSlug":"shortest-distance-from-all-buildings"},{"formTitle":"[318]最大单词长度乘积","frontendQuestionId":"318","leaf":true,"level":2,"nodeType":"def","questionId":"318","status":"","title":"最大单词长度乘积","titleSlug":"maximum-product-of-word-lengths"},{"formTitle":"[319]灯泡开关","frontendQuestionId":"319","leaf":true,"level":2,"nodeType":"def","questionId":"319","status":"","title":"灯泡开关","titleSlug":"bulb-switcher"},{"formTitle":"[320]列举单词的全部缩写","frontendQuestionId":"320","leaf":true,"level":2,"nodeType":"def","questionId":"320","status":"lock","title":"列举单词的全部缩写","titleSlug":"generalized-abbreviation"},{"formTitle":"[321]拼接最大数","frontendQuestionId":"321","leaf":true,"level":3,"nodeType":"def","questionId":"321","status":"","title":"拼接最大数","titleSlug":"create-maximum-number"},{"formTitle":"[322]零钱兑换","frontendQuestionId":"322","leaf":true,"level":2,"nodeType":"def","questionId":"322","status":"","title":"零钱兑换","titleSlug":"coin-change"},{"formTitle":"[323]无向图中连通分量的数目","frontendQuestionId":"323","leaf":true,"level":2,"nodeType":"def","questionId":"323","status":"lock","title":"无向图中连通分量的数目","titleSlug":"number-of-connected-components-in-an-undirected-graph"},{"formTitle":"[324]摆动排序 II","frontendQuestionId":"324","leaf":true,"level":2,"nodeType":"def","questionId":"324","status":"","title":"摆动排序 II","titleSlug":"wiggle-sort-ii"},{"formTitle":"[325]和等于 k 的最长子数组长度","frontendQuestionId":"325","leaf":true,"level":2,"nodeType":"def","questionId":"325","status":"lock","title":"和等于 k 的最长子数组长度","titleSlug":"maximum-size-subarray-sum-equals-k"},{"formTitle":"[326]3的幂","frontendQuestionId":"326","leaf":true,"level":1,"nodeType":"def","questionId":"326","status":"","title":"3的幂","titleSlug":"power-of-three"},{"formTitle":"[327]区间和的个数","frontendQuestionId":"327","leaf":true,"level":3,"nodeType":"def","questionId":"327","status":"","title":"区间和的个数","titleSlug":"count-of-range-sum"},{"formTitle":"[328]奇偶链表","frontendQuestionId":"328","leaf":true,"level":2,"nodeType":"def","questionId":"328","status":"","title":"奇偶链表","titleSlug":"odd-even-linked-list"},{"formTitle":"[329]矩阵中的最长递增路径","frontendQuestionId":"329","leaf":true,"level":3,"nodeType":"def","questionId":"329","status":"","title":"矩阵中的最长递增路径","titleSlug":"longest-increasing-path-in-a-matrix"},{"formTitle":"[330]按要求补齐数组","frontendQuestionId":"330","leaf":true,"level":3,"nodeType":"def","questionId":"330","status":"","title":"按要求补齐数组","titleSlug":"patching-array"},{"formTitle":"[331]验证二叉树的前序序列化","frontendQuestionId":"331","leaf":true,"level":2,"nodeType":"def","questionId":"331","status":"","title":"验证二叉树的前序序列化","titleSlug":"verify-preorder-serialization-of-a-binary-tree"},{"formTitle":"[332]重新安排行程","frontendQuestionId":"332","leaf":true,"level":2,"nodeType":"def","questionId":"332","status":"","title":"重新安排行程","titleSlug":"reconstruct-itinerary"},{"formTitle":"[333]最大 BST 子树","frontendQuestionId":"333","leaf":true,"level":2,"nodeType":"def","questionId":"333","status":"lock","title":"最大 BST 子树","titleSlug":"largest-bst-subtree"},{"formTitle":"[334]递增的三元子序列","frontendQuestionId":"334","leaf":true,"level":2,"nodeType":"def","questionId":"334","status":"","title":"递增的三元子序列","titleSlug":"increasing-triplet-subsequence"},{"formTitle":"[335]路径交叉","frontendQuestionId":"335","leaf":true,"level":3,"nodeType":"def","questionId":"335","status":"","title":"路径交叉","titleSlug":"self-crossing"},{"formTitle":"[336]回文对","frontendQuestionId":"336","leaf":true,"level":3,"nodeType":"def","questionId":"336","status":"","title":"回文对","titleSlug":"palindrome-pairs"},{"formTitle":"[337]打家劫舍 III","frontendQuestionId":"337","leaf":true,"level":2,"nodeType":"def","questionId":"337","status":"","title":"打家劫舍 III","titleSlug":"house-robber-iii"},{"formTitle":"[338]比特位计数","frontendQuestionId":"338","leaf":true,"level":2,"nodeType":"def","questionId":"338","status":"","title":"比特位计数","titleSlug":"counting-bits"},{"formTitle":"[339]嵌套列表权重和","frontendQuestionId":"339","leaf":true,"level":1,"nodeType":"def","questionId":"339","status":"lock","title":"嵌套列表权重和","titleSlug":"nested-list-weight-sum"},{"formTitle":"[340]至多包含 K 个不同字符的最长子串","frontendQuestionId":"340","leaf":true,"level":3,"nodeType":"def","questionId":"340","status":"lock","title":"至多包含 K 个不同字符的最长子串","titleSlug":"longest-substring-with-at-most-k-distinct-characters"},{"formTitle":"[341]扁平化嵌套列表迭代器","frontendQuestionId":"341","leaf":true,"level":2,"nodeType":"def","questionId":"341","status":"","title":"扁平化嵌套列表迭代器","titleSlug":"flatten-nested-list-iterator"},{"formTitle":"[342]4的幂","frontendQuestionId":"342","leaf":true,"level":1,"nodeType":"def","questionId":"342","status":"","title":"4的幂","titleSlug":"power-of-four"},{"formTitle":"[343]整数拆分","frontendQuestionId":"343","leaf":true,"level":2,"nodeType":"def","questionId":"343","status":"","title":"整数拆分","titleSlug":"integer-break"},{"formTitle":"[344]反转字符串","frontendQuestionId":"344","leaf":true,"level":1,"nodeType":"def","questionId":"344","status":"","title":"反转字符串","titleSlug":"reverse-string"},{"formTitle":"[345]反转字符串中的元音字母","frontendQuestionId":"345","leaf":true,"level":1,"nodeType":"def","questionId":"345","status":"","title":"反转字符串中的元音字母","titleSlug":"reverse-vowels-of-a-string"},{"formTitle":"[346]数据流中的移动平均值","frontendQuestionId":"346","leaf":true,"level":1,"nodeType":"def","questionId":"346","status":"lock","title":"数据流中的移动平均值","titleSlug":"moving-average-from-data-stream"},{"formTitle":"[347]前 K 个高频元素","frontendQuestionId":"347","leaf":true,"level":2,"nodeType":"def","questionId":"347","status":"","title":"前 K 个高频元素","titleSlug":"top-k-frequent-elements"},{"formTitle":"[348]判定井字棋胜负","frontendQuestionId":"348","leaf":true,"level":2,"nodeType":"def","questionId":"348","status":"lock","title":"判定井字棋胜负","titleSlug":"design-tic-tac-toe"},{"formTitle":"[349]两个数组的交集","frontendQuestionId":"349","leaf":true,"level":1,"nodeType":"def","questionId":"349","status":"","title":"两个数组的交集","titleSlug":"intersection-of-two-arrays"},{"formTitle":"[350]两个数组的交集 II","frontendQuestionId":"350","leaf":true,"level":1,"nodeType":"def","questionId":"350","status":"","title":"两个数组的交集 II","titleSlug":"intersection-of-two-arrays-ii"},{"formTitle":"[351]安卓系统手势解锁","frontendQuestionId":"351","leaf":true,"level":2,"nodeType":"def","questionId":"351","status":"lock","title":"安卓系统手势解锁","titleSlug":"android-unlock-patterns"},{"formTitle":"[352]将数据流变为多个不相交区间","frontendQuestionId":"352","leaf":true,"level":3,"nodeType":"def","questionId":"352","status":"","title":"将数据流变为多个不相交区间","titleSlug":"data-stream-as-disjoint-intervals"},{"formTitle":"[353]贪吃蛇","frontendQuestionId":"353","leaf":true,"level":2,"nodeType":"def","questionId":"353","status":"lock","title":"贪吃蛇","titleSlug":"design-snake-game"},{"formTitle":"[354]俄罗斯套娃信封问题","frontendQuestionId":"354","leaf":true,"level":3,"nodeType":"def","questionId":"354","status":"","title":"俄罗斯套娃信封问题","titleSlug":"russian-doll-envelopes"},{"formTitle":"[355]设计推特","frontendQuestionId":"355","leaf":true,"level":2,"nodeType":"def","questionId":"355","status":"","title":"设计推特","titleSlug":"design-twitter"},{"formTitle":"[356]直线镜像","frontendQuestionId":"356","leaf":true,"level":2,"nodeType":"def","questionId":"356","status":"lock","title":"直线镜像","titleSlug":"line-reflection"},{"formTitle":"[357]计算各个位数不同的数字个数","frontendQuestionId":"357","leaf":true,"level":2,"nodeType":"def","questionId":"357","status":"","title":"计算各个位数不同的数字个数","titleSlug":"count-numbers-with-unique-digits"},{"formTitle":"[358]K 距离间隔重排字符串","frontendQuestionId":"358","leaf":true,"level":3,"nodeType":"def","questionId":"358","status":"lock","title":"K 距离间隔重排字符串","titleSlug":"rearrange-string-k-distance-apart"},{"formTitle":"[359]日志速率限制器","frontendQuestionId":"359","leaf":true,"level":1,"nodeType":"def","questionId":"359","status":"lock","title":"日志速率限制器","titleSlug":"logger-rate-limiter"},{"formTitle":"[360]有序转化数组","frontendQuestionId":"360","leaf":true,"level":2,"nodeType":"def","questionId":"360","status":"lock","title":"有序转化数组","titleSlug":"sort-transformed-array"},{"formTitle":"[361]轰炸敌人","frontendQuestionId":"361","leaf":true,"level":2,"nodeType":"def","questionId":"361","status":"lock","title":"轰炸敌人","titleSlug":"bomb-enemy"},{"formTitle":"[362]敲击计数器","frontendQuestionId":"362","leaf":true,"level":2,"nodeType":"def","questionId":"362","status":"lock","title":"敲击计数器","titleSlug":"design-hit-counter"},{"formTitle":"[363]矩形区域不超过 K 的最大数值和","frontendQuestionId":"363","leaf":true,"level":3,"nodeType":"def","questionId":"363","status":"","title":"矩形区域不超过 K 的最大数值和","titleSlug":"max-sum-of-rectangle-no-larger-than-k"},{"formTitle":"[364]加权嵌套序列和 II","frontendQuestionId":"364","leaf":true,"level":2,"nodeType":"def","questionId":"364","status":"lock","title":"加权嵌套序列和 II","titleSlug":"nested-list-weight-sum-ii"},{"formTitle":"[365]水壶问题","frontendQuestionId":"365","leaf":true,"level":2,"nodeType":"def","questionId":"365","status":"","title":"水壶问题","titleSlug":"water-and-jug-problem"},{"formTitle":"[366]寻找完全二叉树的叶子节点","frontendQuestionId":"366","leaf":true,"level":2,"nodeType":"def","questionId":"366","status":"lock","title":"寻找完全二叉树的叶子节点","titleSlug":"find-leaves-of-binary-tree"},{"formTitle":"[367]有效的完全平方数","frontendQuestionId":"367","leaf":true,"level":1,"nodeType":"def","questionId":"367","status":"","title":"有效的完全平方数","titleSlug":"valid-perfect-square"},{"formTitle":"[368]最大整除子集","frontendQuestionId":"368","leaf":true,"level":2,"nodeType":"def","questionId":"368","status":"","title":"最大整除子集","titleSlug":"largest-divisible-subset"},{"formTitle":"[369]给单链表加一","frontendQuestionId":"369","leaf":true,"level":2,"nodeType":"def","questionId":"369","status":"lock","title":"给单链表加一","titleSlug":"plus-one-linked-list"},{"formTitle":"[370]区间加法","frontendQuestionId":"370","leaf":true,"level":2,"nodeType":"def","questionId":"370","status":"lock","title":"区间加法","titleSlug":"range-addition"},{"formTitle":"[371]两整数之和","frontendQuestionId":"371","leaf":true,"level":1,"nodeType":"def","questionId":"371","status":"","title":"两整数之和","titleSlug":"sum-of-two-integers"},{"formTitle":"[372]超级次方","frontendQuestionId":"372","leaf":true,"level":2,"nodeType":"def","questionId":"372","status":"","title":"超级次方","titleSlug":"super-pow"},{"formTitle":"[373]查找和最小的K对数字","frontendQuestionId":"373","leaf":true,"level":2,"nodeType":"def","questionId":"373","status":"","title":"查找和最小的K对数字","titleSlug":"find-k-pairs-with-smallest-sums"},{"formTitle":"[374]猜数字大小","frontendQuestionId":"374","leaf":true,"level":1,"nodeType":"def","questionId":"374","status":"","title":"猜数字大小","titleSlug":"guess-number-higher-or-lower"},{"formTitle":"[375]猜数字大小 II","frontendQuestionId":"375","leaf":true,"level":2,"nodeType":"def","questionId":"375","status":"","title":"猜数字大小 II","titleSlug":"guess-number-higher-or-lower-ii"},{"formTitle":"[376]摆动序列","frontendQuestionId":"376","leaf":true,"level":2,"nodeType":"def","questionId":"376","status":"","title":"摆动序列","titleSlug":"wiggle-subsequence"},{"formTitle":"[377]组合总和 Ⅳ","frontendQuestionId":"377","leaf":true,"level":2,"nodeType":"def","questionId":"377","status":"","title":"组合总和 Ⅳ","titleSlug":"combination-sum-iv"},{"formTitle":"[378]有序矩阵中第K小的元素","frontendQuestionId":"378","leaf":true,"level":2,"nodeType":"def","questionId":"378","status":"","title":"有序矩阵中第K小的元素","titleSlug":"kth-smallest-element-in-a-sorted-matrix"},{"formTitle":"[379]电话目录管理系统","frontendQuestionId":"379","leaf":true,"level":2,"nodeType":"def","questionId":"379","status":"lock","title":"电话目录管理系统","titleSlug":"design-phone-directory"},{"formTitle":"[380]常数时间插入、删除和获取随机元素","frontendQuestionId":"380","leaf":true,"level":2,"nodeType":"def","questionId":"380","status":"","title":"常数时间插入、删除和获取随机元素","titleSlug":"insert-delete-getrandom-o1"},{"formTitle":"[381]O(1) 时间插入、删除和获取随机元素 - 允许重复","frontendQuestionId":"381","leaf":true,"level":3,"nodeType":"def","questionId":"381","status":"","title":"O(1) 时间插入、删除和获取随机元素 - 允许重复","titleSlug":"insert-delete-getrandom-o1-duplicates-allowed"},{"formTitle":"[382]链表随机节点","frontendQuestionId":"382","leaf":true,"level":2,"nodeType":"def","questionId":"382","status":"","title":"链表随机节点","titleSlug":"linked-list-random-node"},{"formTitle":"[383]赎金信","frontendQuestionId":"383","leaf":true,"level":1,"nodeType":"def","questionId":"383","status":"","title":"赎金信","titleSlug":"ransom-note"},{"formTitle":"[384]打乱数组","frontendQuestionId":"384","leaf":true,"level":2,"nodeType":"def","questionId":"384","status":"","title":"打乱数组","titleSlug":"shuffle-an-array"},{"formTitle":"[385]迷你语法分析器","frontendQuestionId":"385","leaf":true,"level":2,"nodeType":"def","questionId":"385","status":"","title":"迷你语法分析器","titleSlug":"mini-parser"},{"formTitle":"[386]字典序排数","frontendQuestionId":"386","leaf":true,"level":2,"nodeType":"def","questionId":"386","status":"","title":"字典序排数","titleSlug":"lexicographical-numbers"},{"formTitle":"[387]字符串中的第一个唯一字符","frontendQuestionId":"387","leaf":true,"level":1,"nodeType":"def","questionId":"387","status":"","title":"字符串中的第一个唯一字符","titleSlug":"first-unique-character-in-a-string"},{"formTitle":"[388]文件的最长绝对路径","frontendQuestionId":"388","leaf":true,"level":2,"nodeType":"def","questionId":"388","status":"","title":"文件的最长绝对路径","titleSlug":"longest-absolute-file-path"},{"formTitle":"[389]找不同","frontendQuestionId":"389","leaf":true,"level":1,"nodeType":"def","questionId":"389","status":"","title":"找不同","titleSlug":"find-the-difference"},{"formTitle":"[390]消除游戏","frontendQuestionId":"390","leaf":true,"level":2,"nodeType":"def","questionId":"390","status":"","title":"消除游戏","titleSlug":"elimination-game"},{"formTitle":"[391]完美矩形","frontendQuestionId":"391","leaf":true,"level":3,"nodeType":"def","questionId":"391","status":"","title":"完美矩形","titleSlug":"perfect-rectangle"},{"formTitle":"[392]判断子序列","frontendQuestionId":"392","leaf":true,"level":1,"nodeType":"def","questionId":"392","status":"","title":"判断子序列","titleSlug":"is-subsequence"},{"formTitle":"[393]UTF-8 编码验证","frontendQuestionId":"393","leaf":true,"level":2,"nodeType":"def","questionId":"393","status":"","title":"UTF-8 编码验证","titleSlug":"utf-8-validation"},{"formTitle":"[394]字符串解码","frontendQuestionId":"394","leaf":true,"level":2,"nodeType":"def","questionId":"394","status":"","title":"字符串解码","titleSlug":"decode-string"},{"formTitle":"[395]至少有K个重复字符的最长子串","frontendQuestionId":"395","leaf":true,"level":2,"nodeType":"def","questionId":"395","status":"","title":"至少有K个重复字符的最长子串","titleSlug":"longest-substring-with-at-least-k-repeating-characters"},{"formTitle":"[396]旋转函数","frontendQuestionId":"396","leaf":true,"level":2,"nodeType":"def","questionId":"396","status":"","title":"旋转函数","titleSlug":"rotate-function"},{"formTitle":"[397]整数替换","frontendQuestionId":"397","leaf":true,"level":2,"nodeType":"def","questionId":"397","status":"","title":"整数替换","titleSlug":"integer-replacement"},{"formTitle":"[398]随机数索引","frontendQuestionId":"398","leaf":true,"level":2,"nodeType":"def","questionId":"398","status":"","title":"随机数索引","titleSlug":"random-pick-index"},{"formTitle":"[399]除法求值","frontendQuestionId":"399","leaf":true,"level":2,"nodeType":"def","questionId":"399","status":"","title":"除法求值","titleSlug":"evaluate-division"},{"formTitle":"[400]第N个数字","frontendQuestionId":"400","leaf":true,"level":2,"nodeType":"def","questionId":"400","status":"","title":"第N个数字","titleSlug":"nth-digit"},{"formTitle":"[401]二进制手表","frontendQuestionId":"401","leaf":true,"level":1,"nodeType":"def","questionId":"401","status":"","title":"二进制手表","titleSlug":"binary-watch"},{"formTitle":"[402]移掉K位数字","frontendQuestionId":"402","leaf":true,"level":2,"nodeType":"def","questionId":"402","status":"","title":"移掉K位数字","titleSlug":"remove-k-digits"},{"formTitle":"[403]青蛙过河","frontendQuestionId":"403","leaf":true,"level":3,"nodeType":"def","questionId":"403","status":"","title":"青蛙过河","titleSlug":"frog-jump"},{"formTitle":"[404]左叶子之和","frontendQuestionId":"404","leaf":true,"level":1,"nodeType":"def","questionId":"404","status":"","title":"左叶子之和","titleSlug":"sum-of-left-leaves"},{"formTitle":"[405]数字转换为十六进制数","frontendQuestionId":"405","leaf":true,"level":1,"nodeType":"def","questionId":"405","status":"","title":"数字转换为十六进制数","titleSlug":"convert-a-number-to-hexadecimal"},{"formTitle":"[406]根据身高重建队列","frontendQuestionId":"406","leaf":true,"level":2,"nodeType":"def","questionId":"406","status":"","title":"根据身高重建队列","titleSlug":"queue-reconstruction-by-height"},{"formTitle":"[407]接雨水 II","frontendQuestionId":"407","leaf":true,"level":3,"nodeType":"def","questionId":"407","status":"","title":"接雨水 II","titleSlug":"trapping-rain-water-ii"},{"formTitle":"[408]有效单词缩写","frontendQuestionId":"408","leaf":true,"level":1,"nodeType":"def","questionId":"408","status":"lock","title":"有效单词缩写","titleSlug":"valid-word-abbreviation"},{"formTitle":"[409]最长回文串","frontendQuestionId":"409","leaf":true,"level":1,"nodeType":"def","questionId":"409","status":"","title":"最长回文串","titleSlug":"longest-palindrome"},{"formTitle":"[410]分割数组的最大值","frontendQuestionId":"410","leaf":true,"level":3,"nodeType":"def","questionId":"410","status":"","title":"分割数组的最大值","titleSlug":"split-array-largest-sum"},{"formTitle":"[411]最短特异单词缩写","frontendQuestionId":"411","leaf":true,"level":3,"nodeType":"def","questionId":"411","status":"lock","title":"最短特异单词缩写","titleSlug":"minimum-unique-word-abbreviation"},{"formTitle":"[412]Fizz Buzz","frontendQuestionId":"412","leaf":true,"level":1,"nodeType":"def","questionId":"412","status":"","title":"Fizz Buzz","titleSlug":"fizz-buzz"},{"formTitle":"[413]等差数列划分","frontendQuestionId":"413","leaf":true,"level":2,"nodeType":"def","questionId":"413","status":"","title":"等差数列划分","titleSlug":"arithmetic-slices"},{"formTitle":"[414]第三大的数","frontendQuestionId":"414","leaf":true,"level":1,"nodeType":"def","questionId":"414","status":"","title":"第三大的数","titleSlug":"third-maximum-number"},{"formTitle":"[415]字符串相加","frontendQuestionId":"415","leaf":true,"level":1,"nodeType":"def","questionId":"415","status":"","title":"字符串相加","titleSlug":"add-strings"},{"formTitle":"[416]分割等和子集","frontendQuestionId":"416","leaf":true,"level":2,"nodeType":"def","questionId":"416","status":"","title":"分割等和子集","titleSlug":"partition-equal-subset-sum"},{"formTitle":"[417]太平洋大西洋水流问题","frontendQuestionId":"417","leaf":true,"level":2,"nodeType":"def","questionId":"417","status":"","title":"太平洋大西洋水流问题","titleSlug":"pacific-atlantic-water-flow"},{"formTitle":"[418]屏幕可显示句子的数量","frontendQuestionId":"418","leaf":true,"level":2,"nodeType":"def","questionId":"418","status":"lock","title":"屏幕可显示句子的数量","titleSlug":"sentence-screen-fitting"},{"formTitle":"[419]甲板上的战舰","frontendQuestionId":"419","leaf":true,"level":2,"nodeType":"def","questionId":"419","status":"","title":"甲板上的战舰","titleSlug":"battleships-in-a-board"},{"formTitle":"[420]强密码检验器","frontendQuestionId":"420","leaf":true,"level":3,"nodeType":"def","questionId":"420","status":"","title":"强密码检验器","titleSlug":"strong-password-checker"},{"formTitle":"[421]数组中两个数的最大异或值","frontendQuestionId":"421","leaf":true,"level":2,"nodeType":"def","questionId":"421","status":"","title":"数组中两个数的最大异或值","titleSlug":"maximum-xor-of-two-numbers-in-an-array"},{"formTitle":"[422]有效的单词方块","frontendQuestionId":"422","leaf":true,"level":1,"nodeType":"def","questionId":"422","status":"lock","title":"有效的单词方块","titleSlug":"valid-word-square"},{"formTitle":"[423]从英文中重建数字","frontendQuestionId":"423","leaf":true,"level":2,"nodeType":"def","questionId":"423","status":"","title":"从英文中重建数字","titleSlug":"reconstruct-original-digits-from-english"},{"formTitle":"[424]替换后的最长重复字符","frontendQuestionId":"424","leaf":true,"level":2,"nodeType":"def","questionId":"424","status":"","title":"替换后的最长重复字符","titleSlug":"longest-repeating-character-replacement"},{"formTitle":"[425]单词方块","frontendQuestionId":"425","leaf":true,"level":3,"nodeType":"def","questionId":"425","status":"lock","title":"单词方块","titleSlug":"word-squares"},{"formTitle":"[426]将二叉搜索树转化为排序的双向链表","frontendQuestionId":"426","leaf":true,"level":2,"nodeType":"def","questionId":"758","status":"lock","title":"将二叉搜索树转化为排序的双向链表","titleSlug":"convert-binary-search-tree-to-sorted-doubly-linked-list"},{"formTitle":"[427]建立四叉树","frontendQuestionId":"427","leaf":true,"level":2,"nodeType":"def","questionId":"772","status":"","title":"建立四叉树","titleSlug":"construct-quad-tree"},{"formTitle":"[428]序列化和反序列化 N 叉树","frontendQuestionId":"428","leaf":true,"level":3,"nodeType":"def","questionId":"765","status":"lock","title":"序列化和反序列化 N 叉树","titleSlug":"serialize-and-deserialize-n-ary-tree"},{"formTitle":"[429]N叉树的层序遍历","frontendQuestionId":"429","leaf":true,"level":2,"nodeType":"def","questionId":"764","status":"","title":"N叉树的层序遍历","titleSlug":"n-ary-tree-level-order-traversal"},{"formTitle":"[430]扁平化多级双向链表","frontendQuestionId":"430","leaf":true,"level":2,"nodeType":"def","questionId":"766","status":"","title":"扁平化多级双向链表","titleSlug":"flatten-a-multilevel-doubly-linked-list"},{"formTitle":"[431]将 N 叉树编码为二叉树","frontendQuestionId":"431","leaf":true,"level":3,"nodeType":"def","questionId":"771","status":"lock","title":"将 N 叉树编码为二叉树","titleSlug":"encode-n-ary-tree-to-binary-tree"},{"formTitle":"[432]全 O(1) 的数据结构","frontendQuestionId":"432","leaf":true,"level":3,"nodeType":"def","questionId":"432","status":"","title":"全 O(1) 的数据结构","titleSlug":"all-oone-data-structure"},{"formTitle":"[433]最小基因变化","frontendQuestionId":"433","leaf":true,"level":2,"nodeType":"def","questionId":"433","status":"","title":"最小基因变化","titleSlug":"minimum-genetic-mutation"},{"formTitle":"[434]字符串中的单词数","frontendQuestionId":"434","leaf":true,"level":1,"nodeType":"def","questionId":"434","status":"","title":"字符串中的单词数","titleSlug":"number-of-segments-in-a-string"},{"formTitle":"[435]无重叠区间","frontendQuestionId":"435","leaf":true,"level":2,"nodeType":"def","questionId":"435","status":"","title":"无重叠区间","titleSlug":"non-overlapping-intervals"},{"formTitle":"[436]寻找右区间","frontendQuestionId":"436","leaf":true,"level":2,"nodeType":"def","questionId":"436","status":"","title":"寻找右区间","titleSlug":"find-right-interval"},{"formTitle":"[437]路径总和 III","frontendQuestionId":"437","leaf":true,"level":1,"nodeType":"def","questionId":"437","status":"","title":"路径总和 III","titleSlug":"path-sum-iii"},{"formTitle":"[438]找到字符串中所有字母异位词","frontendQuestionId":"438","leaf":true,"level":2,"nodeType":"def","questionId":"438","status":"","title":"找到字符串中所有字母异位词","titleSlug":"find-all-anagrams-in-a-string"},{"formTitle":"[439]三元表达式解析器","frontendQuestionId":"439","leaf":true,"level":2,"nodeType":"def","questionId":"439","status":"lock","title":"三元表达式解析器","titleSlug":"ternary-expression-parser"},{"formTitle":"[440]字典序的第K小数字","frontendQuestionId":"440","leaf":true,"level":3,"nodeType":"def","questionId":"440","status":"","title":"字典序的第K小数字","titleSlug":"k-th-smallest-in-lexicographical-order"},{"formTitle":"[441]排列硬币","frontendQuestionId":"441","leaf":true,"level":1,"nodeType":"def","questionId":"441","status":"","title":"排列硬币","titleSlug":"arranging-coins"},{"formTitle":"[442]数组中重复的数据","frontendQuestionId":"442","leaf":true,"level":2,"nodeType":"def","questionId":"442","status":"","title":"数组中重复的数据","titleSlug":"find-all-duplicates-in-an-array"},{"formTitle":"[443]压缩字符串","frontendQuestionId":"443","leaf":true,"level":1,"nodeType":"def","questionId":"443","status":"","title":"压缩字符串","titleSlug":"string-compression"},{"formTitle":"[444]序列重建","frontendQuestionId":"444","leaf":true,"level":2,"nodeType":"def","questionId":"444","status":"lock","title":"序列重建","titleSlug":"sequence-reconstruction"},{"formTitle":"[445]两数相加 II","frontendQuestionId":"445","leaf":true,"level":2,"nodeType":"def","questionId":"445","status":"","title":"两数相加 II","titleSlug":"add-two-numbers-ii"},{"formTitle":"[446]等差数列划分 II - 子序列","frontendQuestionId":"446","leaf":true,"level":3,"nodeType":"def","questionId":"446","status":"","title":"等差数列划分 II - 子序列","titleSlug":"arithmetic-slices-ii-subsequence"},{"formTitle":"[447]回旋镖的数量","frontendQuestionId":"447","leaf":true,"level":1,"nodeType":"def","questionId":"447","status":"","title":"回旋镖的数量","titleSlug":"number-of-boomerangs"},{"formTitle":"[448]找到所有数组中消失的数字","frontendQuestionId":"448","leaf":true,"level":1,"nodeType":"def","questionId":"448","status":"","title":"找到所有数组中消失的数字","titleSlug":"find-all-numbers-disappeared-in-an-array"},{"formTitle":"[449]序列化和反序列化二叉搜索树","frontendQuestionId":"449","leaf":true,"level":2,"nodeType":"def","questionId":"449","status":"","title":"序列化和反序列化二叉搜索树","titleSlug":"serialize-and-deserialize-bst"},{"formTitle":"[450]删除二叉搜索树中的节点","frontendQuestionId":"450","leaf":true,"level":2,"nodeType":"def","questionId":"450","status":"","title":"删除二叉搜索树中的节点","titleSlug":"delete-node-in-a-bst"},{"formTitle":"[451]根据字符出现频率排序","frontendQuestionId":"451","leaf":true,"level":2,"nodeType":"def","questionId":"451","status":"","title":"根据字符出现频率排序","titleSlug":"sort-characters-by-frequency"},{"formTitle":"[452]用最少数量的箭引爆气球","frontendQuestionId":"452","leaf":true,"level":2,"nodeType":"def","questionId":"452","status":"","title":"用最少数量的箭引爆气球","titleSlug":"minimum-number-of-arrows-to-burst-balloons"},{"formTitle":"[453]最小移动次数使数组元素相等","frontendQuestionId":"453","leaf":true,"level":1,"nodeType":"def","questionId":"453","status":"","title":"最小移动次数使数组元素相等","titleSlug":"minimum-moves-to-equal-array-elements"},{"formTitle":"[454]四数相加 II","frontendQuestionId":"454","leaf":true,"level":2,"nodeType":"def","questionId":"454","status":"","title":"四数相加 II","titleSlug":"4sum-ii"},{"formTitle":"[455]分发饼干","frontendQuestionId":"455","leaf":true,"level":1,"nodeType":"def","questionId":"455","status":"","title":"分发饼干","titleSlug":"assign-cookies"},{"formTitle":"[456]132模式","frontendQuestionId":"456","leaf":true,"level":2,"nodeType":"def","questionId":"456","status":"","title":"132模式","titleSlug":"132-pattern"},{"formTitle":"[457]环形数组循环","frontendQuestionId":"457","leaf":true,"level":2,"nodeType":"def","questionId":"457","status":"","title":"环形数组循环","titleSlug":"circular-array-loop"},{"formTitle":"[458]可怜的小猪","frontendQuestionId":"458","leaf":true,"level":3,"nodeType":"def","questionId":"458","status":"","title":"可怜的小猪","titleSlug":"poor-pigs"},{"formTitle":"[459]重复的子字符串","frontendQuestionId":"459","leaf":true,"level":1,"nodeType":"def","questionId":"459","status":"","title":"重复的子字符串","titleSlug":"repeated-substring-pattern"},{"formTitle":"[460]LFU缓存","frontendQuestionId":"460","leaf":true,"level":3,"nodeType":"def","questionId":"460","status":"","title":"LFU缓存","titleSlug":"lfu-cache"},{"formTitle":"[461]汉明距离","frontendQuestionId":"461","leaf":true,"level":1,"nodeType":"def","questionId":"461","status":"","title":"汉明距离","titleSlug":"hamming-distance"},{"formTitle":"[462]最少移动次数使数组元素相等 II","frontendQuestionId":"462","leaf":true,"level":2,"nodeType":"def","questionId":"462","status":"","title":"最少移动次数使数组元素相等 II","titleSlug":"minimum-moves-to-equal-array-elements-ii"},{"formTitle":"[463]岛屿的周长","frontendQuestionId":"463","leaf":true,"level":1,"nodeType":"def","questionId":"463","status":"","title":"岛屿的周长","titleSlug":"island-perimeter"},{"formTitle":"[464]我能赢吗","frontendQuestionId":"464","leaf":true,"level":2,"nodeType":"def","questionId":"464","status":"","title":"我能赢吗","titleSlug":"can-i-win"},{"formTitle":"[465]最优账单平衡","frontendQuestionId":"465","leaf":true,"level":3,"nodeType":"def","questionId":"465","status":"lock","title":"最优账单平衡","titleSlug":"optimal-account-balancing"},{"formTitle":"[466]统计重复个数","frontendQuestionId":"466","leaf":true,"level":3,"nodeType":"def","questionId":"466","status":"","title":"统计重复个数","titleSlug":"count-the-repetitions"},{"formTitle":"[467]环绕字符串中唯一的子字符串","frontendQuestionId":"467","leaf":true,"level":2,"nodeType":"def","questionId":"467","status":"","title":"环绕字符串中唯一的子字符串","titleSlug":"unique-substrings-in-wraparound-string"},{"formTitle":"[468]验证IP地址","frontendQuestionId":"468","leaf":true,"level":2,"nodeType":"def","questionId":"468","status":"","title":"验证IP地址","titleSlug":"validate-ip-address"},{"formTitle":"[469]凸多边形","frontendQuestionId":"469","leaf":true,"level":2,"nodeType":"def","questionId":"469","status":"lock","title":"凸多边形","titleSlug":"convex-polygon"},{"formTitle":"[470]用 Rand7() 实现 Rand10()","frontendQuestionId":"470","leaf":true,"level":2,"nodeType":"def","questionId":"903","status":"","title":"用 Rand7() 实现 Rand10()","titleSlug":"implement-rand10-using-rand7"},{"formTitle":"[471]编码最短长度的字符串","frontendQuestionId":"471","leaf":true,"level":3,"nodeType":"def","questionId":"471","status":"lock","title":"编码最短长度的字符串","titleSlug":"encode-string-with-shortest-length"},{"formTitle":"[472]连接词","frontendQuestionId":"472","leaf":true,"level":3,"nodeType":"def","questionId":"472","status":"","title":"连接词","titleSlug":"concatenated-words"},{"formTitle":"[473]火柴拼正方形","frontendQuestionId":"473","leaf":true,"level":2,"nodeType":"def","questionId":"473","status":"","title":"火柴拼正方形","titleSlug":"matchsticks-to-square"},{"formTitle":"[474]一和零","frontendQuestionId":"474","leaf":true,"level":2,"nodeType":"def","questionId":"474","status":"","title":"一和零","titleSlug":"ones-and-zeroes"},{"formTitle":"[475]供暖器","frontendQuestionId":"475","leaf":true,"level":1,"nodeType":"def","questionId":"475","status":"","title":"供暖器","titleSlug":"heaters"},{"formTitle":"[476]数字的补数","frontendQuestionId":"476","leaf":true,"level":1,"nodeType":"def","questionId":"476","status":"","title":"数字的补数","titleSlug":"number-complement"},{"formTitle":"[477]汉明距离总和","frontendQuestionId":"477","leaf":true,"level":2,"nodeType":"def","questionId":"477","status":"","title":"汉明距离总和","titleSlug":"total-hamming-distance"},{"formTitle":"[478]在圆内随机生成点","frontendQuestionId":"478","leaf":true,"level":2,"nodeType":"def","questionId":"915","status":"","title":"在圆内随机生成点","titleSlug":"generate-random-point-in-a-circle"},{"formTitle":"[479]最大回文数乘积","frontendQuestionId":"479","leaf":true,"level":3,"nodeType":"def","questionId":"479","status":"","title":"最大回文数乘积","titleSlug":"largest-palindrome-product"},{"formTitle":"[480]滑动窗口中位数","frontendQuestionId":"480","leaf":true,"level":3,"nodeType":"def","questionId":"480","status":"","title":"滑动窗口中位数","titleSlug":"sliding-window-median"},{"formTitle":"[481]神奇字符串","frontendQuestionId":"481","leaf":true,"level":2,"nodeType":"def","questionId":"481","status":"","title":"神奇字符串","titleSlug":"magical-string"},{"formTitle":"[482]密钥格式化","frontendQuestionId":"482","leaf":true,"level":1,"nodeType":"def","questionId":"482","status":"","title":"密钥格式化","titleSlug":"license-key-formatting"},{"formTitle":"[483]最小好进制","frontendQuestionId":"483","leaf":true,"level":3,"nodeType":"def","questionId":"483","status":"","title":"最小好进制","titleSlug":"smallest-good-base"},{"formTitle":"[484]寻找排列","frontendQuestionId":"484","leaf":true,"level":2,"nodeType":"def","questionId":"484","status":"lock","title":"寻找排列","titleSlug":"find-permutation"},{"formTitle":"[485]最大连续1的个数","frontendQuestionId":"485","leaf":true,"level":1,"nodeType":"def","questionId":"485","status":"","title":"最大连续1的个数","titleSlug":"max-consecutive-ones"},{"formTitle":"[486]预测赢家","frontendQuestionId":"486","leaf":true,"level":2,"nodeType":"def","questionId":"486","status":"","title":"预测赢家","titleSlug":"predict-the-winner"},{"formTitle":"[487]最大连续1的个数 II","frontendQuestionId":"487","leaf":true,"level":2,"nodeType":"def","questionId":"487","status":"lock","title":"最大连续1的个数 II","titleSlug":"max-consecutive-ones-ii"},{"formTitle":"[488]祖玛游戏","frontendQuestionId":"488","leaf":true,"level":3,"nodeType":"def","questionId":"488","status":"","title":"祖玛游戏","titleSlug":"zuma-game"},{"formTitle":"[489]扫地机器人","frontendQuestionId":"489","leaf":true,"level":3,"nodeType":"def","questionId":"865","status":"lock","title":"扫地机器人","titleSlug":"robot-room-cleaner"},{"formTitle":"[490]迷宫","frontendQuestionId":"490","leaf":true,"level":2,"nodeType":"def","questionId":"490","status":"lock","title":"迷宫","titleSlug":"the-maze"},{"formTitle":"[491]递增子序列","frontendQuestionId":"491","leaf":true,"level":2,"nodeType":"def","questionId":"491","status":"","title":"递增子序列","titleSlug":"increasing-subsequences"},{"formTitle":"[492]构造矩形","frontendQuestionId":"492","leaf":true,"level":1,"nodeType":"def","questionId":"492","status":"","title":"构造矩形","titleSlug":"construct-the-rectangle"},{"formTitle":"[493]翻转对","frontendQuestionId":"493","leaf":true,"level":3,"nodeType":"def","questionId":"493","status":"","title":"翻转对","titleSlug":"reverse-pairs"},{"formTitle":"[494]目标和","frontendQuestionId":"494","leaf":true,"level":2,"nodeType":"def","questionId":"494","status":"","title":"目标和","titleSlug":"target-sum"},{"formTitle":"[495]提莫攻击","frontendQuestionId":"495","leaf":true,"level":2,"nodeType":"def","questionId":"495","status":"","title":"提莫攻击","titleSlug":"teemo-attacking"},{"formTitle":"[496]下一个更大元素 I","frontendQuestionId":"496","leaf":true,"level":1,"nodeType":"def","questionId":"496","status":"","title":"下一个更大元素 I","titleSlug":"next-greater-element-i"},{"formTitle":"[497]非重叠矩形中的随机点","frontendQuestionId":"497","leaf":true,"level":2,"nodeType":"def","questionId":"914","status":"","title":"非重叠矩形中的随机点","titleSlug":"random-point-in-non-overlapping-rectangles"},{"formTitle":"[498]对角线遍历","frontendQuestionId":"498","leaf":true,"level":2,"nodeType":"def","questionId":"498","status":"","title":"对角线遍历","titleSlug":"diagonal-traverse"},{"formTitle":"[499]迷宫 III","frontendQuestionId":"499","leaf":true,"level":3,"nodeType":"def","questionId":"499","status":"lock","title":"迷宫 III","titleSlug":"the-maze-iii"},{"formTitle":"[500]键盘行","frontendQuestionId":"500","leaf":true,"level":1,"nodeType":"def","questionId":"500","status":"","title":"键盘行","titleSlug":"keyboard-row"},{"formTitle":"[501]二叉搜索树中的众数","frontendQuestionId":"501","leaf":true,"level":1,"nodeType":"def","questionId":"501","status":"","title":"二叉搜索树中的众数","titleSlug":"find-mode-in-binary-search-tree"},{"formTitle":"[502]IPO","frontendQuestionId":"502","leaf":true,"level":3,"nodeType":"def","questionId":"502","status":"","title":"IPO","titleSlug":"ipo"},{"formTitle":"[503]下一个更大元素 II","frontendQuestionId":"503","leaf":true,"level":2,"nodeType":"def","questionId":"503","status":"","title":"下一个更大元素 II","titleSlug":"next-greater-element-ii"},{"formTitle":"[504]七进制数","frontendQuestionId":"504","leaf":true,"level":1,"nodeType":"def","questionId":"504","status":"","title":"七进制数","titleSlug":"base-7"},{"formTitle":"[505]迷宫 II","frontendQuestionId":"505","leaf":true,"level":2,"nodeType":"def","questionId":"505","status":"lock","title":"迷宫 II","titleSlug":"the-maze-ii"},{"formTitle":"[506]相对名次","frontendQuestionId":"506","leaf":true,"level":1,"nodeType":"def","questionId":"506","status":"","title":"相对名次","titleSlug":"relative-ranks"},{"formTitle":"[507]完美数","frontendQuestionId":"507","leaf":true,"level":1,"nodeType":"def","questionId":"507","status":"","title":"完美数","titleSlug":"perfect-number"},{"formTitle":"[508]出现次数最多的子树元素和","frontendQuestionId":"508","leaf":true,"level":2,"nodeType":"def","questionId":"508","status":"","title":"出现次数最多的子树元素和","titleSlug":"most-frequent-subtree-sum"},{"formTitle":"[509]斐波那契数","frontendQuestionId":"509","leaf":true,"level":1,"nodeType":"def","questionId":"1013","status":"","title":"斐波那契数","titleSlug":"fibonacci-number"},{"formTitle":"[510]二叉搜索树中的中序后继 II","frontendQuestionId":"510","leaf":true,"level":2,"nodeType":"def","questionId":"509","status":"lock","title":"二叉搜索树中的中序后继 II","titleSlug":"inorder-successor-in-bst-ii"},{"formTitle":"[511]游戏玩法分析 I","frontendQuestionId":"511","leaf":true,"level":1,"nodeType":"def","questionId":"1179","status":"lock","title":"游戏玩法分析 I","titleSlug":"game-play-analysis-i"},{"formTitle":"[512]游戏玩法分析 II","frontendQuestionId":"512","leaf":true,"level":1,"nodeType":"def","questionId":"1180","status":"lock","title":"游戏玩法分析 II","titleSlug":"game-play-analysis-ii"},{"formTitle":"[513]找树左下角的值","frontendQuestionId":"513","leaf":true,"level":2,"nodeType":"def","questionId":"513","status":"","title":"找树左下角的值","titleSlug":"find-bottom-left-tree-value"},{"formTitle":"[514]自由之路","frontendQuestionId":"514","leaf":true,"level":3,"nodeType":"def","questionId":"514","status":"","title":"自由之路","titleSlug":"freedom-trail"},{"formTitle":"[515]在每个树行中找最大值","frontendQuestionId":"515","leaf":true,"level":2,"nodeType":"def","questionId":"515","status":"","title":"在每个树行中找最大值","titleSlug":"find-largest-value-in-each-tree-row"},{"formTitle":"[516]最长回文子序列","frontendQuestionId":"516","leaf":true,"level":2,"nodeType":"def","questionId":"516","status":"","title":"最长回文子序列","titleSlug":"longest-palindromic-subsequence"},{"formTitle":"[517]超级洗衣机","frontendQuestionId":"517","leaf":true,"level":3,"nodeType":"def","questionId":"517","status":"","title":"超级洗衣机","titleSlug":"super-washing-machines"},{"formTitle":"[518]零钱兑换 II","frontendQuestionId":"518","leaf":true,"level":2,"nodeType":"def","questionId":"518","status":"","title":"零钱兑换 II","titleSlug":"coin-change-2"},{"formTitle":"[519]随机翻转矩阵","frontendQuestionId":"519","leaf":true,"level":2,"nodeType":"def","questionId":"913","status":"","title":"随机翻转矩阵","titleSlug":"random-flip-matrix"},{"formTitle":"[520]检测大写字母","frontendQuestionId":"520","leaf":true,"level":1,"nodeType":"def","questionId":"520","status":"","title":"检测大写字母","titleSlug":"detect-capital"},{"formTitle":"[521]最长特殊序列 Ⅰ","frontendQuestionId":"521","leaf":true,"level":1,"nodeType":"def","questionId":"521","status":"","title":"最长特殊序列 Ⅰ","titleSlug":"longest-uncommon-subsequence-i"},{"formTitle":"[522]最长特殊序列 II","frontendQuestionId":"522","leaf":true,"level":2,"nodeType":"def","questionId":"522","status":"","title":"最长特殊序列 II","titleSlug":"longest-uncommon-subsequence-ii"},{"formTitle":"[523]连续的子数组和","frontendQuestionId":"523","leaf":true,"level":2,"nodeType":"def","questionId":"523","status":"","title":"连续的子数组和","titleSlug":"continuous-subarray-sum"},{"formTitle":"[524]通过删除字母匹配到字典里最长单词","frontendQuestionId":"524","leaf":true,"level":2,"nodeType":"def","questionId":"524","status":"","title":"通过删除字母匹配到字典里最长单词","titleSlug":"longest-word-in-dictionary-through-deleting"},{"formTitle":"[525]连续数组","frontendQuestionId":"525","leaf":true,"level":2,"nodeType":"def","questionId":"525","status":"","title":"连续数组","titleSlug":"contiguous-array"},{"formTitle":"[526]优美的排列","frontendQuestionId":"526","leaf":true,"level":2,"nodeType":"def","questionId":"526","status":"","title":"优美的排列","titleSlug":"beautiful-arrangement"},{"formTitle":"[527]单词缩写","frontendQuestionId":"527","leaf":true,"level":3,"nodeType":"def","questionId":"527","status":"lock","title":"单词缩写","titleSlug":"word-abbreviation"},{"formTitle":"[528]按权重随机选择","frontendQuestionId":"528","leaf":true,"level":2,"nodeType":"def","questionId":"912","status":"","title":"按权重随机选择","titleSlug":"random-pick-with-weight"},{"formTitle":"[529]扫雷游戏","frontendQuestionId":"529","leaf":true,"level":2,"nodeType":"def","questionId":"529","status":"","title":"扫雷游戏","titleSlug":"minesweeper"},{"formTitle":"[530]二叉搜索树的最小绝对差","frontendQuestionId":"530","leaf":true,"level":1,"nodeType":"def","questionId":"530","status":"","title":"二叉搜索树的最小绝对差","titleSlug":"minimum-absolute-difference-in-bst"},{"formTitle":"[531]孤独像素 I","frontendQuestionId":"531","leaf":true,"level":2,"nodeType":"def","questionId":"531","status":"lock","title":"孤独像素 I","titleSlug":"lonely-pixel-i"},{"formTitle":"[532]数组中的K-diff数对","frontendQuestionId":"532","leaf":true,"level":1,"nodeType":"def","questionId":"532","status":"","title":"数组中的K-diff数对","titleSlug":"k-diff-pairs-in-an-array"},{"formTitle":"[533]孤独像素 II","frontendQuestionId":"533","leaf":true,"level":2,"nodeType":"def","questionId":"533","status":"lock","title":"孤独像素 II","titleSlug":"lonely-pixel-ii"},{"formTitle":"[534]游戏玩法分析 III","frontendQuestionId":"534","leaf":true,"level":2,"nodeType":"def","questionId":"1181","status":"lock","title":"游戏玩法分析 III","titleSlug":"game-play-analysis-iii"},{"formTitle":"[535]TinyURL 的加密与解密","frontendQuestionId":"535","leaf":true,"level":2,"nodeType":"def","questionId":"535","status":"","title":"TinyURL 的加密与解密","titleSlug":"encode-and-decode-tinyurl"},{"formTitle":"[536]从字符串生成二叉树","frontendQuestionId":"536","leaf":true,"level":2,"nodeType":"def","questionId":"536","status":"lock","title":"从字符串生成二叉树","titleSlug":"construct-binary-tree-from-string"},{"formTitle":"[537]复数乘法","frontendQuestionId":"537","leaf":true,"level":2,"nodeType":"def","questionId":"537","status":"","title":"复数乘法","titleSlug":"complex-number-multiplication"},{"formTitle":"[538]把二叉搜索树转换为累加树","frontendQuestionId":"538","leaf":true,"level":1,"nodeType":"def","questionId":"538","status":"","title":"把二叉搜索树转换为累加树","titleSlug":"convert-bst-to-greater-tree"},{"formTitle":"[539]最小时间差","frontendQuestionId":"539","leaf":true,"level":2,"nodeType":"def","questionId":"539","status":"","title":"最小时间差","titleSlug":"minimum-time-difference"},{"formTitle":"[540]有序数组中的单一元素","frontendQuestionId":"540","leaf":true,"level":2,"nodeType":"def","questionId":"540","status":"","title":"有序数组中的单一元素","titleSlug":"single-element-in-a-sorted-array"},{"formTitle":"[541]反转字符串 II","frontendQuestionId":"541","leaf":true,"level":1,"nodeType":"def","questionId":"541","status":"","title":"反转字符串 II","titleSlug":"reverse-string-ii"},{"formTitle":"[542]01 矩阵","frontendQuestionId":"542","leaf":true,"level":2,"nodeType":"def","questionId":"542","status":"","title":"01 矩阵","titleSlug":"01-matrix"},{"formTitle":"[543]二叉树的直径","frontendQuestionId":"543","leaf":true,"level":1,"nodeType":"def","questionId":"543","status":"","title":"二叉树的直径","titleSlug":"diameter-of-binary-tree"},{"formTitle":"[544]输出比赛匹配对","frontendQuestionId":"544","leaf":true,"level":2,"nodeType":"def","questionId":"544","status":"lock","title":"输出比赛匹配对","titleSlug":"output-contest-matches"},{"formTitle":"[545]二叉树的边界","frontendQuestionId":"545","leaf":true,"level":2,"nodeType":"def","questionId":"545","status":"lock","title":"二叉树的边界","titleSlug":"boundary-of-binary-tree"},{"formTitle":"[546]移除盒子","frontendQuestionId":"546","leaf":true,"level":3,"nodeType":"def","questionId":"546","status":"","title":"移除盒子","titleSlug":"remove-boxes"},{"formTitle":"[547]朋友圈","frontendQuestionId":"547","leaf":true,"level":2,"nodeType":"def","questionId":"547","status":"ac","title":"朋友圈","titleSlug":"friend-circles"},{"formTitle":"[548]将数组分割成和相等的子数组","frontendQuestionId":"548","leaf":true,"level":2,"nodeType":"def","questionId":"548","status":"lock","title":"将数组分割成和相等的子数组","titleSlug":"split-array-with-equal-sum"},{"formTitle":"[549]二叉树中最长的连续序列","frontendQuestionId":"549","leaf":true,"level":2,"nodeType":"def","questionId":"549","status":"lock","title":"二叉树中最长的连续序列","titleSlug":"binary-tree-longest-consecutive-sequence-ii"},{"formTitle":"[550]游戏玩法分析 IV","frontendQuestionId":"550","leaf":true,"level":2,"nodeType":"def","questionId":"1182","status":"lock","title":"游戏玩法分析 IV","titleSlug":"game-play-analysis-iv"},{"formTitle":"[551]学生出勤记录 I","frontendQuestionId":"551","leaf":true,"level":1,"nodeType":"def","questionId":"551","status":"","title":"学生出勤记录 I","titleSlug":"student-attendance-record-i"},{"formTitle":"[552]学生出勤记录 II","frontendQuestionId":"552","leaf":true,"level":3,"nodeType":"def","questionId":"552","status":"","title":"学生出勤记录 II","titleSlug":"student-attendance-record-ii"},{"formTitle":"[553]最优除法","frontendQuestionId":"553","leaf":true,"level":2,"nodeType":"def","questionId":"553","status":"","title":"最优除法","titleSlug":"optimal-division"},{"formTitle":"[554]砖墙","frontendQuestionId":"554","leaf":true,"level":2,"nodeType":"def","questionId":"554","status":"","title":"砖墙","titleSlug":"brick-wall"},{"formTitle":"[555]分割连接字符串","frontendQuestionId":"555","leaf":true,"level":2,"nodeType":"def","questionId":"555","status":"lock","title":"分割连接字符串","titleSlug":"split-concatenated-strings"},{"formTitle":"[556]下一个更大元素 III","frontendQuestionId":"556","leaf":true,"level":2,"nodeType":"def","questionId":"556","status":"","title":"下一个更大元素 III","titleSlug":"next-greater-element-iii"},{"formTitle":"[557]反转字符串中的单词 III","frontendQuestionId":"557","leaf":true,"level":1,"nodeType":"def","questionId":"557","status":"","title":"反转字符串中的单词 III","titleSlug":"reverse-words-in-a-string-iii"},{"formTitle":"[558]四叉树交集","frontendQuestionId":"558","leaf":true,"level":1,"nodeType":"def","questionId":"773","status":"","title":"四叉树交集","titleSlug":"quad-tree-intersection"},{"formTitle":"[559]N叉树的最大深度","frontendQuestionId":"559","leaf":true,"level":1,"nodeType":"def","questionId":"774","status":"","title":"N叉树的最大深度","titleSlug":"maximum-depth-of-n-ary-tree"},{"formTitle":"[560]和为K的子数组","frontendQuestionId":"560","leaf":true,"level":2,"nodeType":"def","questionId":"560","status":"","title":"和为K的子数组","titleSlug":"subarray-sum-equals-k"},{"formTitle":"[561]数组拆分 I","frontendQuestionId":"561","leaf":true,"level":1,"nodeType":"def","questionId":"561","status":"","title":"数组拆分 I","titleSlug":"array-partition-i"},{"formTitle":"[562]矩阵中最长的连续1线段","frontendQuestionId":"562","leaf":true,"level":2,"nodeType":"def","questionId":"562","status":"lock","title":"矩阵中最长的连续1线段","titleSlug":"longest-line-of-consecutive-one-in-matrix"},{"formTitle":"[563]二叉树的坡度","frontendQuestionId":"563","leaf":true,"level":1,"nodeType":"def","questionId":"563","status":"","title":"二叉树的坡度","titleSlug":"binary-tree-tilt"},{"formTitle":"[564]寻找最近的回文数","frontendQuestionId":"564","leaf":true,"level":3,"nodeType":"def","questionId":"564","status":"","title":"寻找最近的回文数","titleSlug":"find-the-closest-palindrome"},{"formTitle":"[565]数组嵌套","frontendQuestionId":"565","leaf":true,"level":2,"nodeType":"def","questionId":"565","status":"","title":"数组嵌套","titleSlug":"array-nesting"},{"formTitle":"[566]重塑矩阵","frontendQuestionId":"566","leaf":true,"level":1,"nodeType":"def","questionId":"566","status":"","title":"重塑矩阵","titleSlug":"reshape-the-matrix"},{"formTitle":"[567]字符串的排列","frontendQuestionId":"567","leaf":true,"level":2,"nodeType":"def","questionId":"567","status":"","title":"字符串的排列","titleSlug":"permutation-in-string"},{"formTitle":"[568]最大休假天数","frontendQuestionId":"568","leaf":true,"level":3,"nodeType":"def","questionId":"568","status":"lock","title":"最大休假天数","titleSlug":"maximum-vacation-days"},{"formTitle":"[569]员工薪水中位数","frontendQuestionId":"569","leaf":true,"level":3,"nodeType":"def","questionId":"569","status":"lock","title":"员工薪水中位数","titleSlug":"median-employee-salary"},{"formTitle":"[570]至少有5名直接下属的经理","frontendQuestionId":"570","leaf":true,"level":2,"nodeType":"def","questionId":"570","status":"lock","title":"至少有5名直接下属的经理","titleSlug":"managers-with-at-least-5-direct-reports"},{"formTitle":"[571]给定数字的频率查询中位数","frontendQuestionId":"571","leaf":true,"level":3,"nodeType":"def","questionId":"571","status":"lock","title":"给定数字的频率查询中位数","titleSlug":"find-median-given-frequency-of-numbers"},{"formTitle":"[572]另一个树的子树","frontendQuestionId":"572","leaf":true,"level":1,"nodeType":"def","questionId":"572","status":"","title":"另一个树的子树","titleSlug":"subtree-of-another-tree"},{"formTitle":"[573]松鼠模拟","frontendQuestionId":"573","leaf":true,"level":2,"nodeType":"def","questionId":"573","status":"lock","title":"松鼠模拟","titleSlug":"squirrel-simulation"},{"formTitle":"[574]当选者","frontendQuestionId":"574","leaf":true,"level":2,"nodeType":"def","questionId":"574","status":"lock","title":"当选者","titleSlug":"winning-candidate"},{"formTitle":"[575]分糖果","frontendQuestionId":"575","leaf":true,"level":1,"nodeType":"def","questionId":"575","status":"","title":"分糖果","titleSlug":"distribute-candies"},{"formTitle":"[576]出界的路径数","frontendQuestionId":"576","leaf":true,"level":2,"nodeType":"def","questionId":"576","status":"","title":"出界的路径数","titleSlug":"out-of-boundary-paths"},{"formTitle":"[577]员工奖金","frontendQuestionId":"577","leaf":true,"level":1,"nodeType":"def","questionId":"577","status":"lock","title":"员工奖金","titleSlug":"employee-bonus"},{"formTitle":"[578]查询回答率最高的问题","frontendQuestionId":"578","leaf":true,"level":2,"nodeType":"def","questionId":"578","status":"lock","title":"查询回答率最高的问题","titleSlug":"get-highest-answer-rate-question"},{"formTitle":"[579]查询员工的累计薪水","frontendQuestionId":"579","leaf":true,"level":3,"nodeType":"def","questionId":"579","status":"lock","title":"查询员工的累计薪水","titleSlug":"find-cumulative-salary-of-an-employee"},{"formTitle":"[580]统计各专业学生人数","frontendQuestionId":"580","leaf":true,"level":2,"nodeType":"def","questionId":"580","status":"lock","title":"统计各专业学生人数","titleSlug":"count-student-number-in-departments"},{"formTitle":"[581]最短无序连续子数组","frontendQuestionId":"581","leaf":true,"level":1,"nodeType":"def","questionId":"581","status":"","title":"最短无序连续子数组","titleSlug":"shortest-unsorted-continuous-subarray"},{"formTitle":"[582]杀死进程","frontendQuestionId":"582","leaf":true,"level":2,"nodeType":"def","questionId":"582","status":"lock","title":"杀死进程","titleSlug":"kill-process"},{"formTitle":"[583]两个字符串的删除操作","frontendQuestionId":"583","leaf":true,"level":2,"nodeType":"def","questionId":"583","status":"","title":"两个字符串的删除操作","titleSlug":"delete-operation-for-two-strings"},{"formTitle":"[584]寻找用户推荐人","frontendQuestionId":"584","leaf":true,"level":1,"nodeType":"def","questionId":"584","status":"lock","title":"寻找用户推荐人","titleSlug":"find-customer-referee"},{"formTitle":"[585]2016年的投资","frontendQuestionId":"585","leaf":true,"level":2,"nodeType":"def","questionId":"585","status":"lock","title":"2016年的投资","titleSlug":"investments-in-2016"},{"formTitle":"[586]订单最多的客户","frontendQuestionId":"586","leaf":true,"level":1,"nodeType":"def","questionId":"586","status":"lock","title":"订单最多的客户","titleSlug":"customer-placing-the-largest-number-of-orders"},{"formTitle":"[587]安装栅栏","frontendQuestionId":"587","leaf":true,"level":3,"nodeType":"def","questionId":"587","status":"","title":"安装栅栏","titleSlug":"erect-the-fence"},{"formTitle":"[588]设计内存文件系统","frontendQuestionId":"588","leaf":true,"level":3,"nodeType":"def","questionId":"588","status":"lock","title":"设计内存文件系统","titleSlug":"design-in-memory-file-system"},{"formTitle":"[589]N叉树的前序遍历","frontendQuestionId":"589","leaf":true,"level":1,"nodeType":"def","questionId":"775","status":"","title":"N叉树的前序遍历","titleSlug":"n-ary-tree-preorder-traversal"},{"formTitle":"[590]N叉树的后序遍历","frontendQuestionId":"590","leaf":true,"level":1,"nodeType":"def","questionId":"776","status":"","title":"N叉树的后序遍历","titleSlug":"n-ary-tree-postorder-traversal"},{"formTitle":"[591]标签验证器","frontendQuestionId":"591","leaf":true,"level":3,"nodeType":"def","questionId":"591","status":"","title":"标签验证器","titleSlug":"tag-validator"},{"formTitle":"[592]分数加减运算","frontendQuestionId":"592","leaf":true,"level":2,"nodeType":"def","questionId":"592","status":"","title":"分数加减运算","titleSlug":"fraction-addition-and-subtraction"},{"formTitle":"[593]有效的正方形","frontendQuestionId":"593","leaf":true,"level":2,"nodeType":"def","questionId":"593","status":"","title":"有效的正方形","titleSlug":"valid-square"},{"formTitle":"[594]最长和谐子序列","frontendQuestionId":"594","leaf":true,"level":1,"nodeType":"def","questionId":"594","status":"","title":"最长和谐子序列","titleSlug":"longest-harmonious-subsequence"},{"formTitle":"[595]大的国家","frontendQuestionId":"595","leaf":true,"level":1,"nodeType":"def","questionId":"595","status":"","title":"大的国家","titleSlug":"big-countries"},{"formTitle":"[596]超过5名学生的课","frontendQuestionId":"596","leaf":true,"level":1,"nodeType":"def","questionId":"596","status":"","title":"超过5名学生的课","titleSlug":"classes-more-than-5-students"},{"formTitle":"[597]好友申请 I :总体通过率","frontendQuestionId":"597","leaf":true,"level":1,"nodeType":"def","questionId":"597","status":"lock","title":"好友申请 I :总体通过率","titleSlug":"friend-requests-i-overall-acceptance-rate"},{"formTitle":"[598]范围求和 II","frontendQuestionId":"598","leaf":true,"level":1,"nodeType":"def","questionId":"598","status":"","title":"范围求和 II","titleSlug":"range-addition-ii"},{"formTitle":"[599]两个列表的最小索引总和","frontendQuestionId":"599","leaf":true,"level":1,"nodeType":"def","questionId":"599","status":"","title":"两个列表的最小索引总和","titleSlug":"minimum-index-sum-of-two-lists"},{"formTitle":"[600]不含连续1的非负整数","frontendQuestionId":"600","leaf":true,"level":3,"nodeType":"def","questionId":"600","status":"","title":"不含连续1的非负整数","titleSlug":"non-negative-integers-without-consecutive-ones"},{"formTitle":"[601]体育馆的人流量","frontendQuestionId":"601","leaf":true,"level":3,"nodeType":"def","questionId":"601","status":"","title":"体育馆的人流量","titleSlug":"human-traffic-of-stadium"},{"formTitle":"[602]好友申请 II :谁有最多的好友","frontendQuestionId":"602","leaf":true,"level":2,"nodeType":"def","questionId":"602","status":"lock","title":"好友申请 II :谁有最多的好友","titleSlug":"friend-requests-ii-who-has-the-most-friends"},{"formTitle":"[603]连续空余座位","frontendQuestionId":"603","leaf":true,"level":1,"nodeType":"def","questionId":"603","status":"lock","title":"连续空余座位","titleSlug":"consecutive-available-seats"},{"formTitle":"[604]迭代压缩字符串","frontendQuestionId":"604","leaf":true,"level":1,"nodeType":"def","questionId":"604","status":"lock","title":"迭代压缩字符串","titleSlug":"design-compressed-string-iterator"},{"formTitle":"[605]种花问题","frontendQuestionId":"605","leaf":true,"level":1,"nodeType":"def","questionId":"605","status":"","title":"种花问题","titleSlug":"can-place-flowers"},{"formTitle":"[606]根据二叉树创建字符串","frontendQuestionId":"606","leaf":true,"level":1,"nodeType":"def","questionId":"606","status":"","title":"根据二叉树创建字符串","titleSlug":"construct-string-from-binary-tree"},{"formTitle":"[607]销售员","frontendQuestionId":"607","leaf":true,"level":1,"nodeType":"def","questionId":"607","status":"lock","title":"销售员","titleSlug":"sales-person"},{"formTitle":"[608]树节点","frontendQuestionId":"608","leaf":true,"level":2,"nodeType":"def","questionId":"608","status":"lock","title":"树节点","titleSlug":"tree-node"},{"formTitle":"[609]在系统中查找重复文件","frontendQuestionId":"609","leaf":true,"level":2,"nodeType":"def","questionId":"609","status":"","title":"在系统中查找重复文件","titleSlug":"find-duplicate-file-in-system"},{"formTitle":"[610]判断三角形","frontendQuestionId":"610","leaf":true,"level":1,"nodeType":"def","questionId":"610","status":"lock","title":"判断三角形","titleSlug":"triangle-judgement"},{"formTitle":"[611]有效三角形的个数","frontendQuestionId":"611","leaf":true,"level":2,"nodeType":"def","questionId":"611","status":"","title":"有效三角形的个数","titleSlug":"valid-triangle-number"},{"formTitle":"[612]平面上的最近距离","frontendQuestionId":"612","leaf":true,"level":2,"nodeType":"def","questionId":"612","status":"lock","title":"平面上的最近距离","titleSlug":"shortest-distance-in-a-plane"},{"formTitle":"[613]直线上的最近距离","frontendQuestionId":"613","leaf":true,"level":1,"nodeType":"def","questionId":"613","status":"lock","title":"直线上的最近距离","titleSlug":"shortest-distance-in-a-line"},{"formTitle":"[614]二级关注者","frontendQuestionId":"614","leaf":true,"level":2,"nodeType":"def","questionId":"614","status":"lock","title":"二级关注者","titleSlug":"second-degree-follower"},{"formTitle":"[615]平均工资:部门与公司比较","frontendQuestionId":"615","leaf":true,"level":3,"nodeType":"def","questionId":"615","status":"lock","title":"平均工资:部门与公司比较","titleSlug":"average-salary-departments-vs-company"},{"formTitle":"[616]给字符串添加加粗标签","frontendQuestionId":"616","leaf":true,"level":2,"nodeType":"def","questionId":"616","status":"lock","title":"给字符串添加加粗标签","titleSlug":"add-bold-tag-in-string"},{"formTitle":"[617]合并二叉树","frontendQuestionId":"617","leaf":true,"level":1,"nodeType":"def","questionId":"617","status":"","title":"合并二叉树","titleSlug":"merge-two-binary-trees"},{"formTitle":"[618]学生地理信息报告","frontendQuestionId":"618","leaf":true,"level":3,"nodeType":"def","questionId":"618","status":"lock","title":"学生地理信息报告","titleSlug":"students-report-by-geography"},{"formTitle":"[619]只出现一次的最大数字","frontendQuestionId":"619","leaf":true,"level":1,"nodeType":"def","questionId":"619","status":"lock","title":"只出现一次的最大数字","titleSlug":"biggest-single-number"},{"formTitle":"[620]有趣的电影","frontendQuestionId":"620","leaf":true,"level":1,"nodeType":"def","questionId":"620","status":"","title":"有趣的电影","titleSlug":"not-boring-movies"},{"formTitle":"[621]任务调度器","frontendQuestionId":"621","leaf":true,"level":2,"nodeType":"def","questionId":"621","status":"","title":"任务调度器","titleSlug":"task-scheduler"},{"formTitle":"[622]设计循环队列","frontendQuestionId":"622","leaf":true,"level":2,"nodeType":"def","questionId":"860","status":"","title":"设计循环队列","titleSlug":"design-circular-queue"},{"formTitle":"[623]在二叉树中增加一行","frontendQuestionId":"623","leaf":true,"level":2,"nodeType":"def","questionId":"623","status":"","title":"在二叉树中增加一行","titleSlug":"add-one-row-to-tree"},{"formTitle":"[624]数组列表中的最大距离","frontendQuestionId":"624","leaf":true,"level":1,"nodeType":"def","questionId":"624","status":"lock","title":"数组列表中的最大距离","titleSlug":"maximum-distance-in-arrays"},{"formTitle":"[625]最小因式分解","frontendQuestionId":"625","leaf":true,"level":2,"nodeType":"def","questionId":"625","status":"lock","title":"最小因式分解","titleSlug":"minimum-factorization"},{"formTitle":"[626]换座位","frontendQuestionId":"626","leaf":true,"level":2,"nodeType":"def","questionId":"626","status":"","title":"换座位","titleSlug":"exchange-seats"},{"formTitle":"[627]交换工资","frontendQuestionId":"627","leaf":true,"level":1,"nodeType":"def","questionId":"627","status":"","title":"交换工资","titleSlug":"swap-salary"},{"formTitle":"[628]三个数的最大乘积","frontendQuestionId":"628","leaf":true,"level":1,"nodeType":"def","questionId":"628","status":"","title":"三个数的最大乘积","titleSlug":"maximum-product-of-three-numbers"},{"formTitle":"[629]K个逆序对数组","frontendQuestionId":"629","leaf":true,"level":3,"nodeType":"def","questionId":"629","status":"","title":"K个逆序对数组","titleSlug":"k-inverse-pairs-array"},{"formTitle":"[630]课程表 III","frontendQuestionId":"630","leaf":true,"level":3,"nodeType":"def","questionId":"630","status":"","title":"课程表 III","titleSlug":"course-schedule-iii"},{"formTitle":"[631]设计 Excel 求和公式","frontendQuestionId":"631","leaf":true,"level":3,"nodeType":"def","questionId":"631","status":"lock","title":"设计 Excel 求和公式","titleSlug":"design-excel-sum-formula"},{"formTitle":"[632]最小区间","frontendQuestionId":"632","leaf":true,"level":3,"nodeType":"def","questionId":"632","status":"","title":"最小区间","titleSlug":"smallest-range-covering-elements-from-k-lists"},{"formTitle":"[633]平方数之和","frontendQuestionId":"633","leaf":true,"level":1,"nodeType":"def","questionId":"633","status":"","title":"平方数之和","titleSlug":"sum-of-square-numbers"},{"formTitle":"[634]寻找数组的错位排列","frontendQuestionId":"634","leaf":true,"level":2,"nodeType":"def","questionId":"634","status":"lock","title":"寻找数组的错位排列","titleSlug":"find-the-derangement-of-an-array"},{"formTitle":"[635]设计日志存储系统","frontendQuestionId":"635","leaf":true,"level":2,"nodeType":"def","questionId":"635","status":"lock","title":"设计日志存储系统","titleSlug":"design-log-storage-system"},{"formTitle":"[636]函数的独占时间","frontendQuestionId":"636","leaf":true,"level":2,"nodeType":"def","questionId":"636","status":"","title":"函数的独占时间","titleSlug":"exclusive-time-of-functions"},{"formTitle":"[637]二叉树的层平均值","frontendQuestionId":"637","leaf":true,"level":1,"nodeType":"def","questionId":"637","status":"","title":"二叉树的层平均值","titleSlug":"average-of-levels-in-binary-tree"},{"formTitle":"[638]大礼包","frontendQuestionId":"638","leaf":true,"level":2,"nodeType":"def","questionId":"638","status":"","title":"大礼包","titleSlug":"shopping-offers"},{"formTitle":"[639]解码方法 2","frontendQuestionId":"639","leaf":true,"level":3,"nodeType":"def","questionId":"639","status":"","title":"解码方法 2","titleSlug":"decode-ways-ii"},{"formTitle":"[640]求解方程","frontendQuestionId":"640","leaf":true,"level":2,"nodeType":"def","questionId":"640","status":"","title":"求解方程","titleSlug":"solve-the-equation"},{"formTitle":"[641]设计循环双端队列","frontendQuestionId":"641","leaf":true,"level":2,"nodeType":"def","questionId":"859","status":"","title":"设计循环双端队列","titleSlug":"design-circular-deque"},{"formTitle":"[642]设计搜索自动补全系统","frontendQuestionId":"642","leaf":true,"level":3,"nodeType":"def","questionId":"642","status":"lock","title":"设计搜索自动补全系统","titleSlug":"design-search-autocomplete-system"},{"formTitle":"[643]子数组最大平均数 I","frontendQuestionId":"643","leaf":true,"level":1,"nodeType":"def","questionId":"643","status":"","title":"子数组最大平均数 I","titleSlug":"maximum-average-subarray-i"},{"formTitle":"[644]最大平均子段和 II","frontendQuestionId":"644","leaf":true,"level":3,"nodeType":"def","questionId":"644","status":"lock","title":"最大平均子段和 II","titleSlug":"maximum-average-subarray-ii"},{"formTitle":"[645]错误的集合","frontendQuestionId":"645","leaf":true,"level":1,"nodeType":"def","questionId":"645","status":"","title":"错误的集合","titleSlug":"set-mismatch"},{"formTitle":"[646]最长数对链","frontendQuestionId":"646","leaf":true,"level":2,"nodeType":"def","questionId":"646","status":"","title":"最长数对链","titleSlug":"maximum-length-of-pair-chain"},{"formTitle":"[647]回文子串","frontendQuestionId":"647","leaf":true,"level":2,"nodeType":"def","questionId":"647","status":"","title":"回文子串","titleSlug":"palindromic-substrings"},{"formTitle":"[648]单词替换","frontendQuestionId":"648","leaf":true,"level":2,"nodeType":"def","questionId":"648","status":"","title":"单词替换","titleSlug":"replace-words"},{"formTitle":"[649]Dota2 参议院","frontendQuestionId":"649","leaf":true,"level":2,"nodeType":"def","questionId":"649","status":"","title":"Dota2 参议院","titleSlug":"dota2-senate"},{"formTitle":"[650]只有两个键的键盘","frontendQuestionId":"650","leaf":true,"level":2,"nodeType":"def","questionId":"650","status":"","title":"只有两个键的键盘","titleSlug":"2-keys-keyboard"},{"formTitle":"[651]4键键盘","frontendQuestionId":"651","leaf":true,"level":2,"nodeType":"def","questionId":"651","status":"lock","title":"4键键盘","titleSlug":"4-keys-keyboard"},{"formTitle":"[652]寻找重复的子树","frontendQuestionId":"652","leaf":true,"level":2,"nodeType":"def","questionId":"652","status":"","title":"寻找重复的子树","titleSlug":"find-duplicate-subtrees"},{"formTitle":"[653]两数之和 IV - 输入 BST","frontendQuestionId":"653","leaf":true,"level":1,"nodeType":"def","questionId":"653","status":"","title":"两数之和 IV - 输入 BST","titleSlug":"two-sum-iv-input-is-a-bst"},{"formTitle":"[654]最大二叉树","frontendQuestionId":"654","leaf":true,"level":2,"nodeType":"def","questionId":"654","status":"","title":"最大二叉树","titleSlug":"maximum-binary-tree"},{"formTitle":"[655]输出二叉树","frontendQuestionId":"655","leaf":true,"level":2,"nodeType":"def","questionId":"655","status":"","title":"输出二叉树","titleSlug":"print-binary-tree"},{"formTitle":"[656]金币路径","frontendQuestionId":"656","leaf":true,"level":3,"nodeType":"def","questionId":"656","status":"lock","title":"金币路径","titleSlug":"coin-path"},{"formTitle":"[657]机器人能否返回原点","frontendQuestionId":"657","leaf":true,"level":1,"nodeType":"def","questionId":"657","status":"","title":"机器人能否返回原点","titleSlug":"robot-return-to-origin"},{"formTitle":"[658]找到 K 个最接近的元素","frontendQuestionId":"658","leaf":true,"level":2,"nodeType":"def","questionId":"658","status":"","title":"找到 K 个最接近的元素","titleSlug":"find-k-closest-elements"},{"formTitle":"[659]分割数组为连续子序列","frontendQuestionId":"659","leaf":true,"level":2,"nodeType":"def","questionId":"659","status":"","title":"分割数组为连续子序列","titleSlug":"split-array-into-consecutive-subsequences"},{"formTitle":"[660]移除 9","frontendQuestionId":"660","leaf":true,"level":3,"nodeType":"def","questionId":"660","status":"lock","title":"移除 9","titleSlug":"remove-9"},{"formTitle":"[661]图片平滑器","frontendQuestionId":"661","leaf":true,"level":1,"nodeType":"def","questionId":"661","status":"","title":"图片平滑器","titleSlug":"image-smoother"},{"formTitle":"[662]二叉树最大宽度","frontendQuestionId":"662","leaf":true,"level":2,"nodeType":"def","questionId":"662","status":"","title":"二叉树最大宽度","titleSlug":"maximum-width-of-binary-tree"},{"formTitle":"[663]均匀树划分","frontendQuestionId":"663","leaf":true,"level":2,"nodeType":"def","questionId":"663","status":"lock","title":"均匀树划分","titleSlug":"equal-tree-partition"},{"formTitle":"[664]奇怪的打印机","frontendQuestionId":"664","leaf":true,"level":3,"nodeType":"def","questionId":"664","status":"","title":"奇怪的打印机","titleSlug":"strange-printer"},{"formTitle":"[665]非递减数列","frontendQuestionId":"665","leaf":true,"level":1,"nodeType":"def","questionId":"665","status":"","title":"非递减数列","titleSlug":"non-decreasing-array"},{"formTitle":"[666]路径和 IV","frontendQuestionId":"666","leaf":true,"level":2,"nodeType":"def","questionId":"666","status":"lock","title":"路径和 IV","titleSlug":"path-sum-iv"},{"formTitle":"[667]优美的排列 II","frontendQuestionId":"667","leaf":true,"level":2,"nodeType":"def","questionId":"667","status":"","title":"优美的排列 II","titleSlug":"beautiful-arrangement-ii"},{"formTitle":"[668]乘法表中第k小的数","frontendQuestionId":"668","leaf":true,"level":3,"nodeType":"def","questionId":"668","status":"","title":"乘法表中第k小的数","titleSlug":"kth-smallest-number-in-multiplication-table"},{"formTitle":"[669]修剪二叉搜索树","frontendQuestionId":"669","leaf":true,"level":1,"nodeType":"def","questionId":"669","status":"","title":"修剪二叉搜索树","titleSlug":"trim-a-binary-search-tree"},{"formTitle":"[670]最大交换","frontendQuestionId":"670","leaf":true,"level":2,"nodeType":"def","questionId":"670","status":"","title":"最大交换","titleSlug":"maximum-swap"},{"formTitle":"[671]二叉树中第二小的节点","frontendQuestionId":"671","leaf":true,"level":1,"nodeType":"def","questionId":"671","status":"","title":"二叉树中第二小的节点","titleSlug":"second-minimum-node-in-a-binary-tree"},{"formTitle":"[672]灯泡开关 Ⅱ","frontendQuestionId":"672","leaf":true,"level":2,"nodeType":"def","questionId":"672","status":"","title":"灯泡开关 Ⅱ","titleSlug":"bulb-switcher-ii"},{"formTitle":"[673]最长递增子序列的个数","frontendQuestionId":"673","leaf":true,"level":2,"nodeType":"def","questionId":"673","status":"","title":"最长递增子序列的个数","titleSlug":"number-of-longest-increasing-subsequence"},{"formTitle":"[674]最长连续递增序列","frontendQuestionId":"674","leaf":true,"level":1,"nodeType":"def","questionId":"674","status":"","title":"最长连续递增序列","titleSlug":"longest-continuous-increasing-subsequence"},{"formTitle":"[675]为高尔夫比赛砍树","frontendQuestionId":"675","leaf":true,"level":3,"nodeType":"def","questionId":"675","status":"","title":"为高尔夫比赛砍树","titleSlug":"cut-off-trees-for-golf-event"},{"formTitle":"[676]实现一个魔法字典","frontendQuestionId":"676","leaf":true,"level":2,"nodeType":"def","questionId":"676","status":"","title":"实现一个魔法字典","titleSlug":"implement-magic-dictionary"},{"formTitle":"[677]键值映射","frontendQuestionId":"677","leaf":true,"level":2,"nodeType":"def","questionId":"677","status":"","title":"键值映射","titleSlug":"map-sum-pairs"},{"formTitle":"[678]有效的括号字符串","frontendQuestionId":"678","leaf":true,"level":2,"nodeType":"def","questionId":"678","status":"","title":"有效的括号字符串","titleSlug":"valid-parenthesis-string"},{"formTitle":"[679]24 点游戏","frontendQuestionId":"679","leaf":true,"level":3,"nodeType":"def","questionId":"679","status":"","title":"24 点游戏","titleSlug":"24-game"},{"formTitle":"[680]验证回文字符串 Ⅱ","frontendQuestionId":"680","leaf":true,"level":1,"nodeType":"def","questionId":"680","status":"","title":"验证回文字符串 Ⅱ","titleSlug":"valid-palindrome-ii"},{"formTitle":"[681]最近时刻","frontendQuestionId":"681","leaf":true,"level":2,"nodeType":"def","questionId":"681","status":"lock","title":"最近时刻","titleSlug":"next-closest-time"},{"formTitle":"[682]棒球比赛","frontendQuestionId":"682","leaf":true,"level":1,"nodeType":"def","questionId":"682","status":"","title":"棒球比赛","titleSlug":"baseball-game"},{"formTitle":"[683]K 个空花盆","frontendQuestionId":"683","leaf":true,"level":3,"nodeType":"def","questionId":"683","status":"lock","title":"K 个空花盆","titleSlug":"k-empty-slots"},{"formTitle":"[684]冗余连接","frontendQuestionId":"684","leaf":true,"level":2,"nodeType":"def","questionId":"684","status":"","title":"冗余连接","titleSlug":"redundant-connection"},{"formTitle":"[685]冗余连接 II","frontendQuestionId":"685","leaf":true,"level":3,"nodeType":"def","questionId":"685","status":"","title":"冗余连接 II","titleSlug":"redundant-connection-ii"},{"formTitle":"[686]重复叠加字符串匹配","frontendQuestionId":"686","leaf":true,"level":1,"nodeType":"def","questionId":"686","status":"","title":"重复叠加字符串匹配","titleSlug":"repeated-string-match"},{"formTitle":"[687]最长同值路径","frontendQuestionId":"687","leaf":true,"level":1,"nodeType":"def","questionId":"687","status":"","title":"最长同值路径","titleSlug":"longest-univalue-path"},{"formTitle":"[688]“马”在棋盘上的概率","frontendQuestionId":"688","leaf":true,"level":2,"nodeType":"def","questionId":"688","status":"","title":"“马”在棋盘上的概率","titleSlug":"knight-probability-in-chessboard"},{"formTitle":"[689]三个无重叠子数组的最大和","frontendQuestionId":"689","leaf":true,"level":3,"nodeType":"def","questionId":"689","status":"","title":"三个无重叠子数组的最大和","titleSlug":"maximum-sum-of-3-non-overlapping-subarrays"},{"formTitle":"[690]员工的重要性","frontendQuestionId":"690","leaf":true,"level":1,"nodeType":"def","questionId":"690","status":"","title":"员工的重要性","titleSlug":"employee-importance"},{"formTitle":"[691]贴纸拼词","frontendQuestionId":"691","leaf":true,"level":3,"nodeType":"def","questionId":"691","status":"","title":"贴纸拼词","titleSlug":"stickers-to-spell-word"},{"formTitle":"[692]前K个高频单词","frontendQuestionId":"692","leaf":true,"level":2,"nodeType":"def","questionId":"692","status":"","title":"前K个高频单词","titleSlug":"top-k-frequent-words"},{"formTitle":"[693]交替位二进制数","frontendQuestionId":"693","leaf":true,"level":1,"nodeType":"def","questionId":"693","status":"","title":"交替位二进制数","titleSlug":"binary-number-with-alternating-bits"},{"formTitle":"[694]不同岛屿的数量","frontendQuestionId":"694","leaf":true,"level":2,"nodeType":"def","questionId":"694","status":"lock","title":"不同岛屿的数量","titleSlug":"number-of-distinct-islands"},{"formTitle":"[695]岛屿的最大面积","frontendQuestionId":"695","leaf":true,"level":2,"nodeType":"def","questionId":"695","status":"","title":"岛屿的最大面积","titleSlug":"max-area-of-island"},{"formTitle":"[696]计数二进制子串","frontendQuestionId":"696","leaf":true,"level":1,"nodeType":"def","questionId":"696","status":"","title":"计数二进制子串","titleSlug":"count-binary-substrings"},{"formTitle":"[697]数组的度","frontendQuestionId":"697","leaf":true,"level":1,"nodeType":"def","questionId":"697","status":"","title":"数组的度","titleSlug":"degree-of-an-array"},{"formTitle":"[698]划分为k个相等的子集","frontendQuestionId":"698","leaf":true,"level":2,"nodeType":"def","questionId":"698","status":"","title":"划分为k个相等的子集","titleSlug":"partition-to-k-equal-sum-subsets"},{"formTitle":"[699]掉落的方块","frontendQuestionId":"699","leaf":true,"level":3,"nodeType":"def","questionId":"699","status":"","title":"掉落的方块","titleSlug":"falling-squares"},{"formTitle":"[700]二叉搜索树中的搜索","frontendQuestionId":"700","leaf":true,"level":1,"nodeType":"def","questionId":"783","status":"","title":"二叉搜索树中的搜索","titleSlug":"search-in-a-binary-search-tree"},{"formTitle":"[701]二叉搜索树中的插入操作","frontendQuestionId":"701","leaf":true,"level":2,"nodeType":"def","questionId":"784","status":"","title":"二叉搜索树中的插入操作","titleSlug":"insert-into-a-binary-search-tree"},{"formTitle":"[702]搜索长度未知的有序数组","frontendQuestionId":"702","leaf":true,"level":2,"nodeType":"def","questionId":"786","status":"lock","title":"搜索长度未知的有序数组","titleSlug":"search-in-a-sorted-array-of-unknown-size"},{"formTitle":"[703]数据流中的第K大元素","frontendQuestionId":"703","leaf":true,"level":1,"nodeType":"def","questionId":"789","status":"","title":"数据流中的第K大元素","titleSlug":"kth-largest-element-in-a-stream"},{"formTitle":"[704]二分查找","frontendQuestionId":"704","leaf":true,"level":1,"nodeType":"def","questionId":"792","status":"","title":"二分查找","titleSlug":"binary-search"},{"formTitle":"[705]设计哈希集合","frontendQuestionId":"705","leaf":true,"level":1,"nodeType":"def","questionId":"816","status":"","title":"设计哈希集合","titleSlug":"design-hashset"},{"formTitle":"[706]设计哈希映射","frontendQuestionId":"706","leaf":true,"level":1,"nodeType":"def","questionId":"817","status":"","title":"设计哈希映射","titleSlug":"design-hashmap"},{"formTitle":"[707]设计链表","frontendQuestionId":"707","leaf":true,"level":2,"nodeType":"def","questionId":"838","status":"","title":"设计链表","titleSlug":"design-linked-list"},{"formTitle":"[708]循环有序列表的插入","frontendQuestionId":"708","leaf":true,"level":2,"nodeType":"def","questionId":"850","status":"lock","title":"循环有序列表的插入","titleSlug":"insert-into-a-sorted-circular-linked-list"},{"formTitle":"[709]转换成小写字母","frontendQuestionId":"709","leaf":true,"level":1,"nodeType":"def","questionId":"742","status":"","title":"转换成小写字母","titleSlug":"to-lower-case"},{"formTitle":"[710]黑名单中的随机数","frontendQuestionId":"710","leaf":true,"level":3,"nodeType":"def","questionId":"894","status":"","title":"黑名单中的随机数","titleSlug":"random-pick-with-blacklist"},{"formTitle":"[711]不同岛屿的数量 II","frontendQuestionId":"711","leaf":true,"level":3,"nodeType":"def","questionId":"711","status":"lock","title":"不同岛屿的数量 II","titleSlug":"number-of-distinct-islands-ii"},{"formTitle":"[712]两个字符串的最小ASCII删除和","frontendQuestionId":"712","leaf":true,"level":2,"nodeType":"def","questionId":"712","status":"","title":"两个字符串的最小ASCII删除和","titleSlug":"minimum-ascii-delete-sum-for-two-strings"},{"formTitle":"[713]乘积小于K的子数组","frontendQuestionId":"713","leaf":true,"level":2,"nodeType":"def","questionId":"713","status":"","title":"乘积小于K的子数组","titleSlug":"subarray-product-less-than-k"},{"formTitle":"[714]买卖股票的最佳时机含手续费","frontendQuestionId":"714","leaf":true,"level":2,"nodeType":"def","questionId":"714","status":"","title":"买卖股票的最佳时机含手续费","titleSlug":"best-time-to-buy-and-sell-stock-with-transaction-fee"},{"formTitle":"[715]Range 模块","frontendQuestionId":"715","leaf":true,"level":3,"nodeType":"def","questionId":"715","status":"","title":"Range 模块","titleSlug":"range-module"},{"formTitle":"[716]最大栈","frontendQuestionId":"716","leaf":true,"level":1,"nodeType":"def","questionId":"716","status":"lock","title":"最大栈","titleSlug":"max-stack"},{"formTitle":"[717]1比特与2比特字符","frontendQuestionId":"717","leaf":true,"level":1,"nodeType":"def","questionId":"717","status":"","title":"1比特与2比特字符","titleSlug":"1-bit-and-2-bit-characters"},{"formTitle":"[718]最长重复子数组","frontendQuestionId":"718","leaf":true,"level":2,"nodeType":"def","questionId":"718","status":"","title":"最长重复子数组","titleSlug":"maximum-length-of-repeated-subarray"},{"formTitle":"[719]找出第 k 小的距离对","frontendQuestionId":"719","leaf":true,"level":3,"nodeType":"def","questionId":"719","status":"","title":"找出第 k 小的距离对","titleSlug":"find-k-th-smallest-pair-distance"},{"formTitle":"[720]词典中最长的单词","frontendQuestionId":"720","leaf":true,"level":1,"nodeType":"def","questionId":"720","status":"","title":"词典中最长的单词","titleSlug":"longest-word-in-dictionary"},{"formTitle":"[721]账户合并","frontendQuestionId":"721","leaf":true,"level":2,"nodeType":"def","questionId":"721","status":"","title":"账户合并","titleSlug":"accounts-merge"},{"formTitle":"[722]删除注释","frontendQuestionId":"722","leaf":true,"level":2,"nodeType":"def","questionId":"722","status":"","title":"删除注释","titleSlug":"remove-comments"},{"formTitle":"[723]粉碎糖果","frontendQuestionId":"723","leaf":true,"level":2,"nodeType":"def","questionId":"723","status":"lock","title":"粉碎糖果","titleSlug":"candy-crush"},{"formTitle":"[724]寻找数组的中心索引","frontendQuestionId":"724","leaf":true,"level":1,"nodeType":"def","questionId":"724","status":"","title":"寻找数组的中心索引","titleSlug":"find-pivot-index"},{"formTitle":"[725]分隔链表","frontendQuestionId":"725","leaf":true,"level":2,"nodeType":"def","questionId":"725","status":"","title":"分隔链表","titleSlug":"split-linked-list-in-parts"},{"formTitle":"[726]原子的数量","frontendQuestionId":"726","leaf":true,"level":3,"nodeType":"def","questionId":"726","status":"","title":"原子的数量","titleSlug":"number-of-atoms"},{"formTitle":"[727]最小窗口子序列","frontendQuestionId":"727","leaf":true,"level":3,"nodeType":"def","questionId":"727","status":"lock","title":"最小窗口子序列","titleSlug":"minimum-window-subsequence"},{"formTitle":"[728]自除数","frontendQuestionId":"728","leaf":true,"level":1,"nodeType":"def","questionId":"728","status":"","title":"自除数","titleSlug":"self-dividing-numbers"},{"formTitle":"[729]我的日程安排表 I","frontendQuestionId":"729","leaf":true,"level":2,"nodeType":"def","questionId":"729","status":"","title":"我的日程安排表 I","titleSlug":"my-calendar-i"},{"formTitle":"[730]统计不同回文子字符串","frontendQuestionId":"730","leaf":true,"level":3,"nodeType":"def","questionId":"730","status":"","title":"统计不同回文子字符串","titleSlug":"count-different-palindromic-subsequences"},{"formTitle":"[731]我的日程安排表 II","frontendQuestionId":"731","leaf":true,"level":2,"nodeType":"def","questionId":"731","status":"","title":"我的日程安排表 II","titleSlug":"my-calendar-ii"},{"formTitle":"[732]我的日程安排表 III","frontendQuestionId":"732","leaf":true,"level":3,"nodeType":"def","questionId":"732","status":"","title":"我的日程安排表 III","titleSlug":"my-calendar-iii"},{"formTitle":"[733]图像渲染","frontendQuestionId":"733","leaf":true,"level":1,"nodeType":"def","questionId":"733","status":"","title":"图像渲染","titleSlug":"flood-fill"},{"formTitle":"[734]句子相似性","frontendQuestionId":"734","leaf":true,"level":1,"nodeType":"def","questionId":"734","status":"lock","title":"句子相似性","titleSlug":"sentence-similarity"},{"formTitle":"[735]行星碰撞","frontendQuestionId":"735","leaf":true,"level":2,"nodeType":"def","questionId":"735","status":"","title":"行星碰撞","titleSlug":"asteroid-collision"},{"formTitle":"[736]Lisp 语法解析","frontendQuestionId":"736","leaf":true,"level":3,"nodeType":"def","questionId":"736","status":"","title":"Lisp 语法解析","titleSlug":"parse-lisp-expression"},{"formTitle":"[737]句子相似性 II","frontendQuestionId":"737","leaf":true,"level":2,"nodeType":"def","questionId":"737","status":"lock","title":"句子相似性 II","titleSlug":"sentence-similarity-ii"},{"formTitle":"[738]单调递增的数字","frontendQuestionId":"738","leaf":true,"level":2,"nodeType":"def","questionId":"738","status":"","title":"单调递增的数字","titleSlug":"monotone-increasing-digits"},{"formTitle":"[739]每日温度","frontendQuestionId":"739","leaf":true,"level":2,"nodeType":"def","questionId":"739","status":"","title":"每日温度","titleSlug":"daily-temperatures"},{"formTitle":"[740]删除与获得点数","frontendQuestionId":"740","leaf":true,"level":2,"nodeType":"def","questionId":"740","status":"","title":"删除与获得点数","titleSlug":"delete-and-earn"},{"formTitle":"[741]摘樱桃","frontendQuestionId":"741","leaf":true,"level":3,"nodeType":"def","questionId":"741","status":"","title":"摘樱桃","titleSlug":"cherry-pickup"},{"formTitle":"[742]二叉树最近的叶节点","frontendQuestionId":"742","leaf":true,"level":2,"nodeType":"def","questionId":"743","status":"lock","title":"二叉树最近的叶节点","titleSlug":"closest-leaf-in-a-binary-tree"},{"formTitle":"[743]网络延迟时间","frontendQuestionId":"743","leaf":true,"level":2,"nodeType":"def","questionId":"744","status":"","title":"网络延迟时间","titleSlug":"network-delay-time"},{"formTitle":"[744]寻找比目标字母大的最小字母","frontendQuestionId":"744","leaf":true,"level":1,"nodeType":"def","questionId":"745","status":"","title":"寻找比目标字母大的最小字母","titleSlug":"find-smallest-letter-greater-than-target"},{"formTitle":"[745]前缀和后缀搜索","frontendQuestionId":"745","leaf":true,"level":3,"nodeType":"def","questionId":"746","status":"","title":"前缀和后缀搜索","titleSlug":"prefix-and-suffix-search"},{"formTitle":"[746]使用最小花费爬楼梯","frontendQuestionId":"746","leaf":true,"level":1,"nodeType":"def","questionId":"747","status":"","title":"使用最小花费爬楼梯","titleSlug":"min-cost-climbing-stairs"},{"formTitle":"[747]至少是其他数字两倍的最大数","frontendQuestionId":"747","leaf":true,"level":1,"nodeType":"def","questionId":"748","status":"","title":"至少是其他数字两倍的最大数","titleSlug":"largest-number-at-least-twice-of-others"},{"formTitle":"[748]最短完整词","frontendQuestionId":"748","leaf":true,"level":1,"nodeType":"def","questionId":"749","status":"","title":"最短完整词","titleSlug":"shortest-completing-word"},{"formTitle":"[749]隔离病毒","frontendQuestionId":"749","leaf":true,"level":3,"nodeType":"def","questionId":"750","status":"","title":"隔离病毒","titleSlug":"contain-virus"},{"formTitle":"[750]角矩形的数量","frontendQuestionId":"750","leaf":true,"level":2,"nodeType":"def","questionId":"751","status":"lock","title":"角矩形的数量","titleSlug":"number-of-corner-rectangles"},{"formTitle":"[751]IP 到 CIDR","frontendQuestionId":"751","leaf":true,"level":1,"nodeType":"def","questionId":"752","status":"lock","title":"IP 到 CIDR","titleSlug":"ip-to-cidr"},{"formTitle":"[752]打开转盘锁","frontendQuestionId":"752","leaf":true,"level":2,"nodeType":"def","questionId":"753","status":"","title":"打开转盘锁","titleSlug":"open-the-lock"},{"formTitle":"[753]破解保险箱","frontendQuestionId":"753","leaf":true,"level":3,"nodeType":"def","questionId":"754","status":"","title":"破解保险箱","titleSlug":"cracking-the-safe"},{"formTitle":"[754]到达终点数字","frontendQuestionId":"754","leaf":true,"level":2,"nodeType":"def","questionId":"755","status":"","title":"到达终点数字","titleSlug":"reach-a-number"},{"formTitle":"[755]倒水","frontendQuestionId":"755","leaf":true,"level":2,"nodeType":"def","questionId":"756","status":"lock","title":"倒水","titleSlug":"pour-water"},{"formTitle":"[756]金字塔转换矩阵","frontendQuestionId":"756","leaf":true,"level":2,"nodeType":"def","questionId":"757","status":"","title":"金字塔转换矩阵","titleSlug":"pyramid-transition-matrix"},{"formTitle":"[757] 设置交集大小至少为2","frontendQuestionId":"757","leaf":true,"level":3,"nodeType":"def","questionId":"759","status":"","title":" 设置交集大小至少为2","titleSlug":"set-intersection-size-at-least-two"},{"formTitle":"[758]字符串中的加粗单词","frontendQuestionId":"758","leaf":true,"level":1,"nodeType":"def","questionId":"760","status":"lock","title":"字符串中的加粗单词","titleSlug":"bold-words-in-string"},{"formTitle":"[759]员工空闲时间","frontendQuestionId":"759","leaf":true,"level":3,"nodeType":"def","questionId":"761","status":"lock","title":"员工空闲时间","titleSlug":"employee-free-time"},{"formTitle":"[760]找出变位映射","frontendQuestionId":"760","leaf":true,"level":1,"nodeType":"def","questionId":"762","status":"lock","title":"找出变位映射","titleSlug":"find-anagram-mappings"},{"formTitle":"[761]特殊的二进制序列","frontendQuestionId":"761","leaf":true,"level":3,"nodeType":"def","questionId":"763","status":"","title":"特殊的二进制序列","titleSlug":"special-binary-string"},{"formTitle":"[762]二进制表示中质数个计算置位","frontendQuestionId":"762","leaf":true,"level":1,"nodeType":"def","questionId":"767","status":"","title":"二进制表示中质数个计算置位","titleSlug":"prime-number-of-set-bits-in-binary-representation"},{"formTitle":"[763]划分字母区间","frontendQuestionId":"763","leaf":true,"level":2,"nodeType":"def","questionId":"768","status":"","title":"划分字母区间","titleSlug":"partition-labels"},{"formTitle":"[764]最大加号标志","frontendQuestionId":"764","leaf":true,"level":2,"nodeType":"def","questionId":"769","status":"","title":"最大加号标志","titleSlug":"largest-plus-sign"},{"formTitle":"[765]情侣牵手","frontendQuestionId":"765","leaf":true,"level":3,"nodeType":"def","questionId":"770","status":"","title":"情侣牵手","titleSlug":"couples-holding-hands"},{"formTitle":"[766]托普利茨矩阵","frontendQuestionId":"766","leaf":true,"level":1,"nodeType":"def","questionId":"777","status":"","title":"托普利茨矩阵","titleSlug":"toeplitz-matrix"},{"formTitle":"[767]重构字符串","frontendQuestionId":"767","leaf":true,"level":2,"nodeType":"def","questionId":"778","status":"","title":"重构字符串","titleSlug":"reorganize-string"},{"formTitle":"[768]最多能完成排序的块 II","frontendQuestionId":"768","leaf":true,"level":3,"nodeType":"def","questionId":"779","status":"","title":"最多能完成排序的块 II","titleSlug":"max-chunks-to-make-sorted-ii"},{"formTitle":"[769]最多能完成排序的块","frontendQuestionId":"769","leaf":true,"level":2,"nodeType":"def","questionId":"780","status":"","title":"最多能完成排序的块","titleSlug":"max-chunks-to-make-sorted"},{"formTitle":"[770]基本计算器 IV","frontendQuestionId":"770","leaf":true,"level":3,"nodeType":"def","questionId":"781","status":"","title":"基本计算器 IV","titleSlug":"basic-calculator-iv"},{"formTitle":"[771]宝石与石头","frontendQuestionId":"771","leaf":true,"level":1,"nodeType":"def","questionId":"782","status":"","title":"宝石与石头","titleSlug":"jewels-and-stones"},{"formTitle":"[772]基本计算器 III","frontendQuestionId":"772","leaf":true,"level":3,"nodeType":"def","questionId":"785","status":"lock","title":"基本计算器 III","titleSlug":"basic-calculator-iii"},{"formTitle":"[773]滑动谜题","frontendQuestionId":"773","leaf":true,"level":3,"nodeType":"def","questionId":"787","status":"","title":"滑动谜题","titleSlug":"sliding-puzzle"},{"formTitle":"[774]最小化去加油站的最大距离","frontendQuestionId":"774","leaf":true,"level":3,"nodeType":"def","questionId":"788","status":"lock","title":"最小化去加油站的最大距离","titleSlug":"minimize-max-distance-to-gas-station"},{"formTitle":"[775]全局倒置与局部倒置","frontendQuestionId":"775","leaf":true,"level":2,"nodeType":"def","questionId":"790","status":"","title":"全局倒置与局部倒置","titleSlug":"global-and-local-inversions"},{"formTitle":"[776]拆分二叉搜索树","frontendQuestionId":"776","leaf":true,"level":2,"nodeType":"def","questionId":"791","status":"lock","title":"拆分二叉搜索树","titleSlug":"split-bst"},{"formTitle":"[777]在LR字符串中交换相邻字符","frontendQuestionId":"777","leaf":true,"level":2,"nodeType":"def","questionId":"793","status":"","title":"在LR字符串中交换相邻字符","titleSlug":"swap-adjacent-in-lr-string"},{"formTitle":"[778]水位上升的泳池中游泳","frontendQuestionId":"778","leaf":true,"level":3,"nodeType":"def","questionId":"794","status":"","title":"水位上升的泳池中游泳","titleSlug":"swim-in-rising-water"},{"formTitle":"[779]第K个语法符号","frontendQuestionId":"779","leaf":true,"level":2,"nodeType":"def","questionId":"795","status":"","title":"第K个语法符号","titleSlug":"k-th-symbol-in-grammar"},{"formTitle":"[780]到达终点","frontendQuestionId":"780","leaf":true,"level":3,"nodeType":"def","questionId":"796","status":"","title":"到达终点","titleSlug":"reaching-points"},{"formTitle":"[781]森林中的兔子","frontendQuestionId":"781","leaf":true,"level":2,"nodeType":"def","questionId":"797","status":"","title":"森林中的兔子","titleSlug":"rabbits-in-forest"},{"formTitle":"[782]变为棋盘","frontendQuestionId":"782","leaf":true,"level":3,"nodeType":"def","questionId":"798","status":"","title":"变为棋盘","titleSlug":"transform-to-chessboard"},{"formTitle":"[783]二叉搜索树结点最小距离","frontendQuestionId":"783","leaf":true,"level":1,"nodeType":"def","questionId":"799","status":"","title":"二叉搜索树结点最小距离","titleSlug":"minimum-distance-between-bst-nodes"},{"formTitle":"[784]字母大小写全排列","frontendQuestionId":"784","leaf":true,"level":1,"nodeType":"def","questionId":"800","status":"","title":"字母大小写全排列","titleSlug":"letter-case-permutation"},{"formTitle":"[785]判断二分图","frontendQuestionId":"785","leaf":true,"level":2,"nodeType":"def","questionId":"801","status":"","title":"判断二分图","titleSlug":"is-graph-bipartite"},{"formTitle":"[786]第 K 个最小的素数分数","frontendQuestionId":"786","leaf":true,"level":3,"nodeType":"def","questionId":"802","status":"","title":"第 K 个最小的素数分数","titleSlug":"k-th-smallest-prime-fraction"},{"formTitle":"[787]K 站中转内最便宜的航班","frontendQuestionId":"787","leaf":true,"level":2,"nodeType":"def","questionId":"803","status":"","title":"K 站中转内最便宜的航班","titleSlug":"cheapest-flights-within-k-stops"},{"formTitle":"[788]旋转数字","frontendQuestionId":"788","leaf":true,"level":1,"nodeType":"def","questionId":"804","status":"","title":"旋转数字","titleSlug":"rotated-digits"},{"formTitle":"[789]逃脱阻碍者","frontendQuestionId":"789","leaf":true,"level":2,"nodeType":"def","questionId":"805","status":"","title":"逃脱阻碍者","titleSlug":"escape-the-ghosts"},{"formTitle":"[790]多米诺和托米诺平铺","frontendQuestionId":"790","leaf":true,"level":2,"nodeType":"def","questionId":"806","status":"","title":"多米诺和托米诺平铺","titleSlug":"domino-and-tromino-tiling"},{"formTitle":"[791]自定义字符串排序","frontendQuestionId":"791","leaf":true,"level":2,"nodeType":"def","questionId":"807","status":"","title":"自定义字符串排序","titleSlug":"custom-sort-string"},{"formTitle":"[792]匹配子序列的单词数","frontendQuestionId":"792","leaf":true,"level":2,"nodeType":"def","questionId":"808","status":"","title":"匹配子序列的单词数","titleSlug":"number-of-matching-subsequences"},{"formTitle":"[793]阶乘函数后K个零","frontendQuestionId":"793","leaf":true,"level":3,"nodeType":"def","questionId":"809","status":"","title":"阶乘函数后K个零","titleSlug":"preimage-size-of-factorial-zeroes-function"},{"formTitle":"[794]有效的井字游戏","frontendQuestionId":"794","leaf":true,"level":2,"nodeType":"def","questionId":"810","status":"","title":"有效的井字游戏","titleSlug":"valid-tic-tac-toe-state"},{"formTitle":"[795]区间子数组个数","frontendQuestionId":"795","leaf":true,"level":2,"nodeType":"def","questionId":"811","status":"","title":"区间子数组个数","titleSlug":"number-of-subarrays-with-bounded-maximum"},{"formTitle":"[796]旋转字符串","frontendQuestionId":"796","leaf":true,"level":1,"nodeType":"def","questionId":"812","status":"","title":"旋转字符串","titleSlug":"rotate-string"},{"formTitle":"[797]所有可能的路径","frontendQuestionId":"797","leaf":true,"level":2,"nodeType":"def","questionId":"813","status":"","title":"所有可能的路径","titleSlug":"all-paths-from-source-to-target"},{"formTitle":"[798]得分最高的最小轮调","frontendQuestionId":"798","leaf":true,"level":3,"nodeType":"def","questionId":"814","status":"","title":"得分最高的最小轮调","titleSlug":"smallest-rotation-with-highest-score"},{"formTitle":"[799]香槟塔","frontendQuestionId":"799","leaf":true,"level":2,"nodeType":"def","questionId":"815","status":"","title":"香槟塔","titleSlug":"champagne-tower"},{"formTitle":"[800]相似 RGB 颜色","frontendQuestionId":"800","leaf":true,"level":1,"nodeType":"def","questionId":"818","status":"lock","title":"相似 RGB 颜色","titleSlug":"similar-rgb-color"},{"formTitle":"[801]使序列递增的最小交换次数","frontendQuestionId":"801","leaf":true,"level":2,"nodeType":"def","questionId":"819","status":"","title":"使序列递增的最小交换次数","titleSlug":"minimum-swaps-to-make-sequences-increasing"},{"formTitle":"[802]找到最终的安全状态","frontendQuestionId":"802","leaf":true,"level":2,"nodeType":"def","questionId":"820","status":"","title":"找到最终的安全状态","titleSlug":"find-eventual-safe-states"},{"formTitle":"[803]打砖块","frontendQuestionId":"803","leaf":true,"level":3,"nodeType":"def","questionId":"821","status":"","title":"打砖块","titleSlug":"bricks-falling-when-hit"},{"formTitle":"[804]唯一摩尔斯密码词","frontendQuestionId":"804","leaf":true,"level":1,"nodeType":"def","questionId":"822","status":"","title":"唯一摩尔斯密码词","titleSlug":"unique-morse-code-words"},{"formTitle":"[805]数组的均值分割","frontendQuestionId":"805","leaf":true,"level":3,"nodeType":"def","questionId":"823","status":"","title":"数组的均值分割","titleSlug":"split-array-with-same-average"},{"formTitle":"[806]写字符串需要的行数","frontendQuestionId":"806","leaf":true,"level":1,"nodeType":"def","questionId":"824","status":"","title":"写字符串需要的行数","titleSlug":"number-of-lines-to-write-string"},{"formTitle":"[807]保持城市天际线","frontendQuestionId":"807","leaf":true,"level":2,"nodeType":"def","questionId":"825","status":"","title":"保持城市天际线","titleSlug":"max-increase-to-keep-city-skyline"},{"formTitle":"[808]分汤","frontendQuestionId":"808","leaf":true,"level":2,"nodeType":"def","questionId":"826","status":"","title":"分汤","titleSlug":"soup-servings"},{"formTitle":"[809]情感丰富的文字","frontendQuestionId":"809","leaf":true,"level":2,"nodeType":"def","questionId":"827","status":"","title":"情感丰富的文字","titleSlug":"expressive-words"},{"formTitle":"[810]黑板异或游戏","frontendQuestionId":"810","leaf":true,"level":3,"nodeType":"def","questionId":"828","status":"","title":"黑板异或游戏","titleSlug":"chalkboard-xor-game"},{"formTitle":"[811]子域名访问计数","frontendQuestionId":"811","leaf":true,"level":1,"nodeType":"def","questionId":"829","status":"","title":"子域名访问计数","titleSlug":"subdomain-visit-count"},{"formTitle":"[812]最大三角形面积","frontendQuestionId":"812","leaf":true,"level":1,"nodeType":"def","questionId":"830","status":"","title":"最大三角形面积","titleSlug":"largest-triangle-area"},{"formTitle":"[813]最大平均值和的分组","frontendQuestionId":"813","leaf":true,"level":2,"nodeType":"def","questionId":"831","status":"","title":"最大平均值和的分组","titleSlug":"largest-sum-of-averages"},{"formTitle":"[814]二叉树剪枝","frontendQuestionId":"814","leaf":true,"level":2,"nodeType":"def","questionId":"832","status":"","title":"二叉树剪枝","titleSlug":"binary-tree-pruning"},{"formTitle":"[815]公交路线","frontendQuestionId":"815","leaf":true,"level":3,"nodeType":"def","questionId":"833","status":"","title":"公交路线","titleSlug":"bus-routes"},{"formTitle":"[816]模糊坐标","frontendQuestionId":"816","leaf":true,"level":2,"nodeType":"def","questionId":"834","status":"","title":"模糊坐标","titleSlug":"ambiguous-coordinates"},{"formTitle":"[817]链表组件","frontendQuestionId":"817","leaf":true,"level":2,"nodeType":"def","questionId":"835","status":"","title":"链表组件","titleSlug":"linked-list-components"},{"formTitle":"[818]赛车","frontendQuestionId":"818","leaf":true,"level":3,"nodeType":"def","questionId":"836","status":"","title":"赛车","titleSlug":"race-car"},{"formTitle":"[819]最常见的单词","frontendQuestionId":"819","leaf":true,"level":1,"nodeType":"def","questionId":"837","status":"","title":"最常见的单词","titleSlug":"most-common-word"},{"formTitle":"[820]单词的压缩编码","frontendQuestionId":"820","leaf":true,"level":2,"nodeType":"def","questionId":"839","status":"","title":"单词的压缩编码","titleSlug":"short-encoding-of-words"},{"formTitle":"[821]字符的最短距离","frontendQuestionId":"821","leaf":true,"level":1,"nodeType":"def","questionId":"841","status":"","title":"字符的最短距离","titleSlug":"shortest-distance-to-a-character"},{"formTitle":"[822]翻转卡片游戏","frontendQuestionId":"822","leaf":true,"level":2,"nodeType":"def","questionId":"842","status":"","title":"翻转卡片游戏","titleSlug":"card-flipping-game"},{"formTitle":"[823]带因子的二叉树","frontendQuestionId":"823","leaf":true,"level":2,"nodeType":"def","questionId":"843","status":"","title":"带因子的二叉树","titleSlug":"binary-trees-with-factors"},{"formTitle":"[824]山羊拉丁文","frontendQuestionId":"824","leaf":true,"level":1,"nodeType":"def","questionId":"851","status":"","title":"山羊拉丁文","titleSlug":"goat-latin"},{"formTitle":"[825]适龄的朋友","frontendQuestionId":"825","leaf":true,"level":2,"nodeType":"def","questionId":"852","status":"","title":"适龄的朋友","titleSlug":"friends-of-appropriate-ages"},{"formTitle":"[826]安排工作以达到最大收益","frontendQuestionId":"826","leaf":true,"level":2,"nodeType":"def","questionId":"853","status":"","title":"安排工作以达到最大收益","titleSlug":"most-profit-assigning-work"},{"formTitle":"[827]最大人工岛","frontendQuestionId":"827","leaf":true,"level":3,"nodeType":"def","questionId":"854","status":"","title":"最大人工岛","titleSlug":"making-a-large-island"},{"formTitle":"[828]独特字符串","frontendQuestionId":"828","leaf":true,"level":3,"nodeType":"def","questionId":"855","status":"","title":"独特字符串","titleSlug":"unique-letter-string"},{"formTitle":"[829]连续整数求和","frontendQuestionId":"829","leaf":true,"level":3,"nodeType":"def","questionId":"856","status":"","title":"连续整数求和","titleSlug":"consecutive-numbers-sum"},{"formTitle":"[830]较大分组的位置","frontendQuestionId":"830","leaf":true,"level":1,"nodeType":"def","questionId":"857","status":"","title":"较大分组的位置","titleSlug":"positions-of-large-groups"},{"formTitle":"[831]隐藏个人信息","frontendQuestionId":"831","leaf":true,"level":2,"nodeType":"def","questionId":"858","status":"","title":"隐藏个人信息","titleSlug":"masking-personal-information"},{"formTitle":"[832]翻转图像","frontendQuestionId":"832","leaf":true,"level":1,"nodeType":"def","questionId":"861","status":"","title":"翻转图像","titleSlug":"flipping-an-image"},{"formTitle":"[833]字符串中的查找与替换","frontendQuestionId":"833","leaf":true,"level":2,"nodeType":"def","questionId":"862","status":"","title":"字符串中的查找与替换","titleSlug":"find-and-replace-in-string"},{"formTitle":"[834]树中距离之和","frontendQuestionId":"834","leaf":true,"level":3,"nodeType":"def","questionId":"863","status":"","title":"树中距离之和","titleSlug":"sum-of-distances-in-tree"},{"formTitle":"[835]图像重叠","frontendQuestionId":"835","leaf":true,"level":2,"nodeType":"def","questionId":"864","status":"","title":"图像重叠","titleSlug":"image-overlap"},{"formTitle":"[836]矩形重叠","frontendQuestionId":"836","leaf":true,"level":1,"nodeType":"def","questionId":"866","status":"","title":"矩形重叠","titleSlug":"rectangle-overlap"},{"formTitle":"[837]新21点","frontendQuestionId":"837","leaf":true,"level":2,"nodeType":"def","questionId":"867","status":"","title":"新21点","titleSlug":"new-21-game"},{"formTitle":"[838]推多米诺","frontendQuestionId":"838","leaf":true,"level":2,"nodeType":"def","questionId":"868","status":"","title":"推多米诺","titleSlug":"push-dominoes"},{"formTitle":"[839]相似字符串组","frontendQuestionId":"839","leaf":true,"level":3,"nodeType":"def","questionId":"869","status":"","title":"相似字符串组","titleSlug":"similar-string-groups"},{"formTitle":"[840]矩阵中的幻方","frontendQuestionId":"840","leaf":true,"level":1,"nodeType":"def","questionId":"870","status":"","title":"矩阵中的幻方","titleSlug":"magic-squares-in-grid"},{"formTitle":"[841]钥匙和房间","frontendQuestionId":"841","leaf":true,"level":2,"nodeType":"def","questionId":"871","status":"","title":"钥匙和房间","titleSlug":"keys-and-rooms"},{"formTitle":"[842]将数组拆分成斐波那契序列","frontendQuestionId":"842","leaf":true,"level":2,"nodeType":"def","questionId":"872","status":"","title":"将数组拆分成斐波那契序列","titleSlug":"split-array-into-fibonacci-sequence"},{"formTitle":"[843]猜猜这个单词","frontendQuestionId":"843","leaf":true,"level":3,"nodeType":"def","questionId":"873","status":"","title":"猜猜这个单词","titleSlug":"guess-the-word"},{"formTitle":"[844]比较含退格的字符串","frontendQuestionId":"844","leaf":true,"level":1,"nodeType":"def","questionId":"874","status":"","title":"比较含退格的字符串","titleSlug":"backspace-string-compare"},{"formTitle":"[845]数组中的最长山脉","frontendQuestionId":"845","leaf":true,"level":2,"nodeType":"def","questionId":"875","status":"","title":"数组中的最长山脉","titleSlug":"longest-mountain-in-array"},{"formTitle":"[846]一手顺子","frontendQuestionId":"846","leaf":true,"level":2,"nodeType":"def","questionId":"876","status":"","title":"一手顺子","titleSlug":"hand-of-straights"},{"formTitle":"[847]访问所有节点的最短路径","frontendQuestionId":"847","leaf":true,"level":3,"nodeType":"def","questionId":"877","status":"","title":"访问所有节点的最短路径","titleSlug":"shortest-path-visiting-all-nodes"},{"formTitle":"[848]字母移位","frontendQuestionId":"848","leaf":true,"level":2,"nodeType":"def","questionId":"878","status":"","title":"字母移位","titleSlug":"shifting-letters"},{"formTitle":"[849]到最近的人的最大距离","frontendQuestionId":"849","leaf":true,"level":1,"nodeType":"def","questionId":"879","status":"","title":"到最近的人的最大距离","titleSlug":"maximize-distance-to-closest-person"},{"formTitle":"[850]矩形面积 II","frontendQuestionId":"850","leaf":true,"level":3,"nodeType":"def","questionId":"880","status":"","title":"矩形面积 II","titleSlug":"rectangle-area-ii"},{"formTitle":"[851]喧闹和富有","frontendQuestionId":"851","leaf":true,"level":2,"nodeType":"def","questionId":"881","status":"","title":"喧闹和富有","titleSlug":"loud-and-rich"},{"formTitle":"[852]山脉数组的峰顶索引","frontendQuestionId":"852","leaf":true,"level":1,"nodeType":"def","questionId":"882","status":"","title":"山脉数组的峰顶索引","titleSlug":"peak-index-in-a-mountain-array"},{"formTitle":"[853]车队","frontendQuestionId":"853","leaf":true,"level":2,"nodeType":"def","questionId":"883","status":"","title":"车队","titleSlug":"car-fleet"},{"formTitle":"[854]相似度为 K 的字符串","frontendQuestionId":"854","leaf":true,"level":3,"nodeType":"def","questionId":"884","status":"","title":"相似度为 K 的字符串","titleSlug":"k-similar-strings"},{"formTitle":"[855]考场就座","frontendQuestionId":"855","leaf":true,"level":2,"nodeType":"def","questionId":"885","status":"","title":"考场就座","titleSlug":"exam-room"},{"formTitle":"[856]括号的分数","frontendQuestionId":"856","leaf":true,"level":2,"nodeType":"def","questionId":"886","status":"","title":"括号的分数","titleSlug":"score-of-parentheses"},{"formTitle":"[857]雇佣 K 名工人的最低成本","frontendQuestionId":"857","leaf":true,"level":3,"nodeType":"def","questionId":"887","status":"","title":"雇佣 K 名工人的最低成本","titleSlug":"minimum-cost-to-hire-k-workers"},{"formTitle":"[858]镜面反射","frontendQuestionId":"858","leaf":true,"level":2,"nodeType":"def","questionId":"888","status":"","title":"镜面反射","titleSlug":"mirror-reflection"},{"formTitle":"[859]亲密字符串","frontendQuestionId":"859","leaf":true,"level":1,"nodeType":"def","questionId":"889","status":"","title":"亲密字符串","titleSlug":"buddy-strings"},{"formTitle":"[860]柠檬水找零","frontendQuestionId":"860","leaf":true,"level":1,"nodeType":"def","questionId":"890","status":"","title":"柠檬水找零","titleSlug":"lemonade-change"},{"formTitle":"[861]翻转矩阵后的得分","frontendQuestionId":"861","leaf":true,"level":2,"nodeType":"def","questionId":"891","status":"","title":"翻转矩阵后的得分","titleSlug":"score-after-flipping-matrix"},{"formTitle":"[862]和至少为 K 的最短子数组","frontendQuestionId":"862","leaf":true,"level":3,"nodeType":"def","questionId":"892","status":"","title":"和至少为 K 的最短子数组","titleSlug":"shortest-subarray-with-sum-at-least-k"},{"formTitle":"[863]二叉树中所有距离为 K 的结点","frontendQuestionId":"863","leaf":true,"level":2,"nodeType":"def","questionId":"893","status":"","title":"二叉树中所有距离为 K 的结点","titleSlug":"all-nodes-distance-k-in-binary-tree"},{"formTitle":"[864]获取所有钥匙的最短路径","frontendQuestionId":"864","leaf":true,"level":3,"nodeType":"def","questionId":"895","status":"","title":"获取所有钥匙的最短路径","titleSlug":"shortest-path-to-get-all-keys"},{"formTitle":"[865]具有所有最深结点的最小子树","frontendQuestionId":"865","leaf":true,"level":2,"nodeType":"def","questionId":"896","status":"","title":"具有所有最深结点的最小子树","titleSlug":"smallest-subtree-with-all-the-deepest-nodes"},{"formTitle":"[866]回文素数","frontendQuestionId":"866","leaf":true,"level":2,"nodeType":"def","questionId":"897","status":"","title":"回文素数","titleSlug":"prime-palindrome"},{"formTitle":"[867]转置矩阵","frontendQuestionId":"867","leaf":true,"level":1,"nodeType":"def","questionId":"898","status":"","title":"转置矩阵","titleSlug":"transpose-matrix"},{"formTitle":"[868]二进制间距","frontendQuestionId":"868","leaf":true,"level":1,"nodeType":"def","questionId":"899","status":"","title":"二进制间距","titleSlug":"binary-gap"},{"formTitle":"[869]重新排序得到 2 的幂","frontendQuestionId":"869","leaf":true,"level":2,"nodeType":"def","questionId":"900","status":"","title":"重新排序得到 2 的幂","titleSlug":"reordered-power-of-2"},{"formTitle":"[870]优势洗牌","frontendQuestionId":"870","leaf":true,"level":2,"nodeType":"def","questionId":"901","status":"","title":"优势洗牌","titleSlug":"advantage-shuffle"},{"formTitle":"[871]最低加油次数","frontendQuestionId":"871","leaf":true,"level":3,"nodeType":"def","questionId":"902","status":"","title":"最低加油次数","titleSlug":"minimum-number-of-refueling-stops"},{"formTitle":"[872]叶子相似的树","frontendQuestionId":"872","leaf":true,"level":1,"nodeType":"def","questionId":"904","status":"","title":"叶子相似的树","titleSlug":"leaf-similar-trees"},{"formTitle":"[873]最长的斐波那契子序列的长度","frontendQuestionId":"873","leaf":true,"level":2,"nodeType":"def","questionId":"905","status":"","title":"最长的斐波那契子序列的长度","titleSlug":"length-of-longest-fibonacci-subsequence"},{"formTitle":"[874]模拟行走机器人","frontendQuestionId":"874","leaf":true,"level":1,"nodeType":"def","questionId":"906","status":"","title":"模拟行走机器人","titleSlug":"walking-robot-simulation"},{"formTitle":"[875]爱吃香蕉的珂珂","frontendQuestionId":"875","leaf":true,"level":2,"nodeType":"def","questionId":"907","status":"","title":"爱吃香蕉的珂珂","titleSlug":"koko-eating-bananas"},{"formTitle":"[876]链表的中间结点","frontendQuestionId":"876","leaf":true,"level":1,"nodeType":"def","questionId":"908","status":"","title":"链表的中间结点","titleSlug":"middle-of-the-linked-list"},{"formTitle":"[877]石子游戏","frontendQuestionId":"877","leaf":true,"level":2,"nodeType":"def","questionId":"909","status":"","title":"石子游戏","titleSlug":"stone-game"},{"formTitle":"[878]第 N 个神奇数字","frontendQuestionId":"878","leaf":true,"level":3,"nodeType":"def","questionId":"910","status":"","title":"第 N 个神奇数字","titleSlug":"nth-magical-number"},{"formTitle":"[879]盈利计划","frontendQuestionId":"879","leaf":true,"level":3,"nodeType":"def","questionId":"911","status":"","title":"盈利计划","titleSlug":"profitable-schemes"},{"formTitle":"[880]索引处的解码字符串","frontendQuestionId":"880","leaf":true,"level":2,"nodeType":"def","questionId":"916","status":"","title":"索引处的解码字符串","titleSlug":"decoded-string-at-index"},{"formTitle":"[881]救生艇","frontendQuestionId":"881","leaf":true,"level":2,"nodeType":"def","questionId":"917","status":"","title":"救生艇","titleSlug":"boats-to-save-people"},{"formTitle":"[882]细分图中的可到达结点","frontendQuestionId":"882","leaf":true,"level":3,"nodeType":"def","questionId":"918","status":"","title":"细分图中的可到达结点","titleSlug":"reachable-nodes-in-subdivided-graph"},{"formTitle":"[883]三维形体投影面积","frontendQuestionId":"883","leaf":true,"level":1,"nodeType":"def","questionId":"919","status":"","title":"三维形体投影面积","titleSlug":"projection-area-of-3d-shapes"},{"formTitle":"[884]两句话中的不常见单词","frontendQuestionId":"884","leaf":true,"level":1,"nodeType":"def","questionId":"920","status":"","title":"两句话中的不常见单词","titleSlug":"uncommon-words-from-two-sentences"},{"formTitle":"[885]螺旋矩阵 III","frontendQuestionId":"885","leaf":true,"level":2,"nodeType":"def","questionId":"921","status":"","title":"螺旋矩阵 III","titleSlug":"spiral-matrix-iii"},{"formTitle":"[886]可能的二分法","frontendQuestionId":"886","leaf":true,"level":2,"nodeType":"def","questionId":"922","status":"","title":"可能的二分法","titleSlug":"possible-bipartition"},{"formTitle":"[887]鸡蛋掉落","frontendQuestionId":"887","leaf":true,"level":3,"nodeType":"def","questionId":"923","status":"","title":"鸡蛋掉落","titleSlug":"super-egg-drop"},{"formTitle":"[888]公平的糖果交换","frontendQuestionId":"888","leaf":true,"level":1,"nodeType":"def","questionId":"924","status":"","title":"公平的糖果交换","titleSlug":"fair-candy-swap"},{"formTitle":"[889]根据前序和后序遍历构造二叉树","frontendQuestionId":"889","leaf":true,"level":2,"nodeType":"def","questionId":"925","status":"","title":"根据前序和后序遍历构造二叉树","titleSlug":"construct-binary-tree-from-preorder-and-postorder-traversal"},{"formTitle":"[890]查找和替换模式","frontendQuestionId":"890","leaf":true,"level":2,"nodeType":"def","questionId":"926","status":"","title":"查找和替换模式","titleSlug":"find-and-replace-pattern"},{"formTitle":"[891]子序列宽度之和","frontendQuestionId":"891","leaf":true,"level":3,"nodeType":"def","questionId":"927","status":"","title":"子序列宽度之和","titleSlug":"sum-of-subsequence-widths"},{"formTitle":"[892]三维形体的表面积","frontendQuestionId":"892","leaf":true,"level":1,"nodeType":"def","questionId":"928","status":"","title":"三维形体的表面积","titleSlug":"surface-area-of-3d-shapes"},{"formTitle":"[893]特殊等价字符串组","frontendQuestionId":"893","leaf":true,"level":1,"nodeType":"def","questionId":"929","status":"","title":"特殊等价字符串组","titleSlug":"groups-of-special-equivalent-strings"},{"formTitle":"[894]所有可能的满二叉树","frontendQuestionId":"894","leaf":true,"level":2,"nodeType":"def","questionId":"930","status":"","title":"所有可能的满二叉树","titleSlug":"all-possible-full-binary-trees"},{"formTitle":"[895]最大频率栈","frontendQuestionId":"895","leaf":true,"level":3,"nodeType":"def","questionId":"931","status":"","title":"最大频率栈","titleSlug":"maximum-frequency-stack"},{"formTitle":"[896]单调数列","frontendQuestionId":"896","leaf":true,"level":1,"nodeType":"def","questionId":"932","status":"","title":"单调数列","titleSlug":"monotonic-array"},{"formTitle":"[897]递增顺序查找树","frontendQuestionId":"897","leaf":true,"level":1,"nodeType":"def","questionId":"933","status":"","title":"递增顺序查找树","titleSlug":"increasing-order-search-tree"},{"formTitle":"[898]子数组按位或操作","frontendQuestionId":"898","leaf":true,"level":2,"nodeType":"def","questionId":"934","status":"","title":"子数组按位或操作","titleSlug":"bitwise-ors-of-subarrays"},{"formTitle":"[899]有序队列","frontendQuestionId":"899","leaf":true,"level":3,"nodeType":"def","questionId":"935","status":"","title":"有序队列","titleSlug":"orderly-queue"},{"formTitle":"[900]RLE 迭代器","frontendQuestionId":"900","leaf":true,"level":2,"nodeType":"def","questionId":"936","status":"","title":"RLE 迭代器","titleSlug":"rle-iterator"},{"formTitle":"[901]股票价格跨度","frontendQuestionId":"901","leaf":true,"level":2,"nodeType":"def","questionId":"937","status":"","title":"股票价格跨度","titleSlug":"online-stock-span"},{"formTitle":"[902]最大为 N 的数字组合","frontendQuestionId":"902","leaf":true,"level":3,"nodeType":"def","questionId":"938","status":"","title":"最大为 N 的数字组合","titleSlug":"numbers-at-most-n-given-digit-set"},{"formTitle":"[903]DI 序列的有效排列","frontendQuestionId":"903","leaf":true,"level":3,"nodeType":"def","questionId":"939","status":"","title":"DI 序列的有效排列","titleSlug":"valid-permutations-for-di-sequence"},{"formTitle":"[904]水果成篮","frontendQuestionId":"904","leaf":true,"level":2,"nodeType":"def","questionId":"940","status":"","title":"水果成篮","titleSlug":"fruit-into-baskets"},{"formTitle":"[905]按奇偶排序数组","frontendQuestionId":"905","leaf":true,"level":1,"nodeType":"def","questionId":"941","status":"","title":"按奇偶排序数组","titleSlug":"sort-array-by-parity"},{"formTitle":"[906]超级回文数","frontendQuestionId":"906","leaf":true,"level":3,"nodeType":"def","questionId":"942","status":"","title":"超级回文数","titleSlug":"super-palindromes"},{"formTitle":"[907]子数组的最小值之和","frontendQuestionId":"907","leaf":true,"level":2,"nodeType":"def","questionId":"943","status":"","title":"子数组的最小值之和","titleSlug":"sum-of-subarray-minimums"},{"formTitle":"[908]最小差值 I","frontendQuestionId":"908","leaf":true,"level":1,"nodeType":"def","questionId":"944","status":"","title":"最小差值 I","titleSlug":"smallest-range-i"},{"formTitle":"[909]蛇梯棋","frontendQuestionId":"909","leaf":true,"level":2,"nodeType":"def","questionId":"945","status":"","title":"蛇梯棋","titleSlug":"snakes-and-ladders"},{"formTitle":"[910]最小差值 II","frontendQuestionId":"910","leaf":true,"level":2,"nodeType":"def","questionId":"946","status":"","title":"最小差值 II","titleSlug":"smallest-range-ii"},{"formTitle":"[911]在线选举","frontendQuestionId":"911","leaf":true,"level":2,"nodeType":"def","questionId":"947","status":"","title":"在线选举","titleSlug":"online-election"},{"formTitle":"[912]排序数组","frontendQuestionId":"912","leaf":true,"level":2,"nodeType":"def","questionId":"948","status":"","title":"排序数组","titleSlug":"sort-an-array"},{"formTitle":"[913]猫和老鼠","frontendQuestionId":"913","leaf":true,"level":3,"nodeType":"def","questionId":"949","status":"","title":"猫和老鼠","titleSlug":"cat-and-mouse"},{"formTitle":"[914]卡牌分组","frontendQuestionId":"914","leaf":true,"level":1,"nodeType":"def","questionId":"950","status":"","title":"卡牌分组","titleSlug":"x-of-a-kind-in-a-deck-of-cards"},{"formTitle":"[915]分割数组","frontendQuestionId":"915","leaf":true,"level":2,"nodeType":"def","questionId":"951","status":"","title":"分割数组","titleSlug":"partition-array-into-disjoint-intervals"},{"formTitle":"[916]单词子集","frontendQuestionId":"916","leaf":true,"level":2,"nodeType":"def","questionId":"952","status":"","title":"单词子集","titleSlug":"word-subsets"},{"formTitle":"[917]仅仅反转字母","frontendQuestionId":"917","leaf":true,"level":1,"nodeType":"def","questionId":"953","status":"","title":"仅仅反转字母","titleSlug":"reverse-only-letters"},{"formTitle":"[918]环形子数组的最大和","frontendQuestionId":"918","leaf":true,"level":2,"nodeType":"def","questionId":"954","status":"","title":"环形子数组的最大和","titleSlug":"maximum-sum-circular-subarray"},{"formTitle":"[919]完全二叉树插入器","frontendQuestionId":"919","leaf":true,"level":2,"nodeType":"def","questionId":"955","status":"","title":"完全二叉树插入器","titleSlug":"complete-binary-tree-inserter"},{"formTitle":"[920]播放列表的数量","frontendQuestionId":"920","leaf":true,"level":3,"nodeType":"def","questionId":"956","status":"","title":"播放列表的数量","titleSlug":"number-of-music-playlists"},{"formTitle":"[921]使括号有效的最少添加","frontendQuestionId":"921","leaf":true,"level":2,"nodeType":"def","questionId":"957","status":"","title":"使括号有效的最少添加","titleSlug":"minimum-add-to-make-parentheses-valid"},{"formTitle":"[922]按奇偶排序数组 II","frontendQuestionId":"922","leaf":true,"level":1,"nodeType":"def","questionId":"958","status":"","title":"按奇偶排序数组 II","titleSlug":"sort-array-by-parity-ii"},{"formTitle":"[923]三数之和的多种可能","frontendQuestionId":"923","leaf":true,"level":2,"nodeType":"def","questionId":"959","status":"","title":"三数之和的多种可能","titleSlug":"3sum-with-multiplicity"},{"formTitle":"[924]尽量减少恶意软件的传播","frontendQuestionId":"924","leaf":true,"level":3,"nodeType":"def","questionId":"960","status":"","title":"尽量减少恶意软件的传播","titleSlug":"minimize-malware-spread"},{"formTitle":"[925]长按键入","frontendQuestionId":"925","leaf":true,"level":1,"nodeType":"def","questionId":"961","status":"","title":"长按键入","titleSlug":"long-pressed-name"},{"formTitle":"[926]将字符串翻转到单调递增","frontendQuestionId":"926","leaf":true,"level":2,"nodeType":"def","questionId":"962","status":"","title":"将字符串翻转到单调递增","titleSlug":"flip-string-to-monotone-increasing"},{"formTitle":"[927]三等分","frontendQuestionId":"927","leaf":true,"level":3,"nodeType":"def","questionId":"963","status":"","title":"三等分","titleSlug":"three-equal-parts"},{"formTitle":"[928]尽量减少恶意软件的传播 II","frontendQuestionId":"928","leaf":true,"level":3,"nodeType":"def","questionId":"964","status":"","title":"尽量减少恶意软件的传播 II","titleSlug":"minimize-malware-spread-ii"},{"formTitle":"[929]独特的电子邮件地址","frontendQuestionId":"929","leaf":true,"level":1,"nodeType":"def","questionId":"965","status":"","title":"独特的电子邮件地址","titleSlug":"unique-email-addresses"},{"formTitle":"[930]和相同的二元子数组","frontendQuestionId":"930","leaf":true,"level":2,"nodeType":"def","questionId":"966","status":"","title":"和相同的二元子数组","titleSlug":"binary-subarrays-with-sum"},{"formTitle":"[931]下降路径最小和","frontendQuestionId":"931","leaf":true,"level":2,"nodeType":"def","questionId":"967","status":"","title":"下降路径最小和","titleSlug":"minimum-falling-path-sum"},{"formTitle":"[932]漂亮数组","frontendQuestionId":"932","leaf":true,"level":2,"nodeType":"def","questionId":"968","status":"","title":"漂亮数组","titleSlug":"beautiful-array"},{"formTitle":"[933]最近的请求次数","frontendQuestionId":"933","leaf":true,"level":1,"nodeType":"def","questionId":"969","status":"","title":"最近的请求次数","titleSlug":"number-of-recent-calls"},{"formTitle":"[934]最短的桥","frontendQuestionId":"934","leaf":true,"level":2,"nodeType":"def","questionId":"971","status":"","title":"最短的桥","titleSlug":"shortest-bridge"},{"formTitle":"[935]骑士拨号器","frontendQuestionId":"935","leaf":true,"level":2,"nodeType":"def","questionId":"972","status":"","title":"骑士拨号器","titleSlug":"knight-dialer"},{"formTitle":"[936]戳印序列","frontendQuestionId":"936","leaf":true,"level":3,"nodeType":"def","questionId":"973","status":"","title":"戳印序列","titleSlug":"stamping-the-sequence"},{"formTitle":"[937]重新排列日志文件","frontendQuestionId":"937","leaf":true,"level":1,"nodeType":"def","questionId":"974","status":"","title":"重新排列日志文件","titleSlug":"reorder-data-in-log-files"},{"formTitle":"[938]二叉搜索树的范围和","frontendQuestionId":"938","leaf":true,"level":1,"nodeType":"def","questionId":"975","status":"","title":"二叉搜索树的范围和","titleSlug":"range-sum-of-bst"},{"formTitle":"[939]最小面积矩形","frontendQuestionId":"939","leaf":true,"level":2,"nodeType":"def","questionId":"976","status":"","title":"最小面积矩形","titleSlug":"minimum-area-rectangle"},{"formTitle":"[940]不同的子序列 II","frontendQuestionId":"940","leaf":true,"level":3,"nodeType":"def","questionId":"977","status":"","title":"不同的子序列 II","titleSlug":"distinct-subsequences-ii"},{"formTitle":"[941]有效的山脉数组","frontendQuestionId":"941","leaf":true,"level":1,"nodeType":"def","questionId":"978","status":"","title":"有效的山脉数组","titleSlug":"valid-mountain-array"},{"formTitle":"[942]增减字符串匹配","frontendQuestionId":"942","leaf":true,"level":1,"nodeType":"def","questionId":"979","status":"","title":"增减字符串匹配","titleSlug":"di-string-match"},{"formTitle":"[943]最短超级串","frontendQuestionId":"943","leaf":true,"level":3,"nodeType":"def","questionId":"980","status":"","title":"最短超级串","titleSlug":"find-the-shortest-superstring"},{"formTitle":"[944]删列造序","frontendQuestionId":"944","leaf":true,"level":1,"nodeType":"def","questionId":"981","status":"","title":"删列造序","titleSlug":"delete-columns-to-make-sorted"},{"formTitle":"[945]使数组唯一的最小增量","frontendQuestionId":"945","leaf":true,"level":2,"nodeType":"def","questionId":"982","status":"","title":"使数组唯一的最小增量","titleSlug":"minimum-increment-to-make-array-unique"},{"formTitle":"[946]验证栈序列","frontendQuestionId":"946","leaf":true,"level":2,"nodeType":"def","questionId":"983","status":"","title":"验证栈序列","titleSlug":"validate-stack-sequences"},{"formTitle":"[947]移除最多的同行或同列石头","frontendQuestionId":"947","leaf":true,"level":2,"nodeType":"def","questionId":"984","status":"","title":"移除最多的同行或同列石头","titleSlug":"most-stones-removed-with-same-row-or-column"},{"formTitle":"[948]令牌放置","frontendQuestionId":"948","leaf":true,"level":2,"nodeType":"def","questionId":"985","status":"","title":"令牌放置","titleSlug":"bag-of-tokens"},{"formTitle":"[949]给定数字能组成的最大时间","frontendQuestionId":"949","leaf":true,"level":1,"nodeType":"def","questionId":"986","status":"","title":"给定数字能组成的最大时间","titleSlug":"largest-time-for-given-digits"},{"formTitle":"[950]按递增顺序显示卡牌","frontendQuestionId":"950","leaf":true,"level":2,"nodeType":"def","questionId":"987","status":"","title":"按递增顺序显示卡牌","titleSlug":"reveal-cards-in-increasing-order"},{"formTitle":"[951]翻转等价二叉树","frontendQuestionId":"951","leaf":true,"level":2,"nodeType":"def","questionId":"988","status":"","title":"翻转等价二叉树","titleSlug":"flip-equivalent-binary-trees"},{"formTitle":"[952]按公因数计算最大组件大小","frontendQuestionId":"952","leaf":true,"level":3,"nodeType":"def","questionId":"989","status":"","title":"按公因数计算最大组件大小","titleSlug":"largest-component-size-by-common-factor"},{"formTitle":"[953]验证外星语词典","frontendQuestionId":"953","leaf":true,"level":1,"nodeType":"def","questionId":"990","status":"","title":"验证外星语词典","titleSlug":"verifying-an-alien-dictionary"},{"formTitle":"[954]二倍数对数组","frontendQuestionId":"954","leaf":true,"level":2,"nodeType":"def","questionId":"991","status":"","title":"二倍数对数组","titleSlug":"array-of-doubled-pairs"},{"formTitle":"[955]删列造序 II","frontendQuestionId":"955","leaf":true,"level":2,"nodeType":"def","questionId":"992","status":"","title":"删列造序 II","titleSlug":"delete-columns-to-make-sorted-ii"},{"formTitle":"[956]最高的广告牌","frontendQuestionId":"956","leaf":true,"level":3,"nodeType":"def","questionId":"993","status":"","title":"最高的广告牌","titleSlug":"tallest-billboard"},{"formTitle":"[957]N 天后的牢房","frontendQuestionId":"957","leaf":true,"level":2,"nodeType":"def","questionId":"994","status":"","title":"N 天后的牢房","titleSlug":"prison-cells-after-n-days"},{"formTitle":"[958]二叉树的完全性检验","frontendQuestionId":"958","leaf":true,"level":2,"nodeType":"def","questionId":"998","status":"","title":"二叉树的完全性检验","titleSlug":"check-completeness-of-a-binary-tree"},{"formTitle":"[959]由斜杠划分区域","frontendQuestionId":"959","leaf":true,"level":2,"nodeType":"def","questionId":"999","status":"","title":"由斜杠划分区域","titleSlug":"regions-cut-by-slashes"},{"formTitle":"[960]删列造序 III","frontendQuestionId":"960","leaf":true,"level":3,"nodeType":"def","questionId":"1000","status":"","title":"删列造序 III","titleSlug":"delete-columns-to-make-sorted-iii"},{"formTitle":"[961]重复 N 次的元素","frontendQuestionId":"961","leaf":true,"level":1,"nodeType":"def","questionId":"1001","status":"","title":"重复 N 次的元素","titleSlug":"n-repeated-element-in-size-2n-array"},{"formTitle":"[962]最大宽度坡","frontendQuestionId":"962","leaf":true,"level":2,"nodeType":"def","questionId":"1002","status":"","title":"最大宽度坡","titleSlug":"maximum-width-ramp"},{"formTitle":"[963]最小面积矩形 II","frontendQuestionId":"963","leaf":true,"level":2,"nodeType":"def","questionId":"1003","status":"","title":"最小面积矩形 II","titleSlug":"minimum-area-rectangle-ii"},{"formTitle":"[964]表示数字的最少运算符","frontendQuestionId":"964","leaf":true,"level":3,"nodeType":"def","questionId":"1004","status":"","title":"表示数字的最少运算符","titleSlug":"least-operators-to-express-number"},{"formTitle":"[965]单值二叉树","frontendQuestionId":"965","leaf":true,"level":1,"nodeType":"def","questionId":"1005","status":"","title":"单值二叉树","titleSlug":"univalued-binary-tree"},{"formTitle":"[966]元音拼写检查器","frontendQuestionId":"966","leaf":true,"level":2,"nodeType":"def","questionId":"1006","status":"","title":"元音拼写检查器","titleSlug":"vowel-spellchecker"},{"formTitle":"[967]连续差相同的数字","frontendQuestionId":"967","leaf":true,"level":2,"nodeType":"def","questionId":"1007","status":"","title":"连续差相同的数字","titleSlug":"numbers-with-same-consecutive-differences"},{"formTitle":"[968]监控二叉树","frontendQuestionId":"968","leaf":true,"level":3,"nodeType":"def","questionId":"1008","status":"","title":"监控二叉树","titleSlug":"binary-tree-cameras"},{"formTitle":"[969]煎饼排序","frontendQuestionId":"969","leaf":true,"level":2,"nodeType":"def","questionId":"1009","status":"","title":"煎饼排序","titleSlug":"pancake-sorting"},{"formTitle":"[970]强整数","frontendQuestionId":"970","leaf":true,"level":1,"nodeType":"def","questionId":"1010","status":"","title":"强整数","titleSlug":"powerful-integers"},{"formTitle":"[971]翻转二叉树以匹配先序遍历","frontendQuestionId":"971","leaf":true,"level":2,"nodeType":"def","questionId":"1011","status":"","title":"翻转二叉树以匹配先序遍历","titleSlug":"flip-binary-tree-to-match-preorder-traversal"},{"formTitle":"[972]相等的有理数","frontendQuestionId":"972","leaf":true,"level":3,"nodeType":"def","questionId":"1012","status":"","title":"相等的有理数","titleSlug":"equal-rational-numbers"},{"formTitle":"[973]最接近原点的 K 个点","frontendQuestionId":"973","leaf":true,"level":2,"nodeType":"def","questionId":"1014","status":"","title":"最接近原点的 K 个点","titleSlug":"k-closest-points-to-origin"},{"formTitle":"[974]和可被 K 整除的子数组","frontendQuestionId":"974","leaf":true,"level":2,"nodeType":"def","questionId":"1016","status":"","title":"和可被 K 整除的子数组","titleSlug":"subarray-sums-divisible-by-k"},{"formTitle":"[975]奇偶跳","frontendQuestionId":"975","leaf":true,"level":3,"nodeType":"def","questionId":"1017","status":"","title":"奇偶跳","titleSlug":"odd-even-jump"},{"formTitle":"[976]三角形的最大周长","frontendQuestionId":"976","leaf":true,"level":1,"nodeType":"def","questionId":"1018","status":"","title":"三角形的最大周长","titleSlug":"largest-perimeter-triangle"},{"formTitle":"[977]有序数组的平方","frontendQuestionId":"977","leaf":true,"level":1,"nodeType":"def","questionId":"1019","status":"","title":"有序数组的平方","titleSlug":"squares-of-a-sorted-array"},{"formTitle":"[978]最长湍流子数组","frontendQuestionId":"978","leaf":true,"level":2,"nodeType":"def","questionId":"1020","status":"","title":"最长湍流子数组","titleSlug":"longest-turbulent-subarray"},{"formTitle":"[979]在二叉树中分配硬币","frontendQuestionId":"979","leaf":true,"level":2,"nodeType":"def","questionId":"1021","status":"","title":"在二叉树中分配硬币","titleSlug":"distribute-coins-in-binary-tree"},{"formTitle":"[980]不同路径 III","frontendQuestionId":"980","leaf":true,"level":3,"nodeType":"def","questionId":"1022","status":"","title":"不同路径 III","titleSlug":"unique-paths-iii"},{"formTitle":"[981]基于时间的键值存储","frontendQuestionId":"981","leaf":true,"level":2,"nodeType":"def","questionId":"1023","status":"","title":"基于时间的键值存储","titleSlug":"time-based-key-value-store"},{"formTitle":"[982]按位与为零的三元组","frontendQuestionId":"982","leaf":true,"level":3,"nodeType":"def","questionId":"1024","status":"","title":"按位与为零的三元组","titleSlug":"triples-with-bitwise-and-equal-to-zero"},{"formTitle":"[983]最低票价","frontendQuestionId":"983","leaf":true,"level":2,"nodeType":"def","questionId":"1025","status":"","title":"最低票价","titleSlug":"minimum-cost-for-tickets"},{"formTitle":"[984]不含 AAA 或 BBB 的字符串","frontendQuestionId":"984","leaf":true,"level":2,"nodeType":"def","questionId":"1026","status":"","title":"不含 AAA 或 BBB 的字符串","titleSlug":"string-without-aaa-or-bbb"},{"formTitle":"[985]查询后的偶数和","frontendQuestionId":"985","leaf":true,"level":1,"nodeType":"def","questionId":"1027","status":"","title":"查询后的偶数和","titleSlug":"sum-of-even-numbers-after-queries"},{"formTitle":"[986]区间列表的交集","frontendQuestionId":"986","leaf":true,"level":2,"nodeType":"def","questionId":"1028","status":"","title":"区间列表的交集","titleSlug":"interval-list-intersections"},{"formTitle":"[987]二叉树的垂序遍历","frontendQuestionId":"987","leaf":true,"level":2,"nodeType":"def","questionId":"1029","status":"","title":"二叉树的垂序遍历","titleSlug":"vertical-order-traversal-of-a-binary-tree"},{"formTitle":"[988]从叶结点开始的最小字符串","frontendQuestionId":"988","leaf":true,"level":2,"nodeType":"def","questionId":"1030","status":"","title":"从叶结点开始的最小字符串","titleSlug":"smallest-string-starting-from-leaf"},{"formTitle":"[989]数组形式的整数加法","frontendQuestionId":"989","leaf":true,"level":1,"nodeType":"def","questionId":"1031","status":"","title":"数组形式的整数加法","titleSlug":"add-to-array-form-of-integer"},{"formTitle":"[990]等式方程的可满足性","frontendQuestionId":"990","leaf":true,"level":2,"nodeType":"def","questionId":"1032","status":"","title":"等式方程的可满足性","titleSlug":"satisfiability-of-equality-equations"},{"formTitle":"[991]坏了的计算器","frontendQuestionId":"991","leaf":true,"level":2,"nodeType":"def","questionId":"1033","status":"","title":"坏了的计算器","titleSlug":"broken-calculator"},{"formTitle":"[992]K 个不同整数的子数组","frontendQuestionId":"992","leaf":true,"level":3,"nodeType":"def","questionId":"1034","status":"","title":"K 个不同整数的子数组","titleSlug":"subarrays-with-k-different-integers"},{"formTitle":"[993]二叉树的堂兄弟节点","frontendQuestionId":"993","leaf":true,"level":1,"nodeType":"def","questionId":"1035","status":"","title":"二叉树的堂兄弟节点","titleSlug":"cousins-in-binary-tree"},{"formTitle":"[994]腐烂的橘子","frontendQuestionId":"994","leaf":true,"level":1,"nodeType":"def","questionId":"1036","status":"","title":"腐烂的橘子","titleSlug":"rotting-oranges"},{"formTitle":"[995]K 连续位的最小翻转次数","frontendQuestionId":"995","leaf":true,"level":3,"nodeType":"def","questionId":"1037","status":"","title":"K 连续位的最小翻转次数","titleSlug":"minimum-number-of-k-consecutive-bit-flips"},{"formTitle":"[996]正方形数组的数目","frontendQuestionId":"996","leaf":true,"level":3,"nodeType":"def","questionId":"1038","status":"","title":"正方形数组的数目","titleSlug":"number-of-squareful-arrays"},{"formTitle":"[997]找到小镇的法官","frontendQuestionId":"997","leaf":true,"level":1,"nodeType":"def","questionId":"1039","status":"","title":"找到小镇的法官","titleSlug":"find-the-town-judge"},{"formTitle":"[998]最大二叉树 II","frontendQuestionId":"998","leaf":true,"level":2,"nodeType":"def","questionId":"1040","status":"","title":"最大二叉树 II","titleSlug":"maximum-binary-tree-ii"},{"formTitle":"[999]车的可用捕获量","frontendQuestionId":"999","leaf":true,"level":1,"nodeType":"def","questionId":"1041","status":"","title":"车的可用捕获量","titleSlug":"available-captures-for-rook"},{"formTitle":"[1000]合并石头的最低成本","frontendQuestionId":"1000","leaf":true,"level":3,"nodeType":"def","questionId":"1042","status":"","title":"合并石头的最低成本","titleSlug":"minimum-cost-to-merge-stones"},{"formTitle":"[1001]网格照明","frontendQuestionId":"1001","leaf":true,"level":3,"nodeType":"def","questionId":"1043","status":"","title":"网格照明","titleSlug":"grid-illumination"},{"formTitle":"[1002]查找常用字符","frontendQuestionId":"1002","leaf":true,"level":1,"nodeType":"def","questionId":"1044","status":"","title":"查找常用字符","titleSlug":"find-common-characters"},{"formTitle":"[1003]检查替换后的词是否有效","frontendQuestionId":"1003","leaf":true,"level":2,"nodeType":"def","questionId":"1045","status":"","title":"检查替换后的词是否有效","titleSlug":"check-if-word-is-valid-after-substitutions"},{"formTitle":"[1004]最大连续1的个数 III","frontendQuestionId":"1004","leaf":true,"level":2,"nodeType":"def","questionId":"1046","status":"","title":"最大连续1的个数 III","titleSlug":"max-consecutive-ones-iii"},{"formTitle":"[1005]K 次取反后最大化的数组和","frontendQuestionId":"1005","leaf":true,"level":1,"nodeType":"def","questionId":"1047","status":"","title":"K 次取反后最大化的数组和","titleSlug":"maximize-sum-of-array-after-k-negations"},{"formTitle":"[1006]笨阶乘","frontendQuestionId":"1006","leaf":true,"level":2,"nodeType":"def","questionId":"1048","status":"","title":"笨阶乘","titleSlug":"clumsy-factorial"},{"formTitle":"[1007]行相等的最少多米诺旋转","frontendQuestionId":"1007","leaf":true,"level":2,"nodeType":"def","questionId":"1049","status":"","title":"行相等的最少多米诺旋转","titleSlug":"minimum-domino-rotations-for-equal-row"},{"formTitle":"[1008]先序遍历构造二叉树","frontendQuestionId":"1008","leaf":true,"level":2,"nodeType":"def","questionId":"1050","status":"","title":"先序遍历构造二叉树","titleSlug":"construct-binary-search-tree-from-preorder-traversal"},{"formTitle":"[1009]十进制整数的反码","frontendQuestionId":"1009","leaf":true,"level":1,"nodeType":"def","questionId":"1054","status":"","title":"十进制整数的反码","titleSlug":"complement-of-base-10-integer"},{"formTitle":"[1010]总持续时间可被 60 整除的歌曲","frontendQuestionId":"1010","leaf":true,"level":1,"nodeType":"def","questionId":"1055","status":"","title":"总持续时间可被 60 整除的歌曲","titleSlug":"pairs-of-songs-with-total-durations-divisible-by-60"},{"formTitle":"[1011]在 D 天内送达包裹的能力","frontendQuestionId":"1011","leaf":true,"level":2,"nodeType":"def","questionId":"1056","status":"","title":"在 D 天内送达包裹的能力","titleSlug":"capacity-to-ship-packages-within-d-days"},{"formTitle":"[1012]至少有 1 位重复的数字","frontendQuestionId":"1012","leaf":true,"level":3,"nodeType":"def","questionId":"1057","status":"","title":"至少有 1 位重复的数字","titleSlug":"numbers-with-repeated-digits"},{"formTitle":"[1013]将数组分成和相等的三个部分","frontendQuestionId":"1013","leaf":true,"level":1,"nodeType":"def","questionId":"1062","status":"","title":"将数组分成和相等的三个部分","titleSlug":"partition-array-into-three-parts-with-equal-sum"},{"formTitle":"[1014]最佳观光组合","frontendQuestionId":"1014","leaf":true,"level":2,"nodeType":"def","questionId":"1063","status":"","title":"最佳观光组合","titleSlug":"best-sightseeing-pair"},{"formTitle":"[1015]可被 K 整除的最小整数","frontendQuestionId":"1015","leaf":true,"level":2,"nodeType":"def","questionId":"1064","status":"","title":"可被 K 整除的最小整数","titleSlug":"smallest-integer-divisible-by-k"},{"formTitle":"[1016]子串能表示从 1 到 N 数字的二进制串","frontendQuestionId":"1016","leaf":true,"level":2,"nodeType":"def","questionId":"1065","status":"","title":"子串能表示从 1 到 N 数字的二进制串","titleSlug":"binary-string-with-substrings-representing-1-to-n"},{"formTitle":"[1017]负二进制转换","frontendQuestionId":"1017","leaf":true,"level":2,"nodeType":"def","questionId":"1070","status":"","title":"负二进制转换","titleSlug":"convert-to-base-2"},{"formTitle":"[1018]可被 5 整除的二进制前缀","frontendQuestionId":"1018","leaf":true,"level":1,"nodeType":"def","questionId":"1071","status":"","title":"可被 5 整除的二进制前缀","titleSlug":"binary-prefix-divisible-by-5"},{"formTitle":"[1019]链表中的下一个更大节点","frontendQuestionId":"1019","leaf":true,"level":2,"nodeType":"def","questionId":"1072","status":"","title":"链表中的下一个更大节点","titleSlug":"next-greater-node-in-linked-list"},{"formTitle":"[1020]飞地的数量","frontendQuestionId":"1020","leaf":true,"level":2,"nodeType":"def","questionId":"1073","status":"","title":"飞地的数量","titleSlug":"number-of-enclaves"},{"formTitle":"[1021]删除最外层的括号","frontendQuestionId":"1021","leaf":true,"level":1,"nodeType":"def","questionId":"1078","status":"","title":"删除最外层的括号","titleSlug":"remove-outermost-parentheses"},{"formTitle":"[1022]从根到叶的二进制数之和","frontendQuestionId":"1022","leaf":true,"level":1,"nodeType":"def","questionId":"1079","status":"","title":"从根到叶的二进制数之和","titleSlug":"sum-of-root-to-leaf-binary-numbers"},{"formTitle":"[1023]驼峰式匹配","frontendQuestionId":"1023","leaf":true,"level":2,"nodeType":"def","questionId":"1080","status":"","title":"驼峰式匹配","titleSlug":"camelcase-matching"},{"formTitle":"[1024]视频拼接","frontendQuestionId":"1024","leaf":true,"level":2,"nodeType":"def","questionId":"1081","status":"","title":"视频拼接","titleSlug":"video-stitching"},{"formTitle":"[1025]除数博弈","frontendQuestionId":"1025","leaf":true,"level":1,"nodeType":"def","questionId":"1086","status":"","title":"除数博弈","titleSlug":"divisor-game"},{"formTitle":"[1026]节点与其祖先之间的最大差值","frontendQuestionId":"1026","leaf":true,"level":2,"nodeType":"def","questionId":"1092","status":"","title":"节点与其祖先之间的最大差值","titleSlug":"maximum-difference-between-node-and-ancestor"},{"formTitle":"[1027]最长等差数列","frontendQuestionId":"1027","leaf":true,"level":2,"nodeType":"def","questionId":"1087","status":"","title":"最长等差数列","titleSlug":"longest-arithmetic-sequence"},{"formTitle":"[1028]从先序遍历还原二叉树","frontendQuestionId":"1028","leaf":true,"level":3,"nodeType":"def","questionId":"1093","status":"","title":"从先序遍历还原二叉树","titleSlug":"recover-a-tree-from-preorder-traversal"},{"formTitle":"[1029]两地调度","frontendQuestionId":"1029","leaf":true,"level":1,"nodeType":"def","questionId":"1095","status":"","title":"两地调度","titleSlug":"two-city-scheduling"},{"formTitle":"[1030]距离顺序排列矩阵单元格","frontendQuestionId":"1030","leaf":true,"level":1,"nodeType":"def","questionId":"1094","status":"","title":"距离顺序排列矩阵单元格","titleSlug":"matrix-cells-in-distance-order"},{"formTitle":"[1031]两个非重叠子数组的最大和","frontendQuestionId":"1031","leaf":true,"level":2,"nodeType":"def","questionId":"1096","status":"","title":"两个非重叠子数组的最大和","titleSlug":"maximum-sum-of-two-non-overlapping-subarrays"},{"formTitle":"[1032]字符流","frontendQuestionId":"1032","leaf":true,"level":3,"nodeType":"def","questionId":"1097","status":"","title":"字符流","titleSlug":"stream-of-characters"},{"formTitle":"[1033]移动石子直到连续","frontendQuestionId":"1033","leaf":true,"level":1,"nodeType":"def","questionId":"1103","status":"","title":"移动石子直到连续","titleSlug":"moving-stones-until-consecutive"},{"formTitle":"[1034]边框着色","frontendQuestionId":"1034","leaf":true,"level":2,"nodeType":"def","questionId":"1104","status":"","title":"边框着色","titleSlug":"coloring-a-border"},{"formTitle":"[1035]不相交的线","frontendQuestionId":"1035","leaf":true,"level":2,"nodeType":"def","questionId":"1105","status":"","title":"不相交的线","titleSlug":"uncrossed-lines"},{"formTitle":"[1036]逃离大迷宫","frontendQuestionId":"1036","leaf":true,"level":3,"nodeType":"def","questionId":"1106","status":"","title":"逃离大迷宫","titleSlug":"escape-a-large-maze"},{"formTitle":"[1037]有效的回旋镖","frontendQuestionId":"1037","leaf":true,"level":1,"nodeType":"def","questionId":"1115","status":"","title":"有效的回旋镖","titleSlug":"valid-boomerang"},{"formTitle":"[1038]从二叉搜索树到更大和树","frontendQuestionId":"1038","leaf":true,"level":2,"nodeType":"def","questionId":"1114","status":"","title":"从二叉搜索树到更大和树","titleSlug":"binary-search-tree-to-greater-sum-tree"},{"formTitle":"[1039]多边形三角剖分的最低得分","frontendQuestionId":"1039","leaf":true,"level":2,"nodeType":"def","questionId":"1111","status":"","title":"多边形三角剖分的最低得分","titleSlug":"minimum-score-triangulation-of-polygon"},{"formTitle":"[1040]移动石子直到连续 II","frontendQuestionId":"1040","leaf":true,"level":2,"nodeType":"def","questionId":"1113","status":"","title":"移动石子直到连续 II","titleSlug":"moving-stones-until-consecutive-ii"},{"formTitle":"[1041]困于环中的机器人","frontendQuestionId":"1041","leaf":true,"level":2,"nodeType":"def","questionId":"1119","status":"","title":"困于环中的机器人","titleSlug":"robot-bounded-in-circle"},{"formTitle":"[1042]不邻接植花","frontendQuestionId":"1042","leaf":true,"level":1,"nodeType":"def","questionId":"1120","status":"","title":"不邻接植花","titleSlug":"flower-planting-with-no-adjacent"},{"formTitle":"[1043]分隔数组以得到最大和","frontendQuestionId":"1043","leaf":true,"level":2,"nodeType":"def","questionId":"1121","status":"","title":"分隔数组以得到最大和","titleSlug":"partition-array-for-maximum-sum"},{"formTitle":"[1044]最长重复子串","frontendQuestionId":"1044","leaf":true,"level":3,"nodeType":"def","questionId":"1122","status":"","title":"最长重复子串","titleSlug":"longest-duplicate-substring"},{"formTitle":"[1045]买下所有产品的客户","frontendQuestionId":"1045","leaf":true,"level":2,"nodeType":"def","questionId":"1135","status":"lock","title":"买下所有产品的客户","titleSlug":"customers-who-bought-all-products"},{"formTitle":"[1046]最后一块石头的重量","frontendQuestionId":"1046","leaf":true,"level":1,"nodeType":"def","questionId":"1127","status":"","title":"最后一块石头的重量","titleSlug":"last-stone-weight"},{"formTitle":"[1047]删除字符串中的所有相邻重复项","frontendQuestionId":"1047","leaf":true,"level":1,"nodeType":"def","questionId":"1128","status":"","title":"删除字符串中的所有相邻重复项","titleSlug":"remove-all-adjacent-duplicates-in-string"},{"formTitle":"[1048]最长字符串链","frontendQuestionId":"1048","leaf":true,"level":2,"nodeType":"def","questionId":"1129","status":"","title":"最长字符串链","titleSlug":"longest-string-chain"},{"formTitle":"[1049]最后一块石头的重量 II","frontendQuestionId":"1049","leaf":true,"level":2,"nodeType":"def","questionId":"1130","status":"","title":"最后一块石头的重量 II","titleSlug":"last-stone-weight-ii"},{"formTitle":"[1050]合作过至少三次的演员和导演","frontendQuestionId":"1050","leaf":true,"level":1,"nodeType":"def","questionId":"1136","status":"lock","title":"合作过至少三次的演员和导演","titleSlug":"actors-and-directors-who-cooperated-at-least-three-times"},{"formTitle":"[1051]高度检查器","frontendQuestionId":"1051","leaf":true,"level":1,"nodeType":"def","questionId":"1137","status":"","title":"高度检查器","titleSlug":"height-checker"},{"formTitle":"[1052]爱生气的书店老板","frontendQuestionId":"1052","leaf":true,"level":2,"nodeType":"def","questionId":"1138","status":"","title":"爱生气的书店老板","titleSlug":"grumpy-bookstore-owner"},{"formTitle":"[1053]交换一次的先前排列","frontendQuestionId":"1053","leaf":true,"level":2,"nodeType":"def","questionId":"1139","status":"","title":"交换一次的先前排列","titleSlug":"previous-permutation-with-one-swap"},{"formTitle":"[1054]距离相等的条形码","frontendQuestionId":"1054","leaf":true,"level":2,"nodeType":"def","questionId":"1140","status":"","title":"距离相等的条形码","titleSlug":"distant-barcodes"},{"formTitle":"[1055]形成字符串的最短路径","frontendQuestionId":"1055","leaf":true,"level":2,"nodeType":"def","questionId":"1051","status":"lock","title":"形成字符串的最短路径","titleSlug":"shortest-way-to-form-string"},{"formTitle":"[1056]易混淆数","frontendQuestionId":"1056","leaf":true,"level":1,"nodeType":"def","questionId":"1069","status":"lock","title":"易混淆数","titleSlug":"confusing-number"},{"formTitle":"[1057]校园自行车分配","frontendQuestionId":"1057","leaf":true,"level":2,"nodeType":"def","questionId":"1052","status":"lock","title":"校园自行车分配","titleSlug":"campus-bikes"},{"formTitle":"[1058]最小化舍入误差以满足目标","frontendQuestionId":"1058","leaf":true,"level":2,"nodeType":"def","questionId":"1053","status":"lock","title":"最小化舍入误差以满足目标","titleSlug":"minimize-rounding-error-to-meet-target"},{"formTitle":"[1059]从始点到终点的所有路径","frontendQuestionId":"1059","leaf":true,"level":2,"nodeType":"def","questionId":"511","status":"lock","title":"从始点到终点的所有路径","titleSlug":"all-paths-from-source-lead-to-destination"},{"formTitle":"[1060]有序数组中的缺失元素","frontendQuestionId":"1060","leaf":true,"level":2,"nodeType":"def","questionId":"1059","status":"lock","title":"有序数组中的缺失元素","titleSlug":"missing-element-in-sorted-array"},{"formTitle":"[1061]按字典序排列最小的等效字符串","frontendQuestionId":"1061","leaf":true,"level":2,"nodeType":"def","questionId":"1058","status":"lock","title":"按字典序排列最小的等效字符串","titleSlug":"lexicographically-smallest-equivalent-string"},{"formTitle":"[1062]最长重复子串","frontendQuestionId":"1062","leaf":true,"level":2,"nodeType":"def","questionId":"1060","status":"lock","title":"最长重复子串","titleSlug":"longest-repeating-substring"},{"formTitle":"[1063]有效子数组的数目","frontendQuestionId":"1063","leaf":true,"level":3,"nodeType":"def","questionId":"1061","status":"lock","title":"有效子数组的数目","titleSlug":"number-of-valid-subarrays"},{"formTitle":"[1064]不动点","frontendQuestionId":"1064","leaf":true,"level":1,"nodeType":"def","questionId":"1066","status":"lock","title":"不动点","titleSlug":"fixed-point"},{"formTitle":"[1065]字符串的索引对","frontendQuestionId":"1065","leaf":true,"level":1,"nodeType":"def","questionId":"1075","status":"lock","title":"字符串的索引对","titleSlug":"index-pairs-of-a-string"},{"formTitle":"[1066]校园自行车分配 II","frontendQuestionId":"1066","leaf":true,"level":2,"nodeType":"def","questionId":"1067","status":"lock","title":"校园自行车分配 II","titleSlug":"campus-bikes-ii"},{"formTitle":"[1067]范围内的数字计数","frontendQuestionId":"1067","leaf":true,"level":3,"nodeType":"def","questionId":"1068","status":"lock","title":"范围内的数字计数","titleSlug":"digit-count-in-range"},{"formTitle":"[1068]产品销售分析 I","frontendQuestionId":"1068","leaf":true,"level":1,"nodeType":"def","questionId":"1153","status":"lock","title":"产品销售分析 I","titleSlug":"product-sales-analysis-i"},{"formTitle":"[1069]产品销售分析 II","frontendQuestionId":"1069","leaf":true,"level":1,"nodeType":"def","questionId":"1154","status":"lock","title":"产品销售分析 II","titleSlug":"product-sales-analysis-ii"},{"formTitle":"[1070]产品销售分析 III","frontendQuestionId":"1070","leaf":true,"level":2,"nodeType":"def","questionId":"1155","status":"lock","title":"产品销售分析 III","titleSlug":"product-sales-analysis-iii"},{"formTitle":"[1071]字符串的最大公因子","frontendQuestionId":"1071","leaf":true,"level":1,"nodeType":"def","questionId":"1146","status":"","title":"字符串的最大公因子","titleSlug":"greatest-common-divisor-of-strings"},{"formTitle":"[1072]按列翻转得到最大值等行数","frontendQuestionId":"1072","leaf":true,"level":2,"nodeType":"def","questionId":"1147","status":"","title":"按列翻转得到最大值等行数","titleSlug":"flip-columns-for-maximum-number-of-equal-rows"},{"formTitle":"[1073]负二进制数相加","frontendQuestionId":"1073","leaf":true,"level":2,"nodeType":"def","questionId":"1148","status":"","title":"负二进制数相加","titleSlug":"adding-two-negabinary-numbers"},{"formTitle":"[1074]元素和为目标值的子矩阵数量","frontendQuestionId":"1074","leaf":true,"level":3,"nodeType":"def","questionId":"1145","status":"","title":"元素和为目标值的子矩阵数量","titleSlug":"number-of-submatrices-that-sum-to-target"},{"formTitle":"[1075]项目员工 I","frontendQuestionId":"1075","leaf":true,"level":1,"nodeType":"def","questionId":"1161","status":"lock","title":"项目员工 I","titleSlug":"project-employees-i"},{"formTitle":"[1076]项目员工II","frontendQuestionId":"1076","leaf":true,"level":1,"nodeType":"def","questionId":"1162","status":"lock","title":"项目员工II","titleSlug":"project-employees-ii"},{"formTitle":"[1077]项目员工 III","frontendQuestionId":"1077","leaf":true,"level":2,"nodeType":"def","questionId":"1163","status":"lock","title":"项目员工 III","titleSlug":"project-employees-iii"},{"formTitle":"[1078]Bigram 分词","frontendQuestionId":"1078","leaf":true,"level":1,"nodeType":"def","questionId":"1156","status":"","title":"Bigram 分词","titleSlug":"occurrences-after-bigram"},{"formTitle":"[1079]活字印刷","frontendQuestionId":"1079","leaf":true,"level":2,"nodeType":"def","questionId":"1160","status":"","title":"活字印刷","titleSlug":"letter-tile-possibilities"},{"formTitle":"[1080]根到叶路径上的不足节点","frontendQuestionId":"1080","leaf":true,"level":2,"nodeType":"def","questionId":"1157","status":"","title":"根到叶路径上的不足节点","titleSlug":"insufficient-nodes-in-root-to-leaf-paths"},{"formTitle":"[1081]不同字符的最小子序列","frontendQuestionId":"1081","leaf":true,"level":2,"nodeType":"def","questionId":"1159","status":"","title":"不同字符的最小子序列","titleSlug":"smallest-subsequence-of-distinct-characters"},{"formTitle":"[1082]销售分析 I ","frontendQuestionId":"1082","leaf":true,"level":1,"nodeType":"def","questionId":"1172","status":"lock","title":"销售分析 I ","titleSlug":"sales-analysis-i"},{"formTitle":"[1083]销售分析 II","frontendQuestionId":"1083","leaf":true,"level":1,"nodeType":"def","questionId":"1173","status":"lock","title":"销售分析 II","titleSlug":"sales-analysis-ii"},{"formTitle":"[1084]销售分析III","frontendQuestionId":"1084","leaf":true,"level":1,"nodeType":"def","questionId":"1174","status":"lock","title":"销售分析III","titleSlug":"sales-analysis-iii"},{"formTitle":"[1085]最小元素各数位之和","frontendQuestionId":"1085","leaf":true,"level":1,"nodeType":"def","questionId":"1082","status":"lock","title":"最小元素各数位之和","titleSlug":"sum-of-digits-in-the-minimum-number"},{"formTitle":"[1086]前五科的均分","frontendQuestionId":"1086","leaf":true,"level":1,"nodeType":"def","questionId":"1074","status":"lock","title":"前五科的均分","titleSlug":"high-five"},{"formTitle":"[1087]字母切换","frontendQuestionId":"1087","leaf":true,"level":2,"nodeType":"def","questionId":"1076","status":"lock","title":"字母切换","titleSlug":"brace-expansion"},{"formTitle":"[1088]易混淆数 II","frontendQuestionId":"1088","leaf":true,"level":3,"nodeType":"def","questionId":"1077","status":"lock","title":"易混淆数 II","titleSlug":"confusing-number-ii"},{"formTitle":"[1089]复写零","frontendQuestionId":"1089","leaf":true,"level":1,"nodeType":"def","questionId":"1168","status":"","title":"复写零","titleSlug":"duplicate-zeros"},{"formTitle":"[1090]受标签影响的最大值","frontendQuestionId":"1090","leaf":true,"level":2,"nodeType":"def","questionId":"1169","status":"","title":"受标签影响的最大值","titleSlug":"largest-values-from-labels"},{"formTitle":"[1091]二进制矩阵中的最短路径","frontendQuestionId":"1091","leaf":true,"level":2,"nodeType":"def","questionId":"1171","status":"","title":"二进制矩阵中的最短路径","titleSlug":"shortest-path-in-binary-matrix"},{"formTitle":"[1092]最短公共超序列","frontendQuestionId":"1092","leaf":true,"level":3,"nodeType":"def","questionId":"1170","status":"","title":"最短公共超序列","titleSlug":"shortest-common-supersequence"},{"formTitle":"[1093]大样本统计","frontendQuestionId":"1093","leaf":true,"level":2,"nodeType":"def","questionId":"1183","status":"","title":"大样本统计","titleSlug":"statistics-from-a-large-sample"},{"formTitle":"[1094]拼车","frontendQuestionId":"1094","leaf":true,"level":2,"nodeType":"def","questionId":"1184","status":"","title":"拼车","titleSlug":"car-pooling"},{"formTitle":"[1095]山脉数组中查找目标值","frontendQuestionId":"1095","leaf":true,"level":3,"nodeType":"def","questionId":"1185","status":"","title":"山脉数组中查找目标值","titleSlug":"find-in-mountain-array"},{"formTitle":"[1096]花括号展开 II","frontendQuestionId":"1096","leaf":true,"level":3,"nodeType":"def","questionId":"1188","status":"","title":"花括号展开 II","titleSlug":"brace-expansion-ii"},{"formTitle":"[1097]游戏玩法分析 V","frontendQuestionId":"1097","leaf":true,"level":3,"nodeType":"def","questionId":"1193","status":"lock","title":"游戏玩法分析 V","titleSlug":"game-play-analysis-v"},{"formTitle":"[1098]小众书籍","frontendQuestionId":"1098","leaf":true,"level":2,"nodeType":"def","questionId":"1198","status":"lock","title":"小众书籍","titleSlug":"unpopular-books"},{"formTitle":"[1099]小于 K 的两数之和","frontendQuestionId":"1099","leaf":true,"level":1,"nodeType":"def","questionId":"1083","status":"lock","title":"小于 K 的两数之和","titleSlug":"two-sum-less-than-k"},{"formTitle":"[1100]长度为 K 的无重复字符子串","frontendQuestionId":"1100","leaf":true,"level":2,"nodeType":"def","questionId":"1084","status":"lock","title":"长度为 K 的无重复字符子串","titleSlug":"find-k-length-substrings-with-no-repeated-characters"},{"formTitle":"[1101]彼此熟识的最早时间","frontendQuestionId":"1101","leaf":true,"level":2,"nodeType":"def","questionId":"1085","status":"lock","title":"彼此熟识的最早时间","titleSlug":"the-earliest-moment-when-everyone-become-friends"},{"formTitle":"[1102]得分最高的路径","frontendQuestionId":"1102","leaf":true,"level":2,"nodeType":"def","questionId":"1099","status":"lock","title":"得分最高的路径","titleSlug":"path-with-maximum-minimum-value"},{"formTitle":"[1103]分糖果 II","frontendQuestionId":"1103","leaf":true,"level":1,"nodeType":"def","questionId":"1195","status":"","title":"分糖果 II","titleSlug":"distribute-candies-to-people"},{"formTitle":"[1104]二叉树寻路","frontendQuestionId":"1104","leaf":true,"level":2,"nodeType":"def","questionId":"1194","status":"","title":"二叉树寻路","titleSlug":"path-in-zigzag-labelled-binary-tree"},{"formTitle":"[1105]填充书架","frontendQuestionId":"1105","leaf":true,"level":2,"nodeType":"def","questionId":"1196","status":"","title":"填充书架","titleSlug":"filling-bookcase-shelves"},{"formTitle":"[1106]解析布尔表达式","frontendQuestionId":"1106","leaf":true,"level":3,"nodeType":"def","questionId":"1197","status":"","title":"解析布尔表达式","titleSlug":"parsing-a-boolean-expression"},{"formTitle":"[1107]每日新用户统计","frontendQuestionId":"1107","leaf":true,"level":2,"nodeType":"def","questionId":"1204","status":"lock","title":"每日新用户统计","titleSlug":"new-users-daily-count"},{"formTitle":"[1108]IP 地址无效化","frontendQuestionId":"1108","leaf":true,"level":1,"nodeType":"def","questionId":"1205","status":"","title":"IP 地址无效化","titleSlug":"defanging-an-ip-address"},{"formTitle":"[1109]航班预订统计","frontendQuestionId":"1109","leaf":true,"level":2,"nodeType":"def","questionId":"1206","status":"","title":"航班预订统计","titleSlug":"corporate-flight-bookings"},{"formTitle":"[1110]删点成林","frontendQuestionId":"1110","leaf":true,"level":2,"nodeType":"def","questionId":"1207","status":"","title":"删点成林","titleSlug":"delete-nodes-and-return-forest"},{"formTitle":"[1111]有效括号的嵌套深度","frontendQuestionId":"1111","leaf":true,"level":2,"nodeType":"def","questionId":"1208","status":"","title":"有效括号的嵌套深度","titleSlug":"maximum-nesting-depth-of-two-valid-parentheses-strings"},{"formTitle":"[1112]每位学生的最高成绩","frontendQuestionId":"1112","leaf":true,"level":2,"nodeType":"def","questionId":"1214","status":"lock","title":"每位学生的最高成绩","titleSlug":"highest-grade-for-each-student"},{"formTitle":"[1113]Reported Posts","frontendQuestionId":"1113","leaf":true,"level":1,"nodeType":"def","questionId":"1215","status":"lock","title":"Reported Posts","titleSlug":"reported-posts"},{"formTitle":"[1114]按序打印","frontendQuestionId":"1114","leaf":true,"level":1,"nodeType":"def","questionId":"1203","status":"","title":"按序打印","titleSlug":"print-in-order"},{"formTitle":"[1115]交替打印FooBar","frontendQuestionId":"1115","leaf":true,"level":2,"nodeType":"def","questionId":"1187","status":"","title":"交替打印FooBar","titleSlug":"print-foobar-alternately"},{"formTitle":"[1116]打印零与奇偶数","frontendQuestionId":"1116","leaf":true,"level":2,"nodeType":"def","questionId":"1216","status":"","title":"打印零与奇偶数","titleSlug":"print-zero-even-odd"},{"formTitle":"[1117]H2O 生成","frontendQuestionId":"1117","leaf":true,"level":2,"nodeType":"def","questionId":"1186","status":"","title":"H2O 生成","titleSlug":"building-h2o"},{"formTitle":"[1118]一月有多少天","frontendQuestionId":"1118","leaf":true,"level":1,"nodeType":"def","questionId":"1088","status":"lock","title":"一月有多少天","titleSlug":"number-of-days-in-a-month"},{"formTitle":"[1119]删去字符串中的元音","frontendQuestionId":"1119","leaf":true,"level":1,"nodeType":"def","questionId":"1089","status":"lock","title":"删去字符串中的元音","titleSlug":"remove-vowels-from-a-string"},{"formTitle":"[1120]子树的最大平均值","frontendQuestionId":"1120","leaf":true,"level":2,"nodeType":"def","questionId":"1091","status":"lock","title":"子树的最大平均值","titleSlug":"maximum-average-subtree"},{"formTitle":"[1121]将数组分成几个递增序列","frontendQuestionId":"1121","leaf":true,"level":3,"nodeType":"def","questionId":"1118","status":"lock","title":"将数组分成几个递增序列","titleSlug":"divide-array-into-increasing-sequences"},{"formTitle":"[1122]数组的相对排序","frontendQuestionId":"1122","leaf":true,"level":1,"nodeType":"def","questionId":"1217","status":"","title":"数组的相对排序","titleSlug":"relative-sort-array"},{"formTitle":"[1123]最深叶节点的最近公共祖先","frontendQuestionId":"1123","leaf":true,"level":2,"nodeType":"def","questionId":"1218","status":"","title":"最深叶节点的最近公共祖先","titleSlug":"lowest-common-ancestor-of-deepest-leaves"},{"formTitle":"[1124]表现良好的最长时间段","frontendQuestionId":"1124","leaf":true,"level":2,"nodeType":"def","questionId":"1219","status":"","title":"表现良好的最长时间段","titleSlug":"longest-well-performing-interval"},{"formTitle":"[1125]最小的必要团队","frontendQuestionId":"1125","leaf":true,"level":3,"nodeType":"def","questionId":"1220","status":"","title":"最小的必要团队","titleSlug":"smallest-sufficient-team"},{"formTitle":"[1126]Active Businesses","frontendQuestionId":"1126","leaf":true,"level":2,"nodeType":"def","questionId":"1225","status":"lock","title":"Active Businesses","titleSlug":"active-businesses"},{"formTitle":"[1127]User Purchase Platform","frontendQuestionId":"1127","leaf":true,"level":3,"nodeType":"def","questionId":"1226","status":"lock","title":"User Purchase Platform","titleSlug":"user-purchase-platform"},{"formTitle":"[1128]等价多米诺骨牌对的数量","frontendQuestionId":"1128","leaf":true,"level":1,"nodeType":"def","questionId":"1227","status":"","title":"等价多米诺骨牌对的数量","titleSlug":"number-of-equivalent-domino-pairs"},{"formTitle":"[1129]颜色交替的最短路径","frontendQuestionId":"1129","leaf":true,"level":2,"nodeType":"def","questionId":"1229","status":"","title":"颜色交替的最短路径","titleSlug":"shortest-path-with-alternating-colors"},{"formTitle":"[1130]叶值的最小代价生成树","frontendQuestionId":"1130","leaf":true,"level":2,"nodeType":"def","questionId":"1228","status":"","title":"叶值的最小代价生成树","titleSlug":"minimum-cost-tree-from-leaf-values"},{"formTitle":"[1131]绝对值表达式的最大值","frontendQuestionId":"1131","leaf":true,"level":2,"nodeType":"def","questionId":"1230","status":"","title":"绝对值表达式的最大值","titleSlug":"maximum-of-absolute-value-expression"},{"formTitle":"[1132]Reported Posts II","frontendQuestionId":"1132","leaf":true,"level":2,"nodeType":"def","questionId":"1237","status":"lock","title":"Reported Posts II","titleSlug":"reported-posts-ii"},{"formTitle":"[1133]最大唯一数","frontendQuestionId":"1133","leaf":true,"level":1,"nodeType":"def","questionId":"1098","status":"lock","title":"最大唯一数","titleSlug":"largest-unique-number"},{"formTitle":"[1134]阿姆斯特朗数","frontendQuestionId":"1134","leaf":true,"level":1,"nodeType":"def","questionId":"1090","status":"lock","title":"阿姆斯特朗数","titleSlug":"armstrong-number"},{"formTitle":"[1135]最低成本联通所有城市","frontendQuestionId":"1135","leaf":true,"level":2,"nodeType":"def","questionId":"1100","status":"lock","title":"最低成本联通所有城市","titleSlug":"connecting-cities-with-minimum-cost"},{"formTitle":"[1136]平行课程","frontendQuestionId":"1136","leaf":true,"level":3,"nodeType":"def","questionId":"1101","status":"lock","title":"平行课程","titleSlug":"parallel-courses"},{"formTitle":"[1137]第 N 个泰波那契数","frontendQuestionId":"1137","leaf":true,"level":1,"nodeType":"def","questionId":"1236","status":"","title":"第 N 个泰波那契数","titleSlug":"n-th-tribonacci-number"},{"formTitle":"[1138]字母板上的路径","frontendQuestionId":"1138","leaf":true,"level":2,"nodeType":"def","questionId":"1238","status":"","title":"字母板上的路径","titleSlug":"alphabet-board-path"},{"formTitle":"[1139]最大的以 1 为边界的正方形","frontendQuestionId":"1139","leaf":true,"level":2,"nodeType":"def","questionId":"1239","status":"","title":"最大的以 1 为边界的正方形","titleSlug":"largest-1-bordered-square"},{"formTitle":"[1140]石子游戏 II","frontendQuestionId":"1140","leaf":true,"level":2,"nodeType":"def","questionId":"1240","status":"","title":"石子游戏 II","titleSlug":"stone-game-ii"},{"formTitle":"[1141]User Activity for the Past 30 Days I","frontendQuestionId":"1141","leaf":true,"level":1,"nodeType":"def","questionId":"1245","status":"lock","title":"User Activity for the Past 30 Days I","titleSlug":"user-activity-for-the-past-30-days-i"},{"formTitle":"[1142]过去30天的用户活动 II","frontendQuestionId":"1142","leaf":true,"level":1,"nodeType":"def","questionId":"1246","status":"lock","title":"过去30天的用户活动 II","titleSlug":"user-activity-for-the-past-30-days-ii"},{"formTitle":"[1143]最长公共子序列","frontendQuestionId":"1143","leaf":true,"level":2,"nodeType":"def","questionId":"1250","status":"","title":"最长公共子序列","titleSlug":"longest-common-subsequence"},{"formTitle":"[1144]递减元素使数组呈锯齿状","frontendQuestionId":"1144","leaf":true,"level":2,"nodeType":"def","questionId":"1247","status":"","title":"递减元素使数组呈锯齿状","titleSlug":"decrease-elements-to-make-array-zigzag"},{"formTitle":"[1145]二叉树着色游戏","frontendQuestionId":"1145","leaf":true,"level":2,"nodeType":"def","questionId":"1248","status":"","title":"二叉树着色游戏","titleSlug":"binary-tree-coloring-game"},{"formTitle":"[1146]快照数组","frontendQuestionId":"1146","leaf":true,"level":2,"nodeType":"def","questionId":"1249","status":"","title":"快照数组","titleSlug":"snapshot-array"},{"formTitle":"[1147]段式回文","frontendQuestionId":"1147","leaf":true,"level":3,"nodeType":"def","questionId":"1251","status":"","title":"段式回文","titleSlug":"longest-chunked-palindrome-decomposition"},{"formTitle":"[1148]文章浏览 I","frontendQuestionId":"1148","leaf":true,"level":1,"nodeType":"def","questionId":"1258","status":"lock","title":"文章浏览 I","titleSlug":"article-views-i"},{"formTitle":"[1149]Article Views II","frontendQuestionId":"1149","leaf":true,"level":2,"nodeType":"def","questionId":"1259","status":"lock","title":"Article Views II","titleSlug":"article-views-ii"},{"formTitle":"[1150]检查一个数是否在数组中占绝大多数","frontendQuestionId":"1150","leaf":true,"level":1,"nodeType":"def","questionId":"1102","status":"lock","title":"检查一个数是否在数组中占绝大多数","titleSlug":"check-if-a-number-is-majority-element-in-a-sorted-array"},{"formTitle":"[1151]最少交换次数来组合所有的 1","frontendQuestionId":"1151","leaf":true,"level":2,"nodeType":"def","questionId":"1107","status":"lock","title":"最少交换次数来组合所有的 1","titleSlug":"minimum-swaps-to-group-all-1s-together"},{"formTitle":"[1152]用户网站访问行为分析","frontendQuestionId":"1152","leaf":true,"level":2,"nodeType":"def","questionId":"1108","status":"lock","title":"用户网站访问行为分析","titleSlug":"analyze-user-website-visit-pattern"},{"formTitle":"[1153]字符串转化","frontendQuestionId":"1153","leaf":true,"level":3,"nodeType":"def","questionId":"1124","status":"lock","title":"字符串转化","titleSlug":"string-transforms-into-another-string"},{"formTitle":"[1154]一年中的第几天","frontendQuestionId":"1154","leaf":true,"level":1,"nodeType":"def","questionId":"1260","status":"","title":"一年中的第几天","titleSlug":"day-of-the-year"},{"formTitle":"[1155]掷骰子的N种方法","frontendQuestionId":"1155","leaf":true,"level":2,"nodeType":"def","questionId":"1263","status":"","title":"掷骰子的N种方法","titleSlug":"number-of-dice-rolls-with-target-sum"},{"formTitle":"[1156]单字符重复子串的最大长度","frontendQuestionId":"1156","leaf":true,"level":2,"nodeType":"def","questionId":"1261","status":"","title":"单字符重复子串的最大长度","titleSlug":"swap-for-longest-repeated-character-substring"},{"formTitle":"[1157]子数组中占绝大多数的元素","frontendQuestionId":"1157","leaf":true,"level":3,"nodeType":"def","questionId":"1262","status":"","title":"子数组中占绝大多数的元素","titleSlug":"online-majority-element-in-subarray"},{"formTitle":"[1158]Market Analysis I","frontendQuestionId":"1158","leaf":true,"level":2,"nodeType":"def","questionId":"1268","status":"lock","title":"Market Analysis I","titleSlug":"market-analysis-i"},{"formTitle":"[1159]Market Analysis II","frontendQuestionId":"1159","leaf":true,"level":3,"nodeType":"def","questionId":"1269","status":"lock","title":"Market Analysis II","titleSlug":"market-analysis-ii"},{"formTitle":"[1160]拼写单词","frontendQuestionId":"1160","leaf":true,"level":1,"nodeType":"def","questionId":"1112","status":"","title":"拼写单词","titleSlug":"find-words-that-can-be-formed-by-characters"},{"formTitle":"[1161]最大层内元素和","frontendQuestionId":"1161","leaf":true,"level":2,"nodeType":"def","questionId":"1116","status":"","title":"最大层内元素和","titleSlug":"maximum-level-sum-of-a-binary-tree"},{"formTitle":"[1162]地图分析","frontendQuestionId":"1162","leaf":true,"level":2,"nodeType":"def","questionId":"1117","status":"","title":"地图分析","titleSlug":"as-far-from-land-as-possible"},{"formTitle":"[1163]按字典序排在最后的子串","frontendQuestionId":"1163","leaf":true,"level":3,"nodeType":"def","questionId":"1133","status":"","title":"按字典序排在最后的子串","titleSlug":"last-substring-in-lexicographical-order"},{"formTitle":"[1164]Product Price at a Given Date","frontendQuestionId":"1164","leaf":true,"level":2,"nodeType":"def","questionId":"1278","status":"lock","title":"Product Price at a Given Date","titleSlug":"product-price-at-a-given-date"},{"formTitle":"[1165]单行键盘","frontendQuestionId":"1165","leaf":true,"level":1,"nodeType":"def","questionId":"1123","status":"lock","title":"单行键盘","titleSlug":"single-row-keyboard"},{"formTitle":"[1166]设计文件系统","frontendQuestionId":"1166","leaf":true,"level":2,"nodeType":"def","questionId":"1125","status":"lock","title":"设计文件系统","titleSlug":"design-file-system"},{"formTitle":"[1167]连接棒材的最低费用","frontendQuestionId":"1167","leaf":true,"level":2,"nodeType":"def","questionId":"1126","status":"lock","title":"连接棒材的最低费用","titleSlug":"minimum-cost-to-connect-sticks"},{"formTitle":"[1168]水资源分配优化","frontendQuestionId":"1168","leaf":true,"level":3,"nodeType":"def","questionId":"1144","status":"lock","title":"水资源分配优化","titleSlug":"optimize-water-distribution-in-a-village"},{"formTitle":"[1169]查询无效交易","frontendQuestionId":"1169","leaf":true,"level":2,"nodeType":"def","questionId":"1272","status":"","title":"查询无效交易","titleSlug":"invalid-transactions"},{"formTitle":"[1170]比较字符串最小字母出现频次","frontendQuestionId":"1170","leaf":true,"level":1,"nodeType":"def","questionId":"1273","status":"","title":"比较字符串最小字母出现频次","titleSlug":"compare-strings-by-frequency-of-the-smallest-character"},{"formTitle":"[1171]从链表中删去总和值为零的连续节点","frontendQuestionId":"1171","leaf":true,"level":2,"nodeType":"def","questionId":"1267","status":"","title":"从链表中删去总和值为零的连续节点","titleSlug":"remove-zero-sum-consecutive-nodes-from-linked-list"},{"formTitle":"[1172]餐盘栈","frontendQuestionId":"1172","leaf":true,"level":3,"nodeType":"def","questionId":"1270","status":"","title":"餐盘栈","titleSlug":"dinner-plate-stacks"},{"formTitle":"[1173]Immediate Food Delivery I","frontendQuestionId":"1173","leaf":true,"level":1,"nodeType":"def","questionId":"1291","status":"lock","title":"Immediate Food Delivery I","titleSlug":"immediate-food-delivery-i"},{"formTitle":"[1174]Immediate Food Delivery II","frontendQuestionId":"1174","leaf":true,"level":2,"nodeType":"def","questionId":"1292","status":"lock","title":"Immediate Food Delivery II","titleSlug":"immediate-food-delivery-ii"},{"formTitle":"[1175]质数排列","frontendQuestionId":"1175","leaf":true,"level":1,"nodeType":"def","questionId":"1279","status":"","title":"质数排列","titleSlug":"prime-arrangements"},{"formTitle":"[1176]健身计划评估","frontendQuestionId":"1176","leaf":true,"level":1,"nodeType":"def","questionId":"1280","status":"lock","title":"健身计划评估","titleSlug":"diet-plan-performance"},{"formTitle":"[1177]构建回文串检测","frontendQuestionId":"1177","leaf":true,"level":2,"nodeType":"def","questionId":"1281","status":"","title":"构建回文串检测","titleSlug":"can-make-palindrome-from-substring"},{"formTitle":"[1178]猜字谜","frontendQuestionId":"1178","leaf":true,"level":3,"nodeType":"def","questionId":"1282","status":"","title":"猜字谜","titleSlug":"number-of-valid-words-for-each-puzzle"},{"formTitle":"[1179]重新格式化部门表","frontendQuestionId":"1179","leaf":true,"level":1,"nodeType":"def","questionId":"1301","status":"","title":"重新格式化部门表","titleSlug":"reformat-department-table"},{"formTitle":"[1180]统计只含单一字母的子串","frontendQuestionId":"1180","leaf":true,"level":1,"nodeType":"def","questionId":"1131","status":"lock","title":"统计只含单一字母的子串","titleSlug":"count-substrings-with-only-one-distinct-letter"},{"formTitle":"[1181]前后拼接","frontendQuestionId":"1181","leaf":true,"level":2,"nodeType":"def","questionId":"1132","status":"lock","title":"前后拼接","titleSlug":"before-and-after-puzzle"},{"formTitle":"[1182]与目标颜色间的最短距离","frontendQuestionId":"1182","leaf":true,"level":2,"nodeType":"def","questionId":"1134","status":"lock","title":"与目标颜色间的最短距离","titleSlug":"shortest-distance-to-target-color"},{"formTitle":"[1183]矩阵中 1 的最大数量","frontendQuestionId":"1183","leaf":true,"level":3,"nodeType":"def","questionId":"1152","status":"lock","title":"矩阵中 1 的最大数量","titleSlug":"maximum-number-of-ones"},{"formTitle":"[1184]公交站间的距离","frontendQuestionId":"1184","leaf":true,"level":1,"nodeType":"def","questionId":"1287","status":"","title":"公交站间的距离","titleSlug":"distance-between-bus-stops"},{"formTitle":"[1185]一周中的第几天","frontendQuestionId":"1185","leaf":true,"level":1,"nodeType":"def","questionId":"1289","status":"","title":"一周中的第几天","titleSlug":"day-of-the-week"},{"formTitle":"[1186]删除一次得到子数组最大和","frontendQuestionId":"1186","leaf":true,"level":2,"nodeType":"def","questionId":"1288","status":"","title":"删除一次得到子数组最大和","titleSlug":"maximum-subarray-sum-with-one-deletion"},{"formTitle":"[1187]使数组严格递增","frontendQuestionId":"1187","leaf":true,"level":3,"nodeType":"def","questionId":"1290","status":"","title":"使数组严格递增","titleSlug":"make-array-strictly-increasing"},{"formTitle":"[1188]设计有限阻塞队列","frontendQuestionId":"1188","leaf":true,"level":2,"nodeType":"def","questionId":"1209","status":"lock","title":"设计有限阻塞队列","titleSlug":"design-bounded-blocking-queue"},{"formTitle":"[1189]“气球” 的最大数量","frontendQuestionId":"1189","leaf":true,"level":1,"nodeType":"def","questionId":"1297","status":"","title":"“气球” 的最大数量","titleSlug":"maximum-number-of-balloons"},{"formTitle":"[1190]反转每对括号间的子串","frontendQuestionId":"1190","leaf":true,"level":2,"nodeType":"def","questionId":"1298","status":"","title":"反转每对括号间的子串","titleSlug":"reverse-substrings-between-each-pair-of-parentheses"},{"formTitle":"[1191]K 次串联后最大子数组之和","frontendQuestionId":"1191","leaf":true,"level":2,"nodeType":"def","questionId":"1299","status":"","title":"K 次串联后最大子数组之和","titleSlug":"k-concatenation-maximum-sum"},{"formTitle":"[1192]查找集群内的「关键连接」","frontendQuestionId":"1192","leaf":true,"level":3,"nodeType":"def","questionId":"1300","status":"","title":"查找集群内的「关键连接」","titleSlug":"critical-connections-in-a-network"},{"formTitle":"[1193]每月交易 I","frontendQuestionId":"1193","leaf":true,"level":2,"nodeType":"def","questionId":"1317","status":"lock","title":"每月交易 I","titleSlug":"monthly-transactions-i"},{"formTitle":"[1194]锦标赛优胜者","frontendQuestionId":"1194","leaf":true,"level":3,"nodeType":"def","questionId":"1318","status":"lock","title":"锦标赛优胜者","titleSlug":"tournament-winners"},{"formTitle":"[1195]交替打印字符串","frontendQuestionId":"1195","leaf":true,"level":2,"nodeType":"def","questionId":"1316","status":"","title":"交替打印字符串","titleSlug":"fizz-buzz-multithreaded"},{"formTitle":"[1196]最多可以买到的苹果数量","frontendQuestionId":"1196","leaf":true,"level":1,"nodeType":"def","questionId":"1141","status":"lock","title":"最多可以买到的苹果数量","titleSlug":"how-many-apples-can-you-put-into-the-basket"},{"formTitle":"[1197]进击的骑士","frontendQuestionId":"1197","leaf":true,"level":2,"nodeType":"def","questionId":"1142","status":"lock","title":"进击的骑士","titleSlug":"minimum-knight-moves"},{"formTitle":"[1198]找出所有行中最小公共元素","frontendQuestionId":"1198","leaf":true,"level":2,"nodeType":"def","questionId":"1143","status":"lock","title":"找出所有行中最小公共元素","titleSlug":"find-smallest-common-element-in-all-rows"},{"formTitle":"[1199]建造街区的最短时间","frontendQuestionId":"1199","leaf":true,"level":3,"nodeType":"def","questionId":"1167","status":"lock","title":"建造街区的最短时间","titleSlug":"minimum-time-to-build-blocks"},{"formTitle":"[1200]最小绝对差","frontendQuestionId":"1200","leaf":true,"level":1,"nodeType":"def","questionId":"1306","status":"","title":"最小绝对差","titleSlug":"minimum-absolute-difference"},{"formTitle":"[1201]丑数 III","frontendQuestionId":"1201","leaf":true,"level":2,"nodeType":"def","questionId":"1307","status":"","title":"丑数 III","titleSlug":"ugly-number-iii"},{"formTitle":"[1202]交换字符串中的元素","frontendQuestionId":"1202","leaf":true,"level":2,"nodeType":"def","questionId":"1308","status":"","title":"交换字符串中的元素","titleSlug":"smallest-string-with-swaps"},{"formTitle":"[1203]项目管理","frontendQuestionId":"1203","leaf":true,"level":3,"nodeType":"def","questionId":"1309","status":"","title":"项目管理","titleSlug":"sort-items-by-groups-respecting-dependencies"},{"formTitle":"[1204]Last Person to Fit in the Elevator","frontendQuestionId":"1204","leaf":true,"level":2,"nodeType":"def","questionId":"1327","status":"lock","title":"Last Person to Fit in the Elevator","titleSlug":"last-person-to-fit-in-the-elevator"},{"formTitle":"[1205]每月交易II","frontendQuestionId":"1205","leaf":true,"level":2,"nodeType":"def","questionId":"1328","status":"lock","title":"每月交易II","titleSlug":"monthly-transactions-ii"},{"formTitle":"[1206]设计跳表","frontendQuestionId":"1206","leaf":true,"level":3,"nodeType":"def","questionId":"1337","status":"","title":"设计跳表","titleSlug":"design-skiplist"},{"formTitle":"[1207]独一无二的出现次数","frontendQuestionId":"1207","leaf":true,"level":1,"nodeType":"def","questionId":"1319","status":"","title":"独一无二的出现次数","titleSlug":"unique-number-of-occurrences"},{"formTitle":"[1208]尽可能使字符串相等","frontendQuestionId":"1208","leaf":true,"level":2,"nodeType":"def","questionId":"1321","status":"","title":"尽可能使字符串相等","titleSlug":"get-equal-substrings-within-budget"},{"formTitle":"[1209]删除字符串中的所有相邻重复项 II","frontendQuestionId":"1209","leaf":true,"level":2,"nodeType":"def","questionId":"1320","status":"","title":"删除字符串中的所有相邻重复项 II","titleSlug":"remove-all-adjacent-duplicates-in-string-ii"},{"formTitle":"[1210]穿过迷宫的最少移动次数","frontendQuestionId":"1210","leaf":true,"level":3,"nodeType":"def","questionId":"1322","status":"","title":"穿过迷宫的最少移动次数","titleSlug":"minimum-moves-to-reach-target-with-rotations"},{"formTitle":"[1211]Queries Quality and Percentage","frontendQuestionId":"1211","leaf":true,"level":1,"nodeType":"def","questionId":"1338","status":"lock","title":"Queries Quality and Percentage","titleSlug":"queries-quality-and-percentage"},{"formTitle":"[1212]Team Scores in Football Tournament","frontendQuestionId":"1212","leaf":true,"level":2,"nodeType":"def","questionId":"1339","status":"lock","title":"Team Scores in Football Tournament","titleSlug":"team-scores-in-football-tournament"},{"formTitle":"[1213]三个有序数组的交集","frontendQuestionId":"1213","leaf":true,"level":1,"nodeType":"def","questionId":"1149","status":"lock","title":"三个有序数组的交集","titleSlug":"intersection-of-three-sorted-arrays"},{"formTitle":"[1214]查找两棵二叉搜索树之和","frontendQuestionId":"1214","leaf":true,"level":2,"nodeType":"def","questionId":"1150","status":"lock","title":"查找两棵二叉搜索树之和","titleSlug":"two-sum-bsts"},{"formTitle":"[1215]步进数","frontendQuestionId":"1215","leaf":true,"level":2,"nodeType":"def","questionId":"1151","status":"lock","title":"步进数","titleSlug":"stepping-numbers"},{"formTitle":"[1216]验证回文字符串 III","frontendQuestionId":"1216","leaf":true,"level":3,"nodeType":"def","questionId":"1178","status":"lock","title":"验证回文字符串 III","titleSlug":"valid-palindrome-iii"},{"formTitle":"[1217]玩筹码","frontendQuestionId":"1217","leaf":true,"level":1,"nodeType":"def","questionId":"1329","status":"","title":"玩筹码","titleSlug":"play-with-chips"},{"formTitle":"[1218]最长定差子序列","frontendQuestionId":"1218","leaf":true,"level":2,"nodeType":"def","questionId":"1330","status":"","title":"最长定差子序列","titleSlug":"longest-arithmetic-subsequence-of-given-difference"},{"formTitle":"[1219]黄金矿工","frontendQuestionId":"1219","leaf":true,"level":2,"nodeType":"def","questionId":"1331","status":"","title":"黄金矿工","titleSlug":"path-with-maximum-gold"},{"formTitle":"[1220]统计元音字母序列的数目","frontendQuestionId":"1220","leaf":true,"level":3,"nodeType":"def","questionId":"1332","status":"","title":"统计元音字母序列的数目","titleSlug":"count-vowels-permutation"},{"formTitle":"[1221]分割平衡字符串","frontendQuestionId":"1221","leaf":true,"level":1,"nodeType":"def","questionId":"1341","status":"","title":"分割平衡字符串","titleSlug":"split-a-string-in-balanced-strings"},{"formTitle":"[1222]可以攻击国王的皇后","frontendQuestionId":"1222","leaf":true,"level":2,"nodeType":"def","questionId":"1342","status":"","title":"可以攻击国王的皇后","titleSlug":"queens-that-can-attack-the-king"},{"formTitle":"[1223]掷骰子模拟","frontendQuestionId":"1223","leaf":true,"level":2,"nodeType":"def","questionId":"1343","status":"","title":"掷骰子模拟","titleSlug":"dice-roll-simulation"},{"formTitle":"[1224]最大相等频率","frontendQuestionId":"1224","leaf":true,"level":3,"nodeType":"def","questionId":"1344","status":"","title":"最大相等频率","titleSlug":"maximum-equal-frequency"},{"formTitle":"[1225]报告系统状态的连续日期","frontendQuestionId":"1225","leaf":true,"level":3,"nodeType":"def","questionId":"1357","status":"lock","title":"报告系统状态的连续日期","titleSlug":"report-contiguous-dates"},{"formTitle":"[1226]哲学家进餐","frontendQuestionId":"1226","leaf":true,"level":2,"nodeType":"def","questionId":"1340","status":"","title":"哲学家进餐","titleSlug":"the-dining-philosophers"},{"formTitle":"[1227]飞机座位分配概率","frontendQuestionId":"1227","leaf":true,"level":2,"nodeType":"def","questionId":"1362","status":"","title":"飞机座位分配概率","titleSlug":"airplane-seat-assignment-probability"},{"formTitle":"[1228]等差数列中缺失的数字","frontendQuestionId":"1228","leaf":true,"level":1,"nodeType":"def","questionId":"1164","status":"lock","title":"等差数列中缺失的数字","titleSlug":"missing-number-in-arithmetic-progression"},{"formTitle":"[1229]安排会议日程","frontendQuestionId":"1229","leaf":true,"level":2,"nodeType":"def","questionId":"1165","status":"lock","title":"安排会议日程","titleSlug":"meeting-scheduler"},{"formTitle":"[1230]抛掷硬币","frontendQuestionId":"1230","leaf":true,"level":2,"nodeType":"def","questionId":"1166","status":"lock","title":"抛掷硬币","titleSlug":"toss-strange-coins"},{"formTitle":"[1231]分享巧克力","frontendQuestionId":"1231","leaf":true,"level":3,"nodeType":"def","questionId":"1192","status":"lock","title":"分享巧克力","titleSlug":"divide-chocolate"},{"formTitle":"[1232]缀点成线","frontendQuestionId":"1232","leaf":true,"level":1,"nodeType":"def","questionId":"1349","status":"","title":"缀点成线","titleSlug":"check-if-it-is-a-straight-line"},{"formTitle":"[1233]删除子文件夹","frontendQuestionId":"1233","leaf":true,"level":2,"nodeType":"def","questionId":"1350","status":"","title":"删除子文件夹","titleSlug":"remove-sub-folders-from-the-filesystem"},{"formTitle":"[1234]替换子串得到平衡字符串","frontendQuestionId":"1234","leaf":true,"level":2,"nodeType":"def","questionId":"1351","status":"","title":"替换子串得到平衡字符串","titleSlug":"replace-the-substring-for-balanced-string"},{"formTitle":"[1235]规划兼职工作","frontendQuestionId":"1235","leaf":true,"level":3,"nodeType":"def","questionId":"1352","status":"","title":"规划兼职工作","titleSlug":"maximum-profit-in-job-scheduling"},{"formTitle":"[1236]Web Crawler","frontendQuestionId":"1236","leaf":true,"level":2,"nodeType":"def","questionId":"1271","status":"lock","title":"Web Crawler","titleSlug":"web-crawler"},{"formTitle":"[1237]找出给定方程的正整数解","frontendQuestionId":"1237","leaf":true,"level":1,"nodeType":"def","questionId":"1358","status":"","title":"找出给定方程的正整数解","titleSlug":"find-positive-integer-solution-for-a-given-equation"},{"formTitle":"[1238]循环码排列","frontendQuestionId":"1238","leaf":true,"level":2,"nodeType":"def","questionId":"1359","status":"","title":"循环码排列","titleSlug":"circular-permutation-in-binary-representation"},{"formTitle":"[1239]串联字符串的最大长度","frontendQuestionId":"1239","leaf":true,"level":2,"nodeType":"def","questionId":"1360","status":"","title":"串联字符串的最大长度","titleSlug":"maximum-length-of-a-concatenated-string-with-unique-characters"},{"formTitle":"[1240]铺瓷砖","frontendQuestionId":"1240","leaf":true,"level":3,"nodeType":"def","questionId":"1361","status":"","title":"铺瓷砖","titleSlug":"tiling-a-rectangle-with-the-fewest-squares"},{"formTitle":"[1241]每个帖子的评论数","frontendQuestionId":"1241","leaf":true,"level":1,"nodeType":"def","questionId":"1377","status":"lock","title":"每个帖子的评论数","titleSlug":"number-of-comments-per-post"},{"formTitle":"[1242]多线程网页爬虫","frontendQuestionId":"1242","leaf":true,"level":2,"nodeType":"def","questionId":"1368","status":"lock","title":"多线程网页爬虫","titleSlug":"web-crawler-multithreaded"},{"formTitle":"[1243]数组变换","frontendQuestionId":"1243","leaf":true,"level":1,"nodeType":"def","questionId":"1175","status":"lock","title":"数组变换","titleSlug":"array-transformation"},{"formTitle":"[1244]力扣排行榜","frontendQuestionId":"1244","leaf":true,"level":2,"nodeType":"def","questionId":"1176","status":"lock","title":"力扣排行榜","titleSlug":"design-a-leaderboard"},{"formTitle":"[1245]树的直径","frontendQuestionId":"1245","leaf":true,"level":2,"nodeType":"def","questionId":"1177","status":"lock","title":"树的直径","titleSlug":"tree-diameter"},{"formTitle":"[1246]删除回文子数组","frontendQuestionId":"1246","leaf":true,"level":3,"nodeType":"def","questionId":"1202","status":"lock","title":"删除回文子数组","titleSlug":"palindrome-removal"},{"formTitle":"[1247]交换字符使得字符串相同","frontendQuestionId":"1247","leaf":true,"level":2,"nodeType":"def","questionId":"1369","status":"","title":"交换字符使得字符串相同","titleSlug":"minimum-swaps-to-make-strings-equal"},{"formTitle":"[1248]统计「优美子数组」","frontendQuestionId":"1248","leaf":true,"level":2,"nodeType":"def","questionId":"1370","status":"","title":"统计「优美子数组」","titleSlug":"count-number-of-nice-subarrays"},{"formTitle":"[1249]移除无效的括号","frontendQuestionId":"1249","leaf":true,"level":2,"nodeType":"def","questionId":"1371","status":"","title":"移除无效的括号","titleSlug":"minimum-remove-to-make-valid-parentheses"},{"formTitle":"[1250]检查「好数组」","frontendQuestionId":"1250","leaf":true,"level":3,"nodeType":"def","questionId":"1372","status":"","title":"检查「好数组」","titleSlug":"check-if-it-is-a-good-array"},{"formTitle":"[1251]Average Selling Price","frontendQuestionId":"1251","leaf":true,"level":1,"nodeType":"def","questionId":"1390","status":"lock","title":"Average Selling Price","titleSlug":"average-selling-price"},{"formTitle":"[1252]奇数值单元格的数目","frontendQuestionId":"1252","leaf":true,"level":1,"nodeType":"def","questionId":"1378","status":"","title":"奇数值单元格的数目","titleSlug":"cells-with-odd-values-in-a-matrix"},{"formTitle":"[1253]重构 2 行二进制矩阵","frontendQuestionId":"1253","leaf":true,"level":2,"nodeType":"def","questionId":"1379","status":"","title":"重构 2 行二进制矩阵","titleSlug":"reconstruct-a-2-row-binary-matrix"},{"formTitle":"[1254]统计封闭岛屿的数目","frontendQuestionId":"1254","leaf":true,"level":2,"nodeType":"def","questionId":"1380","status":"","title":"统计封闭岛屿的数目","titleSlug":"number-of-closed-islands"},{"formTitle":"[1255]得分最高的单词集合","frontendQuestionId":"1255","leaf":true,"level":3,"nodeType":"def","questionId":"1381","status":"","title":"得分最高的单词集合","titleSlug":"maximum-score-words-formed-by-letters"},{"formTitle":"[1256]加密数字","frontendQuestionId":"1256","leaf":true,"level":2,"nodeType":"def","questionId":"1189","status":"lock","title":"加密数字","titleSlug":"encode-number"},{"formTitle":"[1257]最小公共区域","frontendQuestionId":"1257","leaf":true,"level":2,"nodeType":"def","questionId":"1190","status":"lock","title":"最小公共区域","titleSlug":"smallest-common-region"},{"formTitle":"[1258]近义词句子","frontendQuestionId":"1258","leaf":true,"level":2,"nodeType":"def","questionId":"1191","status":"lock","title":"近义词句子","titleSlug":"synonymous-sentences"},{"formTitle":"[1259]不相交的握手","frontendQuestionId":"1259","leaf":true,"level":3,"nodeType":"def","questionId":"1213","status":"lock","title":"不相交的握手","titleSlug":"handshakes-that-dont-cross"},{"formTitle":"[1260]二维网格迁移","frontendQuestionId":"1260","leaf":true,"level":1,"nodeType":"def","questionId":"1386","status":"","title":"二维网格迁移","titleSlug":"shift-2d-grid"},{"formTitle":"[1261]在受污染的二叉树中查找元素","frontendQuestionId":"1261","leaf":true,"level":2,"nodeType":"def","questionId":"1387","status":"","title":"在受污染的二叉树中查找元素","titleSlug":"find-elements-in-a-contaminated-binary-tree"},{"formTitle":"[1262]可被三整除的最大和","frontendQuestionId":"1262","leaf":true,"level":2,"nodeType":"def","questionId":"1388","status":"","title":"可被三整除的最大和","titleSlug":"greatest-sum-divisible-by-three"},{"formTitle":"[1263]推箱子","frontendQuestionId":"1263","leaf":true,"level":3,"nodeType":"def","questionId":"1389","status":"","title":"推箱子","titleSlug":"minimum-moves-to-move-a-box-to-their-target-location"},{"formTitle":"[1264]Page Recommendations","frontendQuestionId":"1264","leaf":true,"level":2,"nodeType":"def","questionId":"1399","status":"lock","title":"Page Recommendations","titleSlug":"page-recommendations"},{"formTitle":"[1265]Print Immutable Linked List in Reverse","frontendQuestionId":"1265","leaf":true,"level":2,"nodeType":"def","questionId":"1404","status":"lock","title":"Print Immutable Linked List in Reverse","titleSlug":"print-immutable-linked-list-in-reverse"},{"formTitle":"[1266]访问所有点的最小时间","frontendQuestionId":"1266","leaf":true,"level":1,"nodeType":"def","questionId":"1395","status":"","title":"访问所有点的最小时间","titleSlug":"minimum-time-visiting-all-points"},{"formTitle":"[1267]统计参与通信的服务器","frontendQuestionId":"1267","leaf":true,"level":2,"nodeType":"def","questionId":"1396","status":"","title":"统计参与通信的服务器","titleSlug":"count-servers-that-communicate"},{"formTitle":"[1268]搜索推荐系统","frontendQuestionId":"1268","leaf":true,"level":2,"nodeType":"def","questionId":"1397","status":"","title":"搜索推荐系统","titleSlug":"search-suggestions-system"},{"formTitle":"[1269]停在原地的方案数","frontendQuestionId":"1269","leaf":true,"level":3,"nodeType":"def","questionId":"1398","status":"","title":"停在原地的方案数","titleSlug":"number-of-ways-to-stay-in-the-same-place-after-some-steps"},{"formTitle":"[1270]All People Report to the Given Manager","frontendQuestionId":"1270","leaf":true,"level":2,"nodeType":"def","questionId":"1405","status":"lock","title":"All People Report to the Given Manager","titleSlug":"all-people-report-to-the-given-manager"},{"formTitle":"[1271]十六进制魔术数字","frontendQuestionId":"1271","leaf":true,"level":1,"nodeType":"def","questionId":"1199","status":"lock","title":"十六进制魔术数字","titleSlug":"hexspeak"},{"formTitle":"[1272]删除区间","frontendQuestionId":"1272","leaf":true,"level":2,"nodeType":"def","questionId":"1200","status":"lock","title":"删除区间","titleSlug":"remove-interval"},{"formTitle":"[1273]删除树节点","frontendQuestionId":"1273","leaf":true,"level":2,"nodeType":"def","questionId":"1201","status":"lock","title":"删除树节点","titleSlug":"delete-tree-nodes"},{"formTitle":"[1274]矩形内船只的数目","frontendQuestionId":"1274","leaf":true,"level":3,"nodeType":"def","questionId":"1233","status":"lock","title":"矩形内船只的数目","titleSlug":"number-of-ships-in-a-rectangle"},{"formTitle":"[1275]找出井字棋的获胜者","frontendQuestionId":"1275","leaf":true,"level":1,"nodeType":"def","questionId":"1400","status":"","title":"找出井字棋的获胜者","titleSlug":"find-winner-on-a-tic-tac-toe-game"},{"formTitle":"[1276]不浪费原料的汉堡制作方案","frontendQuestionId":"1276","leaf":true,"level":2,"nodeType":"def","questionId":"1401","status":"","title":"不浪费原料的汉堡制作方案","titleSlug":"number-of-burgers-with-no-waste-of-ingredients"},{"formTitle":"[1277]统计全为 1 的正方形子矩阵","frontendQuestionId":"1277","leaf":true,"level":2,"nodeType":"def","questionId":"1402","status":"","title":"统计全为 1 的正方形子矩阵","titleSlug":"count-square-submatrices-with-all-ones"},{"formTitle":"[1278]分割回文串 III","frontendQuestionId":"1278","leaf":true,"level":3,"nodeType":"def","questionId":"1403","status":"","title":"分割回文串 III","titleSlug":"palindrome-partitioning-iii"},{"formTitle":"[1279]Traffic Light Controlled Intersection","frontendQuestionId":"1279","leaf":true,"level":1,"nodeType":"def","questionId":"1410","status":"lock","title":"Traffic Light Controlled Intersection","titleSlug":"traffic-light-controlled-intersection"},{"formTitle":"[LCP 1]猜数字","frontendQuestionId":"LCP 1","leaf":true,"level":1,"nodeType":"def","questionId":"100107","status":"","title":"猜数字","titleSlug":"guess-numbers"},{"formTitle":"[LCP 2]分式化简","frontendQuestionId":"LCP 2","leaf":true,"level":1,"nodeType":"def","questionId":"100092","status":"","title":"分式化简","titleSlug":"deep-dark-fraction"},{"formTitle":"[LCP 3]机器人大冒险","frontendQuestionId":"LCP 3","leaf":true,"level":2,"nodeType":"def","questionId":"100096","status":"","title":"机器人大冒险","titleSlug":"programmable-robot"},{"formTitle":"[LCP 4]覆盖","frontendQuestionId":"LCP 4","leaf":true,"level":3,"nodeType":"def","questionId":"100093","status":"","title":"覆盖","titleSlug":"broken-board-dominoes"},{"formTitle":"[LCP 5]发 LeetCoin","frontendQuestionId":"LCP 5","leaf":true,"level":3,"nodeType":"def","questionId":"100094","status":"","title":"发 LeetCoin","titleSlug":"coin-bonus"}] \ No newline at end of file diff --git a/Week 07/id_101/translation.json b/Week 07/id_101/translation.json new file mode 100644 index 000000000..e0463abed --- /dev/null +++ b/Week 07/id_101/translation.json @@ -0,0 +1 @@ +{"data":{"translations":[{"title":"\u4e24\u6570\u4e4b\u548c","question":{"questionId":"1","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u52a0","question":{"questionId":"2","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u91cd\u590d\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"3","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u4e24\u4e2a\u6709\u5e8f\u6570\u7ec4\u7684\u4e2d\u4f4d\u6570","question":{"questionId":"4","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u5b50\u4e32","question":{"questionId":"5","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Z \u5b57\u5f62\u53d8\u6362","question":{"questionId":"6","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u53cd\u8f6c","question":{"questionId":"7","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u8f6c\u6362\u6574\u6570 (atoi)","question":{"questionId":"8","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6570","question":{"questionId":"9","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b63\u5219\u8868\u8fbe\u5f0f\u5339\u914d","question":{"questionId":"10","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76db\u6700\u591a\u6c34\u7684\u5bb9\u5668","question":{"questionId":"11","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u8f6c\u7f57\u9a6c\u6570\u5b57","question":{"questionId":"12","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f57\u9a6c\u6570\u5b57\u8f6c\u6574\u6570","question":{"questionId":"13","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u516c\u5171\u524d\u7f00","question":{"questionId":"14","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u6570\u4e4b\u548c","question":{"questionId":"15","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e09\u6570\u4e4b\u548c","question":{"questionId":"16","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7535\u8bdd\u53f7\u7801\u7684\u5b57\u6bcd\u7ec4\u5408","question":{"questionId":"17","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u6570\u4e4b\u548c","question":{"questionId":"18","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u94fe\u8868\u7684\u5012\u6570\u7b2cN\u4e2a\u8282\u70b9","question":{"questionId":"19","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u62ec\u53f7","question":{"questionId":"20","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e24\u4e2a\u6709\u5e8f\u94fe\u8868","question":{"questionId":"21","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62ec\u53f7\u751f\u6210","question":{"questionId":"22","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76K\u4e2a\u6392\u5e8f\u94fe\u8868","question":{"questionId":"23","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e24\u4ea4\u6362\u94fe\u8868\u4e2d\u7684\u8282\u70b9","question":{"questionId":"24","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u4e00\u7ec4\u7ffb\u8f6c\u94fe\u8868","question":{"questionId":"25","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u9879","question":{"questionId":"26","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u5143\u7d20","question":{"questionId":"27","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0 strStr()","question":{"questionId":"28","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u9664","question":{"questionId":"29","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e32\u8054\u6240\u6709\u5355\u8bcd\u7684\u5b50\u4e32","question":{"questionId":"30","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u6392\u5217","question":{"questionId":"31","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6709\u6548\u62ec\u53f7","question":{"questionId":"32","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"33","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u6392\u5e8f\u6570\u7ec4\u4e2d\u67e5\u627e\u5143\u7d20\u7684\u7b2c\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e","question":{"questionId":"34","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u63d2\u5165\u4f4d\u7f6e","question":{"questionId":"35","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u6570\u72ec","question":{"questionId":"36","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u6570\u72ec","question":{"questionId":"37","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62a5\u6570","question":{"questionId":"38","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c","question":{"questionId":"39","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c II","question":{"questionId":"40","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u7684\u7b2c\u4e00\u4e2a\u6b63\u6570","question":{"questionId":"41","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a5\u96e8\u6c34","question":{"questionId":"42","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u76f8\u4e58","question":{"questionId":"43","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u901a\u914d\u7b26\u5339\u914d","question":{"questionId":"44","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8df3\u8dc3\u6e38\u620f II","question":{"questionId":"45","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217","question":{"questionId":"46","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217 II","question":{"questionId":"47","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u56fe\u50cf","question":{"questionId":"48","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5f02\u4f4d\u8bcd\u5206\u7ec4","question":{"questionId":"49","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Pow(x, n)","question":{"questionId":"50","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u7687\u540e","question":{"questionId":"51","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u7687\u540e II","question":{"questionId":"52","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5b50\u5e8f\u548c","question":{"questionId":"53","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635","question":{"questionId":"54","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8df3\u8dc3\u6e38\u620f","question":{"questionId":"55","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u533a\u95f4","question":{"questionId":"56","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63d2\u5165\u533a\u95f4","question":{"questionId":"57","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u4e2a\u5355\u8bcd\u7684\u957f\u5ea6","question":{"questionId":"58","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635 II","question":{"questionId":"59","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2ck\u4e2a\u6392\u5217","question":{"questionId":"60","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u94fe\u8868","question":{"questionId":"61","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84","question":{"questionId":"62","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84 II","question":{"questionId":"63","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u8def\u5f84\u548c","question":{"questionId":"64","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u6570\u5b57","question":{"questionId":"65","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u4e00","question":{"questionId":"66","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u6c42\u548c","question":{"questionId":"67","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u672c\u5de6\u53f3\u5bf9\u9f50","question":{"questionId":"68","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"x \u7684\u5e73\u65b9\u6839","question":{"questionId":"69","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u722c\u697c\u68af","question":{"questionId":"70","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b80\u5316\u8def\u5f84","question":{"questionId":"71","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f16\u8f91\u8ddd\u79bb","question":{"questionId":"72","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u7f6e\u96f6","question":{"questionId":"73","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u4e8c\u7ef4\u77e9\u9635","question":{"questionId":"74","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u989c\u8272\u5206\u7c7b","question":{"questionId":"75","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u8986\u76d6\u5b50\u4e32","question":{"questionId":"76","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408","question":{"questionId":"77","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u96c6","question":{"questionId":"78","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u641c\u7d22","question":{"questionId":"79","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u9879 II","question":{"questionId":"80","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4 II","question":{"questionId":"81","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u94fe\u8868\u4e2d\u7684\u91cd\u590d\u5143\u7d20 II","question":{"questionId":"82","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u94fe\u8868\u4e2d\u7684\u91cd\u590d\u5143\u7d20","question":{"questionId":"83","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67f1\u72b6\u56fe\u4e2d\u6700\u5927\u7684\u77e9\u5f62","question":{"questionId":"84","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u77e9\u5f62","question":{"questionId":"85","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u94fe\u8868","question":{"questionId":"86","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6270\u4e71\u5b57\u7b26\u4e32","question":{"questionId":"87","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e24\u4e2a\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"88","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u683c\u96f7\u7f16\u7801","question":{"questionId":"89","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u96c6 II","question":{"questionId":"90","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u7801\u65b9\u6cd5","question":{"questionId":"91","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u94fe\u8868 II","question":{"questionId":"92","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u539fIP\u5730\u5740","question":{"questionId":"93","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u4e2d\u5e8f\u904d\u5386","question":{"questionId":"94","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u4e8c\u53c9\u641c\u7d22\u6811 II","question":{"questionId":"95","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"96","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u9519\u5b57\u7b26\u4e32","question":{"questionId":"97","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"98","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6062\u590d\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"99","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u540c\u7684\u6811","question":{"questionId":"100","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u79f0\u4e8c\u53c9\u6811","question":{"questionId":"101","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u6b21\u904d\u5386","question":{"questionId":"102","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u952f\u9f7f\u5f62\u5c42\u6b21\u904d\u5386","question":{"questionId":"103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u5927\u6df1\u5ea6","question":{"questionId":"104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u524d\u5e8f\u4e0e\u4e2d\u5e8f\u904d\u5386\u5e8f\u5217\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e2d\u5e8f\u4e0e\u540e\u5e8f\u904d\u5386\u5e8f\u5217\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u6b21\u904d\u5386 II","question":{"questionId":"107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6709\u5e8f\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"108","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u94fe\u8868\u8f6c\u6362\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"109","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u8861\u4e8c\u53c9\u6811","question":{"questionId":"110","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u5c0f\u6df1\u5ea6","question":{"questionId":"111","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c","question":{"questionId":"112","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c II","question":{"questionId":"113","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u5c55\u5f00\u4e3a\u94fe\u8868","question":{"questionId":"114","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u5b50\u5e8f\u5217","question":{"questionId":"115","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u6bcf\u4e2a\u8282\u70b9\u7684\u4e0b\u4e00\u4e2a\u53f3\u4fa7\u8282\u70b9\u6307\u9488","question":{"questionId":"116","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u6bcf\u4e2a\u8282\u70b9\u7684\u4e0b\u4e00\u4e2a\u53f3\u4fa7\u8282\u70b9\u6307\u9488 II","question":{"questionId":"117","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6768\u8f89\u4e09\u89d2","question":{"questionId":"118","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6768\u8f89\u4e09\u89d2 II","question":{"questionId":"119","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u89d2\u5f62\u6700\u5c0f\u8def\u5f84\u548c","question":{"questionId":"120","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a","question":{"questionId":"121","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a II","question":{"questionId":"122","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a III","question":{"questionId":"123","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u7684\u6700\u5927\u8def\u5f84\u548c","question":{"questionId":"124","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u4e32","question":{"questionId":"125","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u63a5\u9f99 II","question":{"questionId":"126","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u63a5\u9f99","question":{"questionId":"127","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"128","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u6839\u5230\u53f6\u5b50\u8282\u70b9\u6570\u5b57\u4e4b\u548c","question":{"questionId":"129","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u88ab\u56f4\u7ed5\u7684\u533a\u57df","question":{"questionId":"130","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u56de\u6587\u4e32","question":{"questionId":"131","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u56de\u6587\u4e32 II","question":{"questionId":"132","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u514b\u9686\u56fe","question":{"questionId":"133","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u6cb9\u7ad9","question":{"questionId":"134","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u53d1\u7cd6\u679c","question":{"questionId":"135","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57","question":{"questionId":"136","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57 II","question":{"questionId":"137","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u5236\u5e26\u968f\u673a\u6307\u9488\u7684\u94fe\u8868","question":{"questionId":"138","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u62c6\u5206","question":{"questionId":"139","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u62c6\u5206 II","question":{"questionId":"140","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u94fe\u8868","question":{"questionId":"141","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u94fe\u8868 II","question":{"questionId":"142","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u6392\u94fe\u8868","question":{"questionId":"143","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u524d\u5e8f\u904d\u5386","question":{"questionId":"144","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u540e\u5e8f\u904d\u5386","question":{"questionId":"145","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"LRU\u7f13\u5b58\u673a\u5236","question":{"questionId":"146","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u94fe\u8868\u8fdb\u884c\u63d2\u5165\u6392\u5e8f","question":{"questionId":"147","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f\u94fe\u8868","question":{"questionId":"148","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u4e0a\u6700\u591a\u7684\u70b9\u6570","question":{"questionId":"149","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9006\u6ce2\u5170\u8868\u8fbe\u5f0f\u6c42\u503c","question":{"questionId":"150","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5b57\u7b26\u4e32\u91cc\u7684\u5355\u8bcd","question":{"questionId":"151","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u79ef\u6700\u5927\u5b50\u5e8f\u5217","question":{"questionId":"152","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u6700\u5c0f\u503c","question":{"questionId":"153","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u6700\u5c0f\u503c II","question":{"questionId":"154","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u6808","question":{"questionId":"155","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0a\u4e0b\u7ffb\u8f6c\u4e8c\u53c9\u6811","question":{"questionId":"156","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Read4 \u8bfb\u53d6 N \u4e2a\u5b57\u7b26","question":{"questionId":"157","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Read4 \u8bfb\u53d6 N \u4e2a\u5b57\u7b26 II","question":{"questionId":"158","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u591a\u5305\u542b\u4e24\u4e2a\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"159","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4ea4\u94fe\u8868","question":{"questionId":"160","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u9694\u4e3a 1 \u7684\u7f16\u8f91\u8ddd\u79bb","question":{"questionId":"161","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u5cf0\u503c","question":{"questionId":"162","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u7684\u533a\u95f4","question":{"questionId":"163","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u95f4\u8ddd","question":{"questionId":"164","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u7248\u672c\u53f7","question":{"questionId":"165","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u5230\u5c0f\u6570","question":{"questionId":"166","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c II - \u8f93\u5165\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"167","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Excel\u8868\u5217\u540d\u79f0","question":{"questionId":"168","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u6570\u5143\u7d20","question":{"questionId":"169","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c III - \u6570\u636e\u7ed3\u6784\u8bbe\u8ba1","question":{"questionId":"170","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Excel\u8868\u5217\u5e8f\u53f7","question":{"questionId":"171","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9636\u4e58\u540e\u7684\u96f6","question":{"questionId":"172","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u8fed\u4ee3\u5668","question":{"questionId":"173","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5730\u4e0b\u57ce\u6e38\u620f","question":{"questionId":"174","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u4e24\u4e2a\u8868","question":{"questionId":"175","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e8c\u9ad8\u7684\u85aa\u6c34","question":{"questionId":"176","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cN\u9ad8\u7684\u85aa\u6c34","question":{"questionId":"177","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u6392\u540d","question":{"questionId":"178","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6570","question":{"questionId":"179","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u51fa\u73b0\u7684\u6570\u5b57","question":{"questionId":"180","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u8fc7\u7ecf\u7406\u6536\u5165\u7684\u5458\u5de5","question":{"questionId":"181","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u91cd\u590d\u7684\u7535\u5b50\u90ae\u7bb1","question":{"questionId":"182","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e0d\u8ba2\u8d2d\u7684\u5ba2\u6237","question":{"questionId":"183","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u90e8\u95e8\u5de5\u8d44\u6700\u9ad8\u7684\u5458\u5de5","question":{"questionId":"184","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u90e8\u95e8\u5de5\u8d44\u524d\u4e09\u9ad8\u7684\u6240\u6709\u5458\u5de5","question":{"questionId":"185","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5b57\u7b26\u4e32\u91cc\u7684\u5355\u8bcd II","question":{"questionId":"186","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u7684DNA\u5e8f\u5217","question":{"questionId":"187","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a IV","question":{"questionId":"188","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u6570\u7ec4","question":{"questionId":"189","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u98a0\u5012\u4e8c\u8fdb\u5236\u4f4d","question":{"questionId":"190","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f4d1\u7684\u4e2a\u6570","question":{"questionId":"191","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u8bcd\u9891","question":{"questionId":"192","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7535\u8bdd\u53f7\u7801","question":{"questionId":"193","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u7f6e\u6587\u4ef6","question":{"questionId":"194","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u5341\u884c","question":{"questionId":"195","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u91cd\u590d\u7684\u7535\u5b50\u90ae\u7bb1","question":{"questionId":"196","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0a\u5347\u7684\u6e29\u5ea6","question":{"questionId":"197","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d","question":{"questionId":"198","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u53f3\u89c6\u56fe","question":{"questionId":"199","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u6570\u91cf","question":{"questionId":"200","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u8303\u56f4\u6309\u4f4d\u4e0e","question":{"questionId":"201","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5feb\u4e50\u6570","question":{"questionId":"202","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u94fe\u8868\u5143\u7d20","question":{"questionId":"203","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u6570\u8d28\u6570","question":{"questionId":"204","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u540c\u6784\u5b57\u7b26\u4e32","question":{"questionId":"205","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u94fe\u8868","question":{"questionId":"206","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868","question":{"questionId":"207","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0 Trie (\u524d\u7f00\u6811)","question":{"questionId":"208","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u5ea6\u6700\u5c0f\u7684\u5b50\u6570\u7ec4","question":{"questionId":"209","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868 II","question":{"questionId":"210","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6dfb\u52a0\u4e0e\u641c\u7d22\u5355\u8bcd - \u6570\u636e\u7ed3\u6784\u8bbe\u8ba1","question":{"questionId":"211","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u641c\u7d22 II","question":{"questionId":"212","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d II","question":{"questionId":"213","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u56de\u6587\u4e32","question":{"questionId":"214","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684\u7b2cK\u4e2a\u6700\u5927\u5143\u7d20","question":{"questionId":"215","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c III","question":{"questionId":"216","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20","question":{"questionId":"217","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5929\u9645\u7ebf\u95ee\u9898","question":{"questionId":"218","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20 II","question":{"questionId":"219","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20 III","question":{"questionId":"220","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6b63\u65b9\u5f62","question":{"questionId":"221","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u4e8c\u53c9\u6811\u7684\u8282\u70b9\u4e2a\u6570","question":{"questionId":"222","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u9762\u79ef","question":{"questionId":"223","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668","question":{"questionId":"224","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u961f\u5217\u5b9e\u73b0\u6808","question":{"questionId":"225","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u4e8c\u53c9\u6811","question":{"questionId":"226","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 II","question":{"questionId":"227","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c47\u603b\u533a\u95f4","question":{"questionId":"228","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u4f17\u6570 II","question":{"questionId":"229","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7b2cK\u5c0f\u7684\u5143\u7d20","question":{"questionId":"230","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2\u7684\u5e42","question":{"questionId":"231","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6808\u5b9e\u73b0\u961f\u5217","question":{"questionId":"232","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57 1 \u7684\u4e2a\u6570","question":{"questionId":"233","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u94fe\u8868","question":{"questionId":"234","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"235","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"236","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u94fe\u8868\u4e2d\u7684\u8282\u70b9","question":{"questionId":"237","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u81ea\u8eab\u4ee5\u5916\u6570\u7ec4\u7684\u4e58\u79ef","question":{"questionId":"238","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u7a97\u53e3\u6700\u5927\u503c","question":{"questionId":"239","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u4e8c\u7ef4\u77e9\u9635 II","question":{"questionId":"240","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e3a\u8fd0\u7b97\u8868\u8fbe\u5f0f\u8bbe\u8ba1\u4f18\u5148\u7ea7","question":{"questionId":"241","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5b57\u6bcd\u5f02\u4f4d\u8bcd","question":{"questionId":"242","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb","question":{"questionId":"243","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb II","question":{"questionId":"244","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb III","question":{"questionId":"245","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570","question":{"questionId":"246","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570 II","question":{"questionId":"247","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570 III","question":{"questionId":"248","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u4f4d\u5b57\u7b26\u4e32\u5206\u7ec4","question":{"questionId":"249","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u540c\u503c\u5b50\u6811","question":{"questionId":"250","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c55\u5f00\u4e8c\u7ef4\u5411\u91cf","question":{"questionId":"251","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f1a\u8bae\u5ba4","question":{"questionId":"252","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f1a\u8bae\u5ba4 II","question":{"questionId":"253","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56e0\u5b50\u7684\u7ec4\u5408","question":{"questionId":"254","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u524d\u5e8f\u904d\u5386\u5e8f\u5217\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"255","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u5237\u623f\u5b50","question":{"questionId":"256","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6240\u6709\u8def\u5f84","question":{"questionId":"257","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5404\u4f4d\u76f8\u52a0","question":{"questionId":"258","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f83\u5c0f\u7684\u4e09\u6570\u4e4b\u548c","question":{"questionId":"259","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57 III","question":{"questionId":"260","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ee5\u56fe\u5224\u6811","question":{"questionId":"261","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u7a0b\u548c\u7528\u6237","question":{"questionId":"262","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570","question":{"questionId":"263","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570 II","question":{"questionId":"264","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u5237\u623f\u5b50 II","question":{"questionId":"265","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6392\u5217","question":{"questionId":"266","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6392\u5217 II","question":{"questionId":"267","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u6570\u5b57","question":{"questionId":"268","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706b\u661f\u8bcd\u5178","question":{"questionId":"269","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e8c\u53c9\u641c\u7d22\u6811\u503c","question":{"questionId":"270","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u7f16\u7801\u4e0e\u89e3\u7801","question":{"questionId":"271","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e8c\u53c9\u641c\u7d22\u6811\u503c II","question":{"questionId":"272","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u8f6c\u6362\u82f1\u6587\u8868\u793a","question":{"questionId":"273","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H\u6307\u6570","question":{"questionId":"274","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H\u6307\u6570 II","question":{"questionId":"275","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6805\u680f\u6d82\u8272","question":{"questionId":"276","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u5bfb\u540d\u4eba","question":{"questionId":"277","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e00\u4e2a\u9519\u8bef\u7684\u7248\u672c","question":{"questionId":"278","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u5e73\u65b9\u6570","question":{"questionId":"279","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u6392\u5e8f","question":{"questionId":"280","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952f\u9f7f\u8fed\u4ee3\u5668","question":{"questionId":"281","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u8868\u8fbe\u5f0f\u6dfb\u52a0\u8fd0\u7b97\u7b26","question":{"questionId":"282","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u96f6","question":{"questionId":"283","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9876\u7aef\u8fed\u4ee3\u5668","question":{"questionId":"284","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u987a\u5e8f\u540e\u7ee7","question":{"questionId":"285","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5899\u4e0e\u95e8","question":{"questionId":"286","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u91cd\u590d\u6570","question":{"questionId":"287","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7684\u552f\u4e00\u7f29\u5199","question":{"questionId":"288","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u751f\u547d\u6e38\u620f","question":{"questionId":"289","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u89c4\u5f8b","question":{"questionId":"290","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u89c4\u5f8b II","question":{"questionId":"291","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Nim \u6e38\u620f","question":{"questionId":"292","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u6e38\u620f","question":{"questionId":"293","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u6e38\u620f II","question":{"questionId":"294","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u7684\u4e2d\u4f4d\u6570","question":{"questionId":"295","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u7684\u78b0\u5934\u5730\u70b9","question":{"questionId":"296","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316","question":{"questionId":"297","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u957f\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"298","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u6e38\u620f","question":{"questionId":"299","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u4e0a\u5347\u5b50\u5e8f\u5217","question":{"questionId":"300","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u65e0\u6548\u7684\u62ec\u53f7","question":{"questionId":"301","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5305\u542b\u5168\u90e8\u9ed1\u8272\u50cf\u7d20\u7684\u6700\u5c0f\u77e9\u5f62","question":{"questionId":"302","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u57df\u548c\u68c0\u7d22 - \u6570\u7ec4\u4e0d\u53ef\u53d8","question":{"questionId":"303","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ef4\u533a\u57df\u548c\u68c0\u7d22 - \u77e9\u9635\u4e0d\u53ef\u53d8","question":{"questionId":"304","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u6570\u91cf II","question":{"questionId":"305","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7d2f\u52a0\u6570","question":{"questionId":"306","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u57df\u548c\u68c0\u7d22 - \u6570\u7ec4\u53ef\u4fee\u6539","question":{"questionId":"307","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ef4\u533a\u57df\u548c\u68c0\u7d22 - \u53ef\u53d8","question":{"questionId":"308","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u4e70\u5356\u80a1\u7968\u65f6\u673a\u542b\u51b7\u51bb\u671f","question":{"questionId":"309","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9ad8\u5ea6\u6811","question":{"questionId":"310","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7a00\u758f\u77e9\u9635\u7684\u4e58\u6cd5","question":{"questionId":"311","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6233\u6c14\u7403","question":{"questionId":"312","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u4e11\u6570","question":{"questionId":"313","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5782\u76f4\u904d\u5386","question":{"questionId":"314","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u7b97\u53f3\u4fa7\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\u7684\u4e2a\u6570","question":{"questionId":"315","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53bb\u9664\u91cd\u590d\u5b57\u6bcd","question":{"questionId":"316","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79bb\u5efa\u7b51\u7269\u6700\u8fd1\u7684\u8ddd\u79bb","question":{"questionId":"317","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5355\u8bcd\u957f\u5ea6\u4e58\u79ef","question":{"questionId":"318","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706f\u6ce1\u5f00\u5173","question":{"questionId":"319","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5217\u4e3e\u5355\u8bcd\u7684\u5168\u90e8\u7f29\u5199","question":{"questionId":"320","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u63a5\u6700\u5927\u6570","question":{"questionId":"321","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96f6\u94b1\u5151\u6362","question":{"questionId":"322","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u5411\u56fe\u4e2d\u8fde\u901a\u5206\u91cf\u7684\u6570\u76ee","question":{"questionId":"323","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u6392\u5e8f II","question":{"questionId":"324","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u7b49\u4e8e k \u7684\u6700\u957f\u5b50\u6570\u7ec4\u957f\u5ea6","question":{"questionId":"325","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"3\u7684\u5e42","question":{"questionId":"326","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u548c\u7684\u4e2a\u6570","question":{"questionId":"327","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u5076\u94fe\u8868","question":{"questionId":"328","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u7684\u6700\u957f\u9012\u589e\u8def\u5f84","question":{"questionId":"329","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u8981\u6c42\u8865\u9f50\u6570\u7ec4","question":{"questionId":"330","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u4e8c\u53c9\u6811\u7684\u524d\u5e8f\u5e8f\u5217\u5316","question":{"questionId":"331","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u5b89\u6392\u884c\u7a0b","question":{"questionId":"332","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927 BST \u5b50\u6811","question":{"questionId":"333","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u7684\u4e09\u5143\u5b50\u5e8f\u5217","question":{"questionId":"334","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u4ea4\u53c9","question":{"questionId":"335","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u5bf9","question":{"questionId":"336","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d III","question":{"questionId":"337","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u7279\u4f4d\u8ba1\u6570","question":{"questionId":"338","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5d4c\u5957\u5217\u8868\u6743\u91cd\u548c","question":{"questionId":"339","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u591a\u5305\u542b K \u4e2a\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"340","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6241\u5e73\u5316\u5d4c\u5957\u5217\u8868\u8fed\u4ee3\u5668","question":{"questionId":"341","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"4\u7684\u5e42","question":{"questionId":"342","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u62c6\u5206","question":{"questionId":"343","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32","question":{"questionId":"344","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u97f3\u5b57\u6bcd","question":{"questionId":"345","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u4e2d\u7684\u79fb\u52a8\u5e73\u5747\u503c","question":{"questionId":"346","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d K \u4e2a\u9ad8\u9891\u5143\u7d20","question":{"questionId":"347","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u5b9a\u4e95\u5b57\u68cb\u80dc\u8d1f","question":{"questionId":"348","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u6570\u7ec4\u7684\u4ea4\u96c6","question":{"questionId":"349","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u6570\u7ec4\u7684\u4ea4\u96c6 II","question":{"questionId":"350","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u5353\u7cfb\u7edf\u624b\u52bf\u89e3\u9501","question":{"questionId":"351","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u636e\u6d41\u53d8\u4e3a\u591a\u4e2a\u4e0d\u76f8\u4ea4\u533a\u95f4","question":{"questionId":"352","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d2a\u5403\u86c7","question":{"questionId":"353","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fc4\u7f57\u65af\u5957\u5a03\u4fe1\u5c01\u95ee\u9898","question":{"questionId":"354","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u63a8\u7279","question":{"questionId":"355","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u955c\u50cf","question":{"questionId":"356","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u7b97\u5404\u4e2a\u4f4d\u6570\u4e0d\u540c\u7684\u6570\u5b57\u4e2a\u6570","question":{"questionId":"357","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u8ddd\u79bb\u95f4\u9694\u91cd\u6392\u5b57\u7b26\u4e32","question":{"questionId":"358","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e5\u5fd7\u901f\u7387\u9650\u5236\u5668","question":{"questionId":"359","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u8f6c\u5316\u6570\u7ec4","question":{"questionId":"360","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f70\u70b8\u654c\u4eba","question":{"questionId":"361","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6572\u51fb\u8ba1\u6570\u5668","question":{"questionId":"362","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u533a\u57df\u4e0d\u8d85\u8fc7 K \u7684\u6700\u5927\u6570\u503c\u548c","question":{"questionId":"363","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u6743\u5d4c\u5957\u5e8f\u5217\u548c II","question":{"questionId":"364","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u58f6\u95ee\u9898","question":{"questionId":"365","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u5b8c\u5168\u4e8c\u53c9\u6811\u7684\u53f6\u5b50\u8282\u70b9","question":{"questionId":"366","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5b8c\u5168\u5e73\u65b9\u6570","question":{"questionId":"367","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6574\u9664\u5b50\u96c6","question":{"questionId":"368","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5355\u94fe\u8868\u52a0\u4e00","question":{"questionId":"369","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u52a0\u6cd5","question":{"questionId":"370","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6574\u6570\u4e4b\u548c","question":{"questionId":"371","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u6b21\u65b9","question":{"questionId":"372","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u548c\u6700\u5c0f\u7684K\u5bf9\u6570\u5b57","question":{"questionId":"373","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u5927\u5c0f","question":{"questionId":"374","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u5927\u5c0f II","question":{"questionId":"375","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u5e8f\u5217","question":{"questionId":"376","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c \u2163","question":{"questionId":"377","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u77e9\u9635\u4e2d\u7b2cK\u5c0f\u7684\u5143\u7d20","question":{"questionId":"378","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7535\u8bdd\u76ee\u5f55\u7ba1\u7406\u7cfb\u7edf","question":{"questionId":"379","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e38\u6570\u65f6\u95f4\u63d2\u5165\u3001\u5220\u9664\u548c\u83b7\u53d6\u968f\u673a\u5143\u7d20","question":{"questionId":"380","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"O(1) \u65f6\u95f4\u63d2\u5165\u3001\u5220\u9664\u548c\u83b7\u53d6\u968f\u673a\u5143\u7d20 - \u5141\u8bb8\u91cd\u590d","question":{"questionId":"381","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u968f\u673a\u8282\u70b9","question":{"questionId":"382","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d4e\u91d1\u4fe1","question":{"questionId":"383","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u4e71\u6570\u7ec4","question":{"questionId":"384","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u4f60\u8bed\u6cd5\u5206\u6790\u5668","question":{"questionId":"385","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u5178\u5e8f\u6392\u6570","question":{"questionId":"386","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u7b2c\u4e00\u4e2a\u552f\u4e00\u5b57\u7b26","question":{"questionId":"387","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u4ef6\u7684\u6700\u957f\u7edd\u5bf9\u8def\u5f84","question":{"questionId":"388","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u4e0d\u540c","question":{"questionId":"389","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d88\u9664\u6e38\u620f","question":{"questionId":"390","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u7f8e\u77e9\u5f62","question":{"questionId":"391","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u5b50\u5e8f\u5217","question":{"questionId":"392","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"UTF-8 \u7f16\u7801\u9a8c\u8bc1","question":{"questionId":"393","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u89e3\u7801","question":{"questionId":"394","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u6709K\u4e2a\u91cd\u590d\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"395","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u51fd\u6570","question":{"questionId":"396","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u66ff\u6362","question":{"questionId":"397","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u968f\u673a\u6570\u7d22\u5f15","question":{"questionId":"398","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u6cd5\u6c42\u503c","question":{"questionId":"399","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cN\u4e2a\u6570\u5b57","question":{"questionId":"400","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u624b\u8868","question":{"questionId":"401","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u6389K\u4f4d\u6570\u5b57","question":{"questionId":"402","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9752\u86d9\u8fc7\u6cb3","question":{"questionId":"403","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5de6\u53f6\u5b50\u4e4b\u548c","question":{"questionId":"404","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u8f6c\u6362\u4e3a\u5341\u516d\u8fdb\u5236\u6570","question":{"questionId":"405","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u8eab\u9ad8\u91cd\u5efa\u961f\u5217","question":{"questionId":"406","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a5\u96e8\u6c34 II","question":{"questionId":"407","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u5355\u8bcd\u7f29\u5199","question":{"questionId":"408","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u4e32","question":{"questionId":"409","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4\u7684\u6700\u5927\u503c","question":{"questionId":"410","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u7279\u5f02\u5355\u8bcd\u7f29\u5199","question":{"questionId":"411","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Fizz Buzz","question":{"questionId":"412","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u5212\u5206","question":{"questionId":"413","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e09\u5927\u7684\u6570","question":{"questionId":"414","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u76f8\u52a0","question":{"questionId":"415","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u7b49\u548c\u5b50\u96c6","question":{"questionId":"416","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u592a\u5e73\u6d0b\u5927\u897f\u6d0b\u6c34\u6d41\u95ee\u9898","question":{"questionId":"417","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c4f\u5e55\u53ef\u663e\u793a\u53e5\u5b50\u7684\u6570\u91cf","question":{"questionId":"418","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7532\u677f\u4e0a\u7684\u6218\u8230","question":{"questionId":"419","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f3a\u5bc6\u7801\u68c0\u9a8c\u5668","question":{"questionId":"420","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u4e24\u4e2a\u6570\u7684\u6700\u5927\u5f02\u6216\u503c","question":{"questionId":"421","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5355\u8bcd\u65b9\u5757","question":{"questionId":"422","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u82f1\u6587\u4e2d\u91cd\u5efa\u6570\u5b57","question":{"questionId":"423","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u66ff\u6362\u540e\u7684\u6700\u957f\u91cd\u590d\u5b57\u7b26","question":{"questionId":"424","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u65b9\u5757","question":{"questionId":"425","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168 O(1) \u7684\u6570\u636e\u7ed3\u6784","question":{"questionId":"432","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u57fa\u56e0\u53d8\u5316","question":{"questionId":"433","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u8bcd\u6570","question":{"questionId":"434","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u91cd\u53e0\u533a\u95f4","question":{"questionId":"435","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u53f3\u533a\u95f4","question":{"questionId":"436","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c III","question":{"questionId":"437","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u5b57\u6bcd\u5f02\u4f4d\u8bcd","question":{"questionId":"438","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u5143\u8868\u8fbe\u5f0f\u89e3\u6790\u5668","question":{"questionId":"439","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u5178\u5e8f\u7684\u7b2cK\u5c0f\u6570\u5b57","question":{"questionId":"440","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5217\u786c\u5e01","question":{"questionId":"441","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u91cd\u590d\u7684\u6570\u636e","question":{"questionId":"442","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u538b\u7f29\u5b57\u7b26\u4e32","question":{"questionId":"443","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u91cd\u5efa","question":{"questionId":"444","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u52a0 II","question":{"questionId":"445","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u5212\u5206 II - \u5b50\u5e8f\u5217","question":{"questionId":"446","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u65cb\u9556\u7684\u6570\u91cf","question":{"questionId":"447","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u6240\u6709\u6570\u7ec4\u4e2d\u6d88\u5931\u7684\u6570\u5b57","question":{"questionId":"448","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u5316\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"449","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u8282\u70b9","question":{"questionId":"450","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u5b57\u7b26\u51fa\u73b0\u9891\u7387\u6392\u5e8f","question":{"questionId":"451","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6700\u5c11\u6570\u91cf\u7684\u7bad\u5f15\u7206\u6c14\u7403","question":{"questionId":"452","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u79fb\u52a8\u6b21\u6570\u4f7f\u6570\u7ec4\u5143\u7d20\u76f8\u7b49","question":{"questionId":"453","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u6570\u76f8\u52a0 II","question":{"questionId":"454","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u53d1\u997c\u5e72","question":{"questionId":"455","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"132\u6a21\u5f0f","question":{"questionId":"456","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u6570\u7ec4\u5faa\u73af","question":{"questionId":"457","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u601c\u7684\u5c0f\u732a","question":{"questionId":"458","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u7684\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"459","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"LFU\u7f13\u5b58","question":{"questionId":"460","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c49\u660e\u8ddd\u79bb","question":{"questionId":"461","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c11\u79fb\u52a8\u6b21\u6570\u4f7f\u6570\u7ec4\u5143\u7d20\u76f8\u7b49 II","question":{"questionId":"462","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u7684\u5468\u957f","question":{"questionId":"463","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u80fd\u8d62\u5417","question":{"questionId":"464","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f18\u8d26\u5355\u5e73\u8861","question":{"questionId":"465","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u91cd\u590d\u4e2a\u6570","question":{"questionId":"466","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u7ed5\u5b57\u7b26\u4e32\u4e2d\u552f\u4e00\u7684\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"467","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1IP\u5730\u5740","question":{"questionId":"468","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51f8\u591a\u8fb9\u5f62","question":{"questionId":"469","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f16\u7801\u6700\u77ed\u957f\u5ea6\u7684\u5b57\u7b26\u4e32","question":{"questionId":"471","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u63a5\u8bcd","question":{"questionId":"472","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706b\u67f4\u62fc\u6b63\u65b9\u5f62","question":{"questionId":"473","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u548c\u96f6","question":{"questionId":"474","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f9b\u6696\u5668","question":{"questionId":"475","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u7684\u8865\u6570","question":{"questionId":"476","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c49\u660e\u8ddd\u79bb\u603b\u548c","question":{"questionId":"477","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u56de\u6587\u6570\u4e58\u79ef","question":{"questionId":"479","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u7a97\u53e3\u4e2d\u4f4d\u6570","question":{"questionId":"480","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u795e\u5947\u5b57\u7b26\u4e32","question":{"questionId":"481","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bc6\u94a5\u683c\u5f0f\u5316","question":{"questionId":"482","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u597d\u8fdb\u5236","question":{"questionId":"483","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6392\u5217","question":{"questionId":"484","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570","question":{"questionId":"485","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9884\u6d4b\u8d62\u5bb6","question":{"questionId":"486","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570 II","question":{"questionId":"487","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7956\u739b\u6e38\u620f","question":{"questionId":"488","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab","question":{"questionId":"490","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u5b50\u5e8f\u5217","question":{"questionId":"491","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6784\u9020\u77e9\u5f62","question":{"questionId":"492","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5bf9","question":{"questionId":"493","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76ee\u6807\u548c","question":{"questionId":"494","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63d0\u83ab\u653b\u51fb","question":{"questionId":"495","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 I","question":{"questionId":"496","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u89d2\u7ebf\u904d\u5386","question":{"questionId":"498","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab III","question":{"questionId":"499","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952e\u76d8\u884c","question":{"questionId":"500","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u4f17\u6570","question":{"questionId":"501","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IPO","question":{"questionId":"502","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 II","question":{"questionId":"503","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e03\u8fdb\u5236\u6570","question":{"questionId":"504","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab II","question":{"questionId":"505","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u5bf9\u540d\u6b21","question":{"questionId":"506","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u7f8e\u6570","question":{"questionId":"507","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fa\u73b0\u6b21\u6570\u6700\u591a\u7684\u5b50\u6811\u5143\u7d20\u548c","question":{"questionId":"508","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u4e2d\u5e8f\u540e\u7ee7 II","question":{"questionId":"509","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u59cb\u70b9\u5230\u7ec8\u70b9\u7684\u6240\u6709\u8def\u5f84","question":{"questionId":"511","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u6811\u5de6\u4e0b\u89d2\u7684\u503c","question":{"questionId":"513","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u7531\u4e4b\u8def","question":{"questionId":"514","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u6bcf\u4e2a\u6811\u884c\u4e2d\u627e\u6700\u5927\u503c","question":{"questionId":"515","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u5b50\u5e8f\u5217","question":{"questionId":"516","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u6d17\u8863\u673a","question":{"questionId":"517","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96f6\u94b1\u5151\u6362 II","question":{"questionId":"518","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u6d4b\u5927\u5199\u5b57\u6bcd","question":{"questionId":"520","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7279\u6b8a\u5e8f\u5217 \u2160","question":{"questionId":"521","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7279\u6b8a\u5e8f\u5217 II","question":{"questionId":"522","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u7684\u5b50\u6570\u7ec4\u548c","question":{"questionId":"523","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u901a\u8fc7\u5220\u9664\u5b57\u6bcd\u5339\u914d\u5230\u5b57\u5178\u91cc\u6700\u957f\u5355\u8bcd","question":{"questionId":"524","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u6570\u7ec4","question":{"questionId":"525","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u7f8e\u7684\u6392\u5217","question":{"questionId":"526","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7f29\u5199","question":{"questionId":"527","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u626b\u96f7\u6e38\u620f","question":{"questionId":"529","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u6700\u5c0f\u7edd\u5bf9\u5dee","question":{"questionId":"530","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b64\u72ec\u50cf\u7d20 I","question":{"questionId":"531","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684K-diff\u6570\u5bf9","question":{"questionId":"532","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b64\u72ec\u50cf\u7d20 II","question":{"questionId":"533","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"TinyURL \u7684\u52a0\u5bc6\u4e0e\u89e3\u5bc6","question":{"questionId":"535","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u5b57\u7b26\u4e32\u751f\u6210\u4e8c\u53c9\u6811","question":{"questionId":"536","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u6570\u4e58\u6cd5","question":{"questionId":"537","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u628a\u4e8c\u53c9\u641c\u7d22\u6811\u8f6c\u6362\u4e3a\u7d2f\u52a0\u6811","question":{"questionId":"538","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u65f6\u95f4\u5dee","question":{"questionId":"539","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u4e2d\u7684\u5355\u4e00\u5143\u7d20","question":{"questionId":"540","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32 II","question":{"questionId":"541","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"01 \u77e9\u9635","question":{"questionId":"542","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u76f4\u5f84","question":{"questionId":"543","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f93\u51fa\u6bd4\u8d5b\u5339\u914d\u5bf9","question":{"questionId":"544","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u8fb9\u754c","question":{"questionId":"545","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u76d2\u5b50","question":{"questionId":"546","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u670b\u53cb\u5708","question":{"questionId":"547","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u5272\u6210\u548c\u76f8\u7b49\u7684\u5b50\u6570\u7ec4","question":{"questionId":"548","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u6700\u957f\u7684\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"549","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u51fa\u52e4\u8bb0\u5f55 I","question":{"questionId":"551","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u51fa\u52e4\u8bb0\u5f55 II","question":{"questionId":"552","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f18\u9664\u6cd5","question":{"questionId":"553","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7816\u5899","question":{"questionId":"554","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u8fde\u63a5\u5b57\u7b26\u4e32","question":{"questionId":"555","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 III","question":{"questionId":"556","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u8bcd III","question":{"questionId":"557","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u4e3aK\u7684\u5b50\u6570\u7ec4","question":{"questionId":"560","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u62c6\u5206 I","question":{"questionId":"561","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u6700\u957f\u7684\u8fde\u7eed1\u7ebf\u6bb5","question":{"questionId":"562","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5761\u5ea6","question":{"questionId":"563","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6700\u8fd1\u7684\u56de\u6587\u6570","question":{"questionId":"564","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5d4c\u5957","question":{"questionId":"565","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u5851\u77e9\u9635","question":{"questionId":"566","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u6392\u5217","question":{"questionId":"567","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4f11\u5047\u5929\u6570","question":{"questionId":"568","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u85aa\u6c34\u4e2d\u4f4d\u6570","question":{"questionId":"569","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u67095\u540d\u76f4\u63a5\u4e0b\u5c5e\u7684\u7ecf\u7406","question":{"questionId":"570","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b9a\u6570\u5b57\u7684\u9891\u7387\u67e5\u8be2\u4e2d\u4f4d\u6570","question":{"questionId":"571","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e6\u4e00\u4e2a\u6811\u7684\u5b50\u6811","question":{"questionId":"572","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u677e\u9f20\u6a21\u62df","question":{"questionId":"573","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f53\u9009\u8005","question":{"questionId":"574","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u7cd6\u679c","question":{"questionId":"575","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fa\u754c\u7684\u8def\u5f84\u6570","question":{"questionId":"576","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u5956\u91d1","question":{"questionId":"577","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u56de\u7b54\u7387\u6700\u9ad8\u7684\u95ee\u9898","question":{"questionId":"578","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u5458\u5de5\u7684\u7d2f\u8ba1\u85aa\u6c34","question":{"questionId":"579","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5404\u4e13\u4e1a\u5b66\u751f\u4eba\u6570","question":{"questionId":"580","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u65e0\u5e8f\u8fde\u7eed\u5b50\u6570\u7ec4","question":{"questionId":"581","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6740\u6b7b\u8fdb\u7a0b","question":{"questionId":"582","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5b57\u7b26\u4e32\u7684\u5220\u9664\u64cd\u4f5c","question":{"questionId":"583","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u7528\u6237\u63a8\u8350\u4eba","question":{"questionId":"584","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2016\u5e74\u7684\u6295\u8d44","question":{"questionId":"585","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba2\u5355\u6700\u591a\u7684\u5ba2\u6237","question":{"questionId":"586","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u88c5\u6805\u680f","question":{"questionId":"587","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5185\u5b58\u6587\u4ef6\u7cfb\u7edf","question":{"questionId":"588","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6807\u7b7e\u9a8c\u8bc1\u5668","question":{"questionId":"591","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u52a0\u51cf\u8fd0\u7b97","question":{"questionId":"592","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u6b63\u65b9\u5f62","question":{"questionId":"593","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u548c\u8c10\u5b50\u5e8f\u5217","question":{"questionId":"594","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u7684\u56fd\u5bb6","question":{"questionId":"595","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u8fc75\u540d\u5b66\u751f\u7684\u8bfe","question":{"questionId":"596","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u597d\u53cb\u7533\u8bf7 I \uff1a\u603b\u4f53\u901a\u8fc7\u7387","question":{"questionId":"597","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8303\u56f4\u6c42\u548c II","question":{"questionId":"598","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5217\u8868\u7684\u6700\u5c0f\u7d22\u5f15\u603b\u548c","question":{"questionId":"599","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u542b\u8fde\u7eed1\u7684\u975e\u8d1f\u6574\u6570","question":{"questionId":"600","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f53\u80b2\u9986\u7684\u4eba\u6d41\u91cf","question":{"questionId":"601","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u597d\u53cb\u7533\u8bf7 II \uff1a\u8c01\u6709\u6700\u591a\u7684\u597d\u53cb","question":{"questionId":"602","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u7a7a\u4f59\u5ea7\u4f4d","question":{"questionId":"603","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fed\u4ee3\u538b\u7f29\u5b57\u7b26\u4e32","question":{"questionId":"604","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79cd\u82b1\u95ee\u9898","question":{"questionId":"605","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u4e8c\u53c9\u6811\u521b\u5efa\u5b57\u7b26\u4e32","question":{"questionId":"606","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5458","question":{"questionId":"607","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6811\u8282\u70b9","question":{"questionId":"608","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u7cfb\u7edf\u4e2d\u67e5\u627e\u91cd\u590d\u6587\u4ef6","question":{"questionId":"609","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u4e09\u89d2\u5f62","question":{"questionId":"610","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u4e09\u89d2\u5f62\u7684\u4e2a\u6570","question":{"questionId":"611","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u9762\u4e0a\u7684\u6700\u8fd1\u8ddd\u79bb","question":{"questionId":"612","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u4e0a\u7684\u6700\u8fd1\u8ddd\u79bb","question":{"questionId":"613","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ea7\u5173\u6ce8\u8005","question":{"questionId":"614","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u5747\u5de5\u8d44\uff1a\u90e8\u95e8\u4e0e\u516c\u53f8\u6bd4\u8f83","question":{"questionId":"615","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b57\u7b26\u4e32\u6dfb\u52a0\u52a0\u7c97\u6807\u7b7e","question":{"questionId":"616","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e8c\u53c9\u6811","question":{"questionId":"617","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u5730\u7406\u4fe1\u606f\u62a5\u544a","question":{"questionId":"618","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6700\u5927\u6570\u5b57","question":{"questionId":"619","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u8da3\u7684\u7535\u5f71","question":{"questionId":"620","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4efb\u52a1\u8c03\u5ea6\u5668","question":{"questionId":"621","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u4e8c\u53c9\u6811\u4e2d\u589e\u52a0\u4e00\u884c","question":{"questionId":"623","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5217\u8868\u4e2d\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"624","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u56e0\u5f0f\u5206\u89e3","question":{"questionId":"625","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6362\u5ea7\u4f4d","question":{"questionId":"626","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u5de5\u8d44","question":{"questionId":"627","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u6570\u7684\u6700\u5927\u4e58\u79ef","question":{"questionId":"628","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K\u4e2a\u9006\u5e8f\u5bf9\u6570\u7ec4","question":{"questionId":"629","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868 III","question":{"questionId":"630","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1 Excel \u6c42\u548c\u516c\u5f0f","question":{"questionId":"631","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u533a\u95f4","question":{"questionId":"632","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u65b9\u6570\u4e4b\u548c","question":{"questionId":"633","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6570\u7ec4\u7684\u9519\u4f4d\u6392\u5217","question":{"questionId":"634","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u65e5\u5fd7\u5b58\u50a8\u7cfb\u7edf","question":{"questionId":"635","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fd\u6570\u7684\u72ec\u5360\u65f6\u95f4","question":{"questionId":"636","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u5e73\u5747\u503c","question":{"questionId":"637","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u793c\u5305","question":{"questionId":"638","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u7801\u65b9\u6cd5 2","question":{"questionId":"639","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u89e3\u65b9\u7a0b","question":{"questionId":"640","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u641c\u7d22\u81ea\u52a8\u8865\u5168\u7cfb\u7edf","question":{"questionId":"642","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u6700\u5927\u5e73\u5747\u6570 I","question":{"questionId":"643","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5e73\u5747\u5b50\u6bb5\u548c II","question":{"questionId":"644","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9519\u8bef\u7684\u96c6\u5408","question":{"questionId":"645","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6570\u5bf9\u94fe","question":{"questionId":"646","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u5b50\u4e32","question":{"questionId":"647","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u66ff\u6362","question":{"questionId":"648","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Dota2 \u53c2\u8bae\u9662","question":{"questionId":"649","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u6709\u4e24\u4e2a\u952e\u7684\u952e\u76d8","question":{"questionId":"650","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"4\u952e\u952e\u76d8","question":{"questionId":"651","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u91cd\u590d\u7684\u5b50\u6811","question":{"questionId":"652","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c IV - \u8f93\u5165 BST","question":{"questionId":"653","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e8c\u53c9\u6811","question":{"questionId":"654","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f93\u51fa\u4e8c\u53c9\u6811","question":{"questionId":"655","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91d1\u5e01\u8def\u5f84","question":{"questionId":"656","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u673a\u5668\u4eba\u80fd\u5426\u8fd4\u56de\u539f\u70b9","question":{"questionId":"657","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230 K \u4e2a\u6700\u63a5\u8fd1\u7684\u5143\u7d20","question":{"questionId":"658","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4\u4e3a\u8fde\u7eed\u5b50\u5e8f\u5217","question":{"questionId":"659","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664 9","question":{"questionId":"660","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u7247\u5e73\u6ed1\u5668","question":{"questionId":"661","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u5927\u5bbd\u5ea6","question":{"questionId":"662","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5747\u5300\u6811\u5212\u5206","question":{"questionId":"663","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u602a\u7684\u6253\u5370\u673a","question":{"questionId":"664","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u975e\u9012\u51cf\u6570\u5217","question":{"questionId":"665","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u548c IV","question":{"questionId":"666","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u7f8e\u7684\u6392\u5217 II","question":{"questionId":"667","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u6cd5\u8868\u4e2d\u7b2ck\u5c0f\u7684\u6570","question":{"questionId":"668","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fee\u526a\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"669","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4ea4\u6362","question":{"questionId":"670","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u7b2c\u4e8c\u5c0f\u7684\u8282\u70b9","question":{"questionId":"671","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706f\u6ce1\u5f00\u5173 \u2161","question":{"questionId":"672","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u9012\u589e\u5b50\u5e8f\u5217\u7684\u4e2a\u6570","question":{"questionId":"673","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u8fde\u7eed\u9012\u589e\u5e8f\u5217","question":{"questionId":"674","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e3a\u9ad8\u5c14\u592b\u6bd4\u8d5b\u780d\u6811","question":{"questionId":"675","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0\u4e00\u4e2a\u9b54\u6cd5\u5b57\u5178","question":{"questionId":"676","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952e\u503c\u6620\u5c04","question":{"questionId":"677","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u62ec\u53f7\u5b57\u7b26\u4e32","question":{"questionId":"678","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"24 \u70b9\u6e38\u620f","question":{"questionId":"679","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u5b57\u7b26\u4e32 \u2161","question":{"questionId":"680","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u8fd1\u65f6\u523b","question":{"questionId":"681","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68d2\u7403\u6bd4\u8d5b","question":{"questionId":"682","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u7a7a\u82b1\u76c6","question":{"questionId":"683","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5197\u4f59\u8fde\u63a5","question":{"questionId":"684","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5197\u4f59\u8fde\u63a5 II","question":{"questionId":"685","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u53e0\u52a0\u5b57\u7b26\u4e32\u5339\u914d","question":{"questionId":"686","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u540c\u503c\u8def\u5f84","question":{"questionId":"687","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u201c\u9a6c\u201d\u5728\u68cb\u76d8\u4e0a\u7684\u6982\u7387","question":{"questionId":"688","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u65e0\u91cd\u53e0\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"689","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u7684\u91cd\u8981\u6027","question":{"questionId":"690","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d34\u7eb8\u62fc\u8bcd","question":{"questionId":"691","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524dK\u4e2a\u9ad8\u9891\u5355\u8bcd","question":{"questionId":"692","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u4f4d\u4e8c\u8fdb\u5236\u6570","question":{"questionId":"693","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5c9b\u5c7f\u7684\u6570\u91cf","question":{"questionId":"694","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u7684\u6700\u5927\u9762\u79ef","question":{"questionId":"695","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u6570\u4e8c\u8fdb\u5236\u5b50\u4e32","question":{"questionId":"696","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u5ea6","question":{"questionId":"697","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5212\u5206\u4e3ak\u4e2a\u76f8\u7b49\u7684\u5b50\u96c6","question":{"questionId":"698","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6389\u843d\u7684\u65b9\u5757","question":{"questionId":"699","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5c9b\u5c7f\u7684\u6570\u91cf II","question":{"questionId":"711","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5b57\u7b26\u4e32\u7684\u6700\u5c0fASCII\u5220\u9664\u548c","question":{"questionId":"712","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u79ef\u5c0f\u4e8eK\u7684\u5b50\u6570\u7ec4","question":{"questionId":"713","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a\u542b\u624b\u7eed\u8d39","question":{"questionId":"714","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Range \u6a21\u5757","question":{"questionId":"715","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6808","question":{"questionId":"716","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"1\u6bd4\u7279\u4e0e2\u6bd4\u7279\u5b57\u7b26","question":{"questionId":"717","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u6570\u7ec4","question":{"questionId":"718","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u7b2c k \u5c0f\u7684\u8ddd\u79bb\u5bf9","question":{"questionId":"719","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bcd\u5178\u4e2d\u6700\u957f\u7684\u5355\u8bcd","question":{"questionId":"720","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d26\u6237\u5408\u5e76","question":{"questionId":"721","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6ce8\u91ca","question":{"questionId":"722","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u788e\u7cd6\u679c","question":{"questionId":"723","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6570\u7ec4\u7684\u4e2d\u5fc3\u7d22\u5f15","question":{"questionId":"724","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u94fe\u8868","question":{"questionId":"725","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u539f\u5b50\u7684\u6570\u91cf","question":{"questionId":"726","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7a97\u53e3\u5b50\u5e8f\u5217","question":{"questionId":"727","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u9664\u6570","question":{"questionId":"728","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 I","question":{"questionId":"729","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u4e0d\u540c\u56de\u6587\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"730","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 II","question":{"questionId":"731","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 III","question":{"questionId":"732","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u50cf\u6e32\u67d3","question":{"questionId":"733","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e5\u5b50\u76f8\u4f3c\u6027","question":{"questionId":"734","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u661f\u78b0\u649e","question":{"questionId":"735","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Lisp \u8bed\u6cd5\u89e3\u6790","question":{"questionId":"736","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e5\u5b50\u76f8\u4f3c\u6027 II","question":{"questionId":"737","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8c03\u9012\u589e\u7684\u6570\u5b57","question":{"questionId":"738","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u65e5\u6e29\u5ea6","question":{"questionId":"739","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e0e\u83b7\u5f97\u70b9\u6570","question":{"questionId":"740","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6458\u6a31\u6843","question":{"questionId":"741","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u6362\u6210\u5c0f\u5199\u5b57\u6bcd","question":{"questionId":"742","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u8fd1\u7684\u53f6\u8282\u70b9","question":{"questionId":"743","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f51\u7edc\u5ef6\u8fdf\u65f6\u95f4","question":{"questionId":"744","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6bd4\u76ee\u6807\u5b57\u6bcd\u5927\u7684\u6700\u5c0f\u5b57\u6bcd","question":{"questionId":"745","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u7f00\u548c\u540e\u7f00\u641c\u7d22","question":{"questionId":"746","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u7528\u6700\u5c0f\u82b1\u8d39\u722c\u697c\u68af","question":{"questionId":"747","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u662f\u5176\u4ed6\u6570\u5b57\u4e24\u500d\u7684\u6700\u5927\u6570","question":{"questionId":"748","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5b8c\u6574\u8bcd","question":{"questionId":"749","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9694\u79bb\u75c5\u6bd2","question":{"questionId":"750","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89d2\u77e9\u5f62\u7684\u6570\u91cf","question":{"questionId":"751","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IP \u5230 CIDR","question":{"questionId":"752","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5f00\u8f6c\u76d8\u9501","question":{"questionId":"753","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7834\u89e3\u4fdd\u9669\u7bb1","question":{"questionId":"754","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u8fbe\u7ec8\u70b9\u6570\u5b57","question":{"questionId":"755","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5012\u6c34","question":{"questionId":"756","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91d1\u5b57\u5854\u8f6c\u6362\u77e9\u9635","question":{"questionId":"757","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u4e8c\u53c9\u641c\u7d22\u6811\u8f6c\u5316\u4e3a\u6392\u5e8f\u7684\u53cc\u5411\u94fe\u8868","question":{"questionId":"758","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":" \u8bbe\u7f6e\u4ea4\u96c6\u5927\u5c0f\u81f3\u5c11\u4e3a2","question":{"questionId":"759","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u52a0\u7c97\u5355\u8bcd","question":{"questionId":"760","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u7a7a\u95f2\u65f6\u95f4","question":{"questionId":"761","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u53d8\u4f4d\u6620\u5c04","question":{"questionId":"762","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7279\u6b8a\u7684\u4e8c\u8fdb\u5236\u5e8f\u5217","question":{"questionId":"763","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u5c42\u5e8f\u904d\u5386","question":{"questionId":"764","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u5316 N \u53c9\u6811","question":{"questionId":"765","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6241\u5e73\u5316\u591a\u7ea7\u53cc\u5411\u94fe\u8868","question":{"questionId":"766","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u8868\u793a\u4e2d\u8d28\u6570\u4e2a\u8ba1\u7b97\u7f6e\u4f4d","question":{"questionId":"767","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5212\u5206\u5b57\u6bcd\u533a\u95f4","question":{"questionId":"768","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u52a0\u53f7\u6807\u5fd7","question":{"questionId":"769","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u60c5\u4fa3\u7275\u624b","question":{"questionId":"770","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06 N \u53c9\u6811\u7f16\u7801\u4e3a\u4e8c\u53c9\u6811","question":{"questionId":"771","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5efa\u7acb\u56db\u53c9\u6811","question":{"questionId":"772","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u53c9\u6811\u4ea4\u96c6","question":{"questionId":"773","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u6700\u5927\u6df1\u5ea6","question":{"questionId":"774","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u524d\u5e8f\u904d\u5386","question":{"questionId":"775","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u540e\u5e8f\u904d\u5386","question":{"questionId":"776","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6258\u666e\u5229\u8328\u77e9\u9635","question":{"questionId":"777","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u6784\u5b57\u7b26\u4e32","question":{"questionId":"778","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u80fd\u5b8c\u6210\u6392\u5e8f\u7684\u5757 II","question":{"questionId":"779","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u80fd\u5b8c\u6210\u6392\u5e8f\u7684\u5757","question":{"questionId":"780","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 IV","question":{"questionId":"781","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9d\u77f3\u4e0e\u77f3\u5934","question":{"questionId":"782","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u641c\u7d22","question":{"questionId":"783","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u63d2\u5165\u64cd\u4f5c","question":{"questionId":"784","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 III","question":{"questionId":"785","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u957f\u5ea6\u672a\u77e5\u7684\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"786","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u8c1c\u9898","question":{"questionId":"787","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5316\u53bb\u52a0\u6cb9\u7ad9\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"788","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u4e2d\u7684\u7b2cK\u5927\u5143\u7d20","question":{"questionId":"789","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u5c40\u5012\u7f6e\u4e0e\u5c40\u90e8\u5012\u7f6e","question":{"questionId":"790","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62c6\u5206\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"791","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u5206\u67e5\u627e","question":{"questionId":"792","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728LR\u5b57\u7b26\u4e32\u4e2d\u4ea4\u6362\u76f8\u90bb\u5b57\u7b26","question":{"questionId":"793","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u4f4d\u4e0a\u5347\u7684\u6cf3\u6c60\u4e2d\u6e38\u6cf3","question":{"questionId":"794","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cK\u4e2a\u8bed\u6cd5\u7b26\u53f7","question":{"questionId":"795","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u8fbe\u7ec8\u70b9","question":{"questionId":"796","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68ee\u6797\u4e2d\u7684\u5154\u5b50","question":{"questionId":"797","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d8\u4e3a\u68cb\u76d8","question":{"questionId":"798","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7ed3\u70b9\u6700\u5c0f\u8ddd\u79bb","question":{"questionId":"799","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5927\u5c0f\u5199\u5168\u6392\u5217","question":{"questionId":"800","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u4e8c\u5206\u56fe","question":{"questionId":"801","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c K \u4e2a\u6700\u5c0f\u7684\u7d20\u6570\u5206\u6570","question":{"questionId":"802","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u7ad9\u4e2d\u8f6c\u5185\u6700\u4fbf\u5b9c\u7684\u822a\u73ed","question":{"questionId":"803","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u6570\u5b57","question":{"questionId":"804","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9003\u8131\u963b\u788d\u8005","question":{"questionId":"805","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u7c73\u8bfa\u548c\u6258\u7c73\u8bfa\u5e73\u94fa","question":{"questionId":"806","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u5b9a\u4e49\u5b57\u7b26\u4e32\u6392\u5e8f","question":{"questionId":"807","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5339\u914d\u5b50\u5e8f\u5217\u7684\u5355\u8bcd\u6570","question":{"questionId":"808","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9636\u4e58\u51fd\u6570\u540eK\u4e2a\u96f6","question":{"questionId":"809","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u4e95\u5b57\u6e38\u620f","question":{"questionId":"810","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u5b50\u6570\u7ec4\u4e2a\u6570","question":{"questionId":"811","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u5b57\u7b26\u4e32","question":{"questionId":"812","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6240\u6709\u53ef\u80fd\u7684\u8def\u5f84","question":{"questionId":"813","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f97\u5206\u6700\u9ad8\u7684\u6700\u5c0f\u8f6e\u8c03","question":{"questionId":"814","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9999\u69df\u5854","question":{"questionId":"815","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u54c8\u5e0c\u96c6\u5408","question":{"questionId":"816","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u54c8\u5e0c\u6620\u5c04","question":{"questionId":"817","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c RGB \u989c\u8272","question":{"questionId":"818","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u5e8f\u5217\u9012\u589e\u7684\u6700\u5c0f\u4ea4\u6362\u6b21\u6570","question":{"questionId":"819","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u6700\u7ec8\u7684\u5b89\u5168\u72b6\u6001","question":{"questionId":"820","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u7816\u5757","question":{"questionId":"821","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u552f\u4e00\u6469\u5c14\u65af\u5bc6\u7801\u8bcd","question":{"questionId":"822","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u5747\u503c\u5206\u5272","question":{"questionId":"823","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5199\u5b57\u7b26\u4e32\u9700\u8981\u7684\u884c\u6570","question":{"questionId":"824","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fdd\u6301\u57ce\u5e02\u5929\u9645\u7ebf","question":{"questionId":"825","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6c64","question":{"questionId":"826","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u60c5\u611f\u4e30\u5bcc\u7684\u6587\u5b57","question":{"questionId":"827","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ed1\u677f\u5f02\u6216\u6e38\u620f","question":{"questionId":"828","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u57df\u540d\u8bbf\u95ee\u8ba1\u6570","question":{"questionId":"829","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e09\u89d2\u5f62\u9762\u79ef","question":{"questionId":"830","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5e73\u5747\u503c\u548c\u7684\u5206\u7ec4","question":{"questionId":"831","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u526a\u679d","question":{"questionId":"832","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u4ea4\u8def\u7ebf","question":{"questionId":"833","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6a21\u7cca\u5750\u6807","question":{"questionId":"834","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u7ec4\u4ef6","question":{"questionId":"835","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d5b\u8f66","question":{"questionId":"836","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5e38\u89c1\u7684\u5355\u8bcd","question":{"questionId":"837","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u94fe\u8868","question":{"questionId":"838","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7684\u538b\u7f29\u7f16\u7801","question":{"questionId":"839","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u7684\u6700\u77ed\u8ddd\u79bb","question":{"questionId":"841","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5361\u7247\u6e38\u620f","question":{"questionId":"842","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e26\u56e0\u5b50\u7684\u4e8c\u53c9\u6811","question":{"questionId":"843","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5faa\u73af\u6709\u5e8f\u5217\u8868\u7684\u63d2\u5165","question":{"questionId":"850","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u7f8a\u62c9\u4e01\u6587","question":{"questionId":"851","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9002\u9f84\u7684\u670b\u53cb","question":{"questionId":"852","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u6392\u5de5\u4f5c\u4ee5\u8fbe\u5230\u6700\u5927\u6536\u76ca","question":{"questionId":"853","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4eba\u5de5\u5c9b","question":{"questionId":"854","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u7279\u5b57\u7b26\u4e32","question":{"questionId":"855","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u6574\u6570\u6c42\u548c","question":{"questionId":"856","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f83\u5927\u5206\u7ec4\u7684\u4f4d\u7f6e","question":{"questionId":"857","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9690\u85cf\u4e2a\u4eba\u4fe1\u606f","question":{"questionId":"858","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5faa\u73af\u53cc\u7aef\u961f\u5217","question":{"questionId":"859","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5faa\u73af\u961f\u5217","question":{"questionId":"860","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u56fe\u50cf","question":{"questionId":"861","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u67e5\u627e\u4e0e\u66ff\u6362","question":{"questionId":"862","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6811\u4e2d\u8ddd\u79bb\u4e4b\u548c","question":{"questionId":"863","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u50cf\u91cd\u53e0","question":{"questionId":"864","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u626b\u5730\u673a\u5668\u4eba","question":{"questionId":"865","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u91cd\u53e0","question":{"questionId":"866","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65b021\u70b9","question":{"questionId":"867","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a8\u591a\u7c73\u8bfa","question":{"questionId":"868","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c\u5b57\u7b26\u4e32\u7ec4","question":{"questionId":"869","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u7684\u5e7b\u65b9","question":{"questionId":"870","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94a5\u5319\u548c\u623f\u95f4","question":{"questionId":"871","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u62c6\u5206\u6210\u6590\u6ce2\u90a3\u5951\u5e8f\u5217","question":{"questionId":"872","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u731c\u8fd9\u4e2a\u5355\u8bcd","question":{"questionId":"873","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u542b\u9000\u683c\u7684\u5b57\u7b26\u4e32","question":{"questionId":"874","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684\u6700\u957f\u5c71\u8109","question":{"questionId":"875","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u624b\u987a\u5b50","question":{"questionId":"876","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbf\u95ee\u6240\u6709\u8282\u70b9\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"877","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u79fb\u4f4d","question":{"questionId":"878","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u6700\u8fd1\u7684\u4eba\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"879","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u9762\u79ef II","question":{"questionId":"880","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u55a7\u95f9\u548c\u5bcc\u6709","question":{"questionId":"881","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u8109\u6570\u7ec4\u7684\u5cf0\u9876\u7d22\u5f15","question":{"questionId":"882","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f66\u961f","question":{"questionId":"883","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c\u5ea6\u4e3a K \u7684\u5b57\u7b26\u4e32","question":{"questionId":"884","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8003\u573a\u5c31\u5ea7","question":{"questionId":"885","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62ec\u53f7\u7684\u5206\u6570","question":{"questionId":"886","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96c7\u4f63 K \u540d\u5de5\u4eba\u7684\u6700\u4f4e\u6210\u672c","question":{"questionId":"887","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u955c\u9762\u53cd\u5c04","question":{"questionId":"888","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4eb2\u5bc6\u5b57\u7b26\u4e32","question":{"questionId":"889","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e0\u6aac\u6c34\u627e\u96f6","question":{"questionId":"890","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u77e9\u9635\u540e\u7684\u5f97\u5206","question":{"questionId":"891","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u81f3\u5c11\u4e3a K \u7684\u6700\u77ed\u5b50\u6570\u7ec4","question":{"questionId":"892","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u6240\u6709\u8ddd\u79bb\u4e3a K \u7684\u7ed3\u70b9","question":{"questionId":"893","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ed1\u540d\u5355\u4e2d\u7684\u968f\u673a\u6570","question":{"questionId":"894","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u83b7\u53d6\u6240\u6709\u94a5\u5319\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"895","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5177\u6709\u6240\u6709\u6700\u6df1\u7ed3\u70b9\u7684\u6700\u5c0f\u5b50\u6811","question":{"questionId":"896","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u7d20\u6570","question":{"questionId":"897","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u7f6e\u77e9\u9635","question":{"questionId":"898","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u95f4\u8ddd","question":{"questionId":"899","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u6392\u5e8f\u5f97\u5230 2 \u7684\u5e42","question":{"questionId":"900","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u52bf\u6d17\u724c","question":{"questionId":"901","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u52a0\u6cb9\u6b21\u6570","question":{"questionId":"902","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Rand7() \u5b9e\u73b0 Rand10()","question":{"questionId":"903","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53f6\u5b50\u76f8\u4f3c\u7684\u6811","question":{"questionId":"904","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7684\u6590\u6ce2\u90a3\u5951\u5b50\u5e8f\u5217\u7684\u957f\u5ea6","question":{"questionId":"905","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6a21\u62df\u884c\u8d70\u673a\u5668\u4eba","question":{"questionId":"906","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7231\u5403\u9999\u8549\u7684\u73c2\u73c2","question":{"questionId":"907","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u7684\u4e2d\u95f4\u7ed3\u70b9","question":{"questionId":"908","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77f3\u5b50\u6e38\u620f","question":{"questionId":"909","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c N \u4e2a\u795e\u5947\u6570\u5b57","question":{"questionId":"910","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76c8\u5229\u8ba1\u5212","question":{"questionId":"911","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u6743\u91cd\u968f\u673a\u9009\u62e9","question":{"questionId":"912","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u968f\u673a\u7ffb\u8f6c\u77e9\u9635","question":{"questionId":"913","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u975e\u91cd\u53e0\u77e9\u5f62\u4e2d\u7684\u968f\u673a\u70b9","question":{"questionId":"914","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u5706\u5185\u968f\u673a\u751f\u6210\u70b9","question":{"questionId":"915","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7d22\u5f15\u5904\u7684\u89e3\u7801\u5b57\u7b26\u4e32","question":{"questionId":"916","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6551\u751f\u8247","question":{"questionId":"917","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec6\u5206\u56fe\u4e2d\u7684\u53ef\u5230\u8fbe\u7ed3\u70b9","question":{"questionId":"918","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7ef4\u5f62\u4f53\u6295\u5f71\u9762\u79ef","question":{"questionId":"919","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u53e5\u8bdd\u4e2d\u7684\u4e0d\u5e38\u89c1\u5355\u8bcd","question":{"questionId":"920","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635 III","question":{"questionId":"921","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u80fd\u7684\u4e8c\u5206\u6cd5","question":{"questionId":"922","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9e21\u86cb\u6389\u843d","question":{"questionId":"923","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u5e73\u7684\u7cd6\u679c\u4ea4\u6362","question":{"questionId":"924","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u524d\u5e8f\u548c\u540e\u5e8f\u904d\u5386\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"925","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u548c\u66ff\u6362\u6a21\u5f0f","question":{"questionId":"926","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u5e8f\u5217\u5bbd\u5ea6\u4e4b\u548c","question":{"questionId":"927","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7ef4\u5f62\u4f53\u7684\u8868\u9762\u79ef","question":{"questionId":"928","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7279\u6b8a\u7b49\u4ef7\u5b57\u7b26\u4e32\u7ec4","question":{"questionId":"929","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6240\u6709\u53ef\u80fd\u7684\u6ee1\u4e8c\u53c9\u6811","question":{"questionId":"930","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u9891\u7387\u6808","question":{"questionId":"931","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8c03\u6570\u5217","question":{"questionId":"932","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u987a\u5e8f\u67e5\u627e\u6811","question":{"questionId":"933","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u6309\u4f4d\u6216\u64cd\u4f5c","question":{"questionId":"934","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u961f\u5217","question":{"questionId":"935","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"RLE \u8fed\u4ee3\u5668","question":{"questionId":"936","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u80a1\u7968\u4ef7\u683c\u8de8\u5ea6","question":{"questionId":"937","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e3a N \u7684\u6570\u5b57\u7ec4\u5408","question":{"questionId":"938","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"DI \u5e8f\u5217\u7684\u6709\u6548\u6392\u5217","question":{"questionId":"939","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u679c\u6210\u7bee","question":{"questionId":"940","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5947\u5076\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"941","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u56de\u6587\u6570","question":{"questionId":"942","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u7684\u6700\u5c0f\u503c\u4e4b\u548c","question":{"questionId":"943","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5dee\u503c I","question":{"questionId":"944","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u86c7\u68af\u68cb","question":{"questionId":"945","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5dee\u503c II","question":{"questionId":"946","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u7ebf\u9009\u4e3e","question":{"questionId":"947","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"948","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u732b\u548c\u8001\u9f20","question":{"questionId":"949","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5361\u724c\u5206\u7ec4","question":{"questionId":"950","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4","question":{"questionId":"951","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u5b50\u96c6","question":{"questionId":"952","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ec5\u4ec5\u53cd\u8f6c\u5b57\u6bcd","question":{"questionId":"953","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"954","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u4e8c\u53c9\u6811\u63d2\u5165\u5668","question":{"questionId":"955","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u64ad\u653e\u5217\u8868\u7684\u6570\u91cf","question":{"questionId":"956","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u62ec\u53f7\u6709\u6548\u7684\u6700\u5c11\u6dfb\u52a0","question":{"questionId":"957","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5947\u5076\u6392\u5e8f\u6570\u7ec4 II","question":{"questionId":"958","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u6570\u4e4b\u548c\u7684\u591a\u79cd\u53ef\u80fd","question":{"questionId":"959","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u91cf\u51cf\u5c11\u6076\u610f\u8f6f\u4ef6\u7684\u4f20\u64ad","question":{"questionId":"960","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u6309\u952e\u5165","question":{"questionId":"961","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u5b57\u7b26\u4e32\u7ffb\u8f6c\u5230\u5355\u8c03\u9012\u589e","question":{"questionId":"962","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7b49\u5206","question":{"questionId":"963","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u91cf\u51cf\u5c11\u6076\u610f\u8f6f\u4ef6\u7684\u4f20\u64ad II","question":{"questionId":"964","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u7279\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740","question":{"questionId":"965","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u76f8\u540c\u7684\u4e8c\u5143\u5b50\u6570\u7ec4","question":{"questionId":"966","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u964d\u8def\u5f84\u6700\u5c0f\u548c","question":{"questionId":"967","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6f02\u4eae\u6570\u7ec4","question":{"questionId":"968","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u8fd1\u7684\u8bf7\u6c42\u6b21\u6570","question":{"questionId":"969","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u7684\u6865","question":{"questionId":"971","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a91\u58eb\u62e8\u53f7\u5668","question":{"questionId":"972","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6233\u5370\u5e8f\u5217","question":{"questionId":"973","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u6392\u5217\u65e5\u5fd7\u6587\u4ef6","question":{"questionId":"974","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u8303\u56f4\u548c","question":{"questionId":"975","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9762\u79ef\u77e9\u5f62","question":{"questionId":"976","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u5b50\u5e8f\u5217 II","question":{"questionId":"977","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5c71\u8109\u6570\u7ec4","question":{"questionId":"978","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u589e\u51cf\u5b57\u7b26\u4e32\u5339\u914d","question":{"questionId":"979","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u8d85\u7ea7\u4e32","question":{"questionId":"980","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f","question":{"questionId":"981","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u6570\u7ec4\u552f\u4e00\u7684\u6700\u5c0f\u589e\u91cf","question":{"questionId":"982","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u6808\u5e8f\u5217","question":{"questionId":"983","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u6700\u591a\u7684\u540c\u884c\u6216\u540c\u5217\u77f3\u5934","question":{"questionId":"984","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ee4\u724c\u653e\u7f6e","question":{"questionId":"985","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b9a\u6570\u5b57\u80fd\u7ec4\u6210\u7684\u6700\u5927\u65f6\u95f4","question":{"questionId":"986","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u9012\u589e\u987a\u5e8f\u663e\u793a\u5361\u724c","question":{"questionId":"987","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u7b49\u4ef7\u4e8c\u53c9\u6811","question":{"questionId":"988","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u516c\u56e0\u6570\u8ba1\u7b97\u6700\u5927\u7ec4\u4ef6\u5927\u5c0f","question":{"questionId":"989","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u5916\u661f\u8bed\u8bcd\u5178","question":{"questionId":"990","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u500d\u6570\u5bf9\u6570\u7ec4","question":{"questionId":"991","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f II","question":{"questionId":"992","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u9ad8\u7684\u5e7f\u544a\u724c","question":{"questionId":"993","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N \u5929\u540e\u7684\u7262\u623f","question":{"questionId":"994","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5b8c\u5168\u6027\u68c0\u9a8c","question":{"questionId":"998","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7531\u659c\u6760\u5212\u5206\u533a\u57df","question":{"questionId":"999","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f III","question":{"questionId":"1000","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d N \u6b21\u7684\u5143\u7d20","question":{"questionId":"1001","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5bbd\u5ea6\u5761","question":{"questionId":"1002","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9762\u79ef\u77e9\u5f62 II","question":{"questionId":"1003","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8868\u793a\u6570\u5b57\u7684\u6700\u5c11\u8fd0\u7b97\u7b26","question":{"questionId":"1004","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u503c\u4e8c\u53c9\u6811","question":{"questionId":"1005","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5143\u97f3\u62fc\u5199\u68c0\u67e5\u5668","question":{"questionId":"1006","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u5dee\u76f8\u540c\u7684\u6570\u5b57","question":{"questionId":"1007","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76d1\u63a7\u4e8c\u53c9\u6811","question":{"questionId":"1008","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u714e\u997c\u6392\u5e8f","question":{"questionId":"1009","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f3a\u6574\u6570","question":{"questionId":"1010","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u4e8c\u53c9\u6811\u4ee5\u5339\u914d\u5148\u5e8f\u904d\u5386","question":{"questionId":"1011","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u7b49\u7684\u6709\u7406\u6570","question":{"questionId":"1012","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6590\u6ce2\u90a3\u5951\u6570","question":{"questionId":"1013","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u539f\u70b9\u7684 K \u4e2a\u70b9","question":{"questionId":"1014","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u53ef\u88ab K \u6574\u9664\u7684\u5b50\u6570\u7ec4","question":{"questionId":"1016","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u5076\u8df3","question":{"questionId":"1017","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u89d2\u5f62\u7684\u6700\u5927\u5468\u957f","question":{"questionId":"1018","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u7684\u5e73\u65b9","question":{"questionId":"1019","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6e4d\u6d41\u5b50\u6570\u7ec4","question":{"questionId":"1020","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u4e8c\u53c9\u6811\u4e2d\u5206\u914d\u786c\u5e01","question":{"questionId":"1021","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84 III","question":{"questionId":"1022","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u4e8e\u65f6\u95f4\u7684\u952e\u503c\u5b58\u50a8","question":{"questionId":"1023","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u4f4d\u4e0e\u4e3a\u96f6\u7684\u4e09\u5143\u7ec4","question":{"questionId":"1024","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u7968\u4ef7","question":{"questionId":"1025","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u542b AAA \u6216 BBB \u7684\u5b57\u7b26\u4e32","question":{"questionId":"1026","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u540e\u7684\u5076\u6570\u548c","question":{"questionId":"1027","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u5217\u8868\u7684\u4ea4\u96c6","question":{"questionId":"1028","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5782\u5e8f\u904d\u5386","question":{"questionId":"1029","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u53f6\u7ed3\u70b9\u5f00\u59cb\u7684\u6700\u5c0f\u5b57\u7b26\u4e32","question":{"questionId":"1030","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5f62\u5f0f\u7684\u6574\u6570\u52a0\u6cd5","question":{"questionId":"1031","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5f0f\u65b9\u7a0b\u7684\u53ef\u6ee1\u8db3\u6027","question":{"questionId":"1032","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u574f\u4e86\u7684\u8ba1\u7b97\u5668","question":{"questionId":"1033","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u4e0d\u540c\u6574\u6570\u7684\u5b50\u6570\u7ec4","question":{"questionId":"1034","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5802\u5144\u5f1f\u8282\u70b9","question":{"questionId":"1035","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8150\u70c2\u7684\u6a58\u5b50","question":{"questionId":"1036","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u8fde\u7eed\u4f4d\u7684\u6700\u5c0f\u7ffb\u8f6c\u6b21\u6570","question":{"questionId":"1037","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b63\u65b9\u5f62\u6570\u7ec4\u7684\u6570\u76ee","question":{"questionId":"1038","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u5c0f\u9547\u7684\u6cd5\u5b98","question":{"questionId":"1039","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e8c\u53c9\u6811 II","question":{"questionId":"1040","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f66\u7684\u53ef\u7528\u6355\u83b7\u91cf","question":{"questionId":"1041","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u77f3\u5934\u7684\u6700\u4f4e\u6210\u672c","question":{"questionId":"1042","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f51\u683c\u7167\u660e","question":{"questionId":"1043","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u5e38\u7528\u5b57\u7b26","question":{"questionId":"1044","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u66ff\u6362\u540e\u7684\u8bcd\u662f\u5426\u6709\u6548","question":{"questionId":"1045","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570 III","question":{"questionId":"1046","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u6b21\u53d6\u53cd\u540e\u6700\u5927\u5316\u7684\u6570\u7ec4\u548c","question":{"questionId":"1047","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b28\u9636\u4e58","question":{"questionId":"1048","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u76f8\u7b49\u7684\u6700\u5c11\u591a\u7c73\u8bfa\u65cb\u8f6c","question":{"questionId":"1049","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5148\u5e8f\u904d\u5386\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"1050","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f62\u6210\u5b57\u7b26\u4e32\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1051","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6821\u56ed\u81ea\u884c\u8f66\u5206\u914d","question":{"questionId":"1052","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5316\u820d\u5165\u8bef\u5dee\u4ee5\u6ee1\u8db3\u76ee\u6807","question":{"questionId":"1053","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5341\u8fdb\u5236\u6574\u6570\u7684\u53cd\u7801","question":{"questionId":"1054","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u603b\u6301\u7eed\u65f6\u95f4\u53ef\u88ab 60 \u6574\u9664\u7684\u6b4c\u66f2","question":{"questionId":"1055","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728 D \u5929\u5185\u9001\u8fbe\u5305\u88f9\u7684\u80fd\u529b","question":{"questionId":"1056","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u6709 1 \u4f4d\u91cd\u590d\u7684\u6570\u5b57","question":{"questionId":"1057","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5b57\u5178\u5e8f\u6392\u5217\u6700\u5c0f\u7684\u7b49\u6548\u5b57\u7b26\u4e32","question":{"questionId":"1058","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u4e2d\u7684\u7f3a\u5931\u5143\u7d20","question":{"questionId":"1059","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u4e32","question":{"questionId":"1060","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u5b50\u6570\u7ec4\u7684\u6570\u76ee","question":{"questionId":"1061","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u6210\u548c\u76f8\u7b49\u7684\u4e09\u4e2a\u90e8\u5206","question":{"questionId":"1062","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u89c2\u5149\u7ec4\u5408","question":{"questionId":"1063","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u88ab K \u6574\u9664\u7684\u6700\u5c0f\u6574\u6570","question":{"questionId":"1064","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u4e32\u80fd\u8868\u793a\u4ece 1 \u5230 N \u6570\u5b57\u7684\u4e8c\u8fdb\u5236\u4e32","question":{"questionId":"1065","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u52a8\u70b9","question":{"questionId":"1066","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6821\u56ed\u81ea\u884c\u8f66\u5206\u914d II","question":{"questionId":"1067","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8303\u56f4\u5185\u7684\u6570\u5b57\u8ba1\u6570","question":{"questionId":"1068","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6613\u6df7\u6dc6\u6570","question":{"questionId":"1069","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d1f\u4e8c\u8fdb\u5236\u8f6c\u6362","question":{"questionId":"1070","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u88ab 5 \u6574\u9664\u7684\u4e8c\u8fdb\u5236\u524d\u7f00","question":{"questionId":"1071","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u4e2d\u7684\u4e0b\u4e00\u4e2a\u66f4\u5927\u8282\u70b9","question":{"questionId":"1072","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u98de\u5730\u7684\u6570\u91cf","question":{"questionId":"1073","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u4e94\u79d1\u7684\u5747\u5206","question":{"questionId":"1074","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u7d22\u5f15\u5bf9","question":{"questionId":"1075","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5207\u6362","question":{"questionId":"1076","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6613\u6df7\u6dc6\u6570 II","question":{"questionId":"1077","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6700\u5916\u5c42\u7684\u62ec\u53f7","question":{"questionId":"1078","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u6839\u5230\u53f6\u7684\u4e8c\u8fdb\u5236\u6570\u4e4b\u548c","question":{"questionId":"1079","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a7c\u5cf0\u5f0f\u5339\u914d","question":{"questionId":"1080","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89c6\u9891\u62fc\u63a5","question":{"questionId":"1081","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5143\u7d20\u5404\u6570\u4f4d\u4e4b\u548c","question":{"questionId":"1082","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c0f\u4e8e K \u7684\u4e24\u6570\u4e4b\u548c","question":{"questionId":"1083","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u5ea6\u4e3a K \u7684\u65e0\u91cd\u590d\u5b57\u7b26\u5b50\u4e32","question":{"questionId":"1084","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f7c\u6b64\u719f\u8bc6\u7684\u6700\u65e9\u65f6\u95f4","question":{"questionId":"1085","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u6570\u535a\u5f08","question":{"questionId":"1086","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7b49\u5dee\u6570\u5217","question":{"questionId":"1087","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u6708\u6709\u591a\u5c11\u5929","question":{"questionId":"1088","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u53bb\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u97f3","question":{"questionId":"1089","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u963f\u59c6\u65af\u7279\u6717\u6570","question":{"questionId":"1090","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6811\u7684\u6700\u5927\u5e73\u5747\u503c","question":{"questionId":"1091","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8282\u70b9\u4e0e\u5176\u7956\u5148\u4e4b\u95f4\u7684\u6700\u5927\u5dee\u503c","question":{"questionId":"1092","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u5148\u5e8f\u904d\u5386\u8fd8\u539f\u4e8c\u53c9\u6811","question":{"questionId":"1093","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ddd\u79bb\u987a\u5e8f\u6392\u5217\u77e9\u9635\u5355\u5143\u683c","question":{"questionId":"1094","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u5730\u8c03\u5ea6","question":{"questionId":"1095","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u975e\u91cd\u53e0\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"1096","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u6d41","question":{"questionId":"1097","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u552f\u4e00\u6570","question":{"questionId":"1098","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f97\u5206\u6700\u9ad8\u7684\u8def\u5f84","question":{"questionId":"1099","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u6210\u672c\u8054\u901a\u6240\u6709\u57ce\u5e02","question":{"questionId":"1100","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u884c\u8bfe\u7a0b","question":{"questionId":"1101","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u4e00\u4e2a\u6570\u662f\u5426\u5728\u6570\u7ec4\u4e2d\u5360\u7edd\u5927\u591a\u6570","question":{"questionId":"1102","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u77f3\u5b50\u76f4\u5230\u8fde\u7eed","question":{"questionId":"1103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fb9\u6846\u7740\u8272","question":{"questionId":"1104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u76f8\u4ea4\u7684\u7ebf","question":{"questionId":"1105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9003\u79bb\u5927\u8ff7\u5bab","question":{"questionId":"1106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c11\u4ea4\u6362\u6b21\u6570\u6765\u7ec4\u5408\u6240\u6709\u7684 1","question":{"questionId":"1107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6237\u7f51\u7ad9\u8bbf\u95ee\u884c\u4e3a\u5206\u6790","question":{"questionId":"1108","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u8def\u6d41\u91cf","question":{"questionId":"1110","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u8fb9\u5f62\u4e09\u89d2\u5256\u5206\u7684\u6700\u4f4e\u5f97\u5206","question":{"questionId":"1111","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u5199\u5355\u8bcd","question":{"questionId":"1112","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u77f3\u5b50\u76f4\u5230\u8fde\u7eed II","question":{"questionId":"1113","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e8c\u53c9\u641c\u7d22\u6811\u5230\u66f4\u5927\u548c\u6811","question":{"questionId":"1114","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u56de\u65cb\u9556","question":{"questionId":"1115","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5c42\u5185\u5143\u7d20\u548c","question":{"questionId":"1116","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5730\u56fe\u5206\u6790","question":{"questionId":"1117","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u6210\u51e0\u4e2a\u9012\u589e\u5e8f\u5217","question":{"questionId":"1118","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56f0\u4e8e\u73af\u4e2d\u7684\u673a\u5668\u4eba","question":{"questionId":"1119","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u90bb\u63a5\u690d\u82b1","question":{"questionId":"1120","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u6570\u7ec4\u4ee5\u5f97\u5230\u6700\u5927\u548c","question":{"questionId":"1121","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u4e32","question":{"questionId":"1122","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u884c\u952e\u76d8","question":{"questionId":"1123","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u8f6c\u5316","question":{"questionId":"1124","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u6587\u4ef6\u7cfb\u7edf","question":{"questionId":"1125","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u63a5\u68d2\u6750\u7684\u6700\u4f4e\u8d39\u7528","question":{"questionId":"1126","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u5757\u77f3\u5934\u7684\u91cd\u91cf","question":{"questionId":"1127","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b57\u7b26\u4e32\u4e2d\u7684\u6240\u6709\u76f8\u90bb\u91cd\u590d\u9879","question":{"questionId":"1128","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u5b57\u7b26\u4e32\u94fe","question":{"questionId":"1129","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u5757\u77f3\u5934\u7684\u91cd\u91cf II","question":{"questionId":"1130","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u53ea\u542b\u5355\u4e00\u5b57\u6bcd\u7684\u5b50\u4e32","question":{"questionId":"1131","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u540e\u62fc\u63a5","question":{"questionId":"1132","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5b57\u5178\u5e8f\u6392\u5728\u6700\u540e\u7684\u5b50\u4e32","question":{"questionId":"1133","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0e\u76ee\u6807\u989c\u8272\u95f4\u7684\u6700\u77ed\u8ddd\u79bb","question":{"questionId":"1134","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u4e0b\u6240\u6709\u4ea7\u54c1\u7684\u5ba2\u6237","question":{"questionId":"1135","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u4f5c\u8fc7\u81f3\u5c11\u4e09\u6b21\u7684\u6f14\u5458\u548c\u5bfc\u6f14","question":{"questionId":"1136","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ad8\u5ea6\u68c0\u67e5\u5668","question":{"questionId":"1137","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7231\u751f\u6c14\u7684\u4e66\u5e97\u8001\u677f","question":{"questionId":"1138","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u4e00\u6b21\u7684\u5148\u524d\u6392\u5217","question":{"questionId":"1139","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ddd\u79bb\u76f8\u7b49\u7684\u6761\u5f62\u7801","question":{"questionId":"1140","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u53ef\u4ee5\u4e70\u5230\u7684\u82f9\u679c\u6570\u91cf","question":{"questionId":"1141","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fdb\u51fb\u7684\u9a91\u58eb","question":{"questionId":"1142","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u6240\u6709\u884c\u4e2d\u6700\u5c0f\u516c\u5171\u5143\u7d20","question":{"questionId":"1143","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u8d44\u6e90\u5206\u914d\u4f18\u5316","question":{"questionId":"1144","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5143\u7d20\u548c\u4e3a\u76ee\u6807\u503c\u7684\u5b50\u77e9\u9635\u6570\u91cf","question":{"questionId":"1145","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u6700\u5927\u516c\u56e0\u5b50","question":{"questionId":"1146","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5217\u7ffb\u8f6c\u5f97\u5230\u6700\u5927\u503c\u7b49\u884c\u6570","question":{"questionId":"1147","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d1f\u4e8c\u8fdb\u5236\u6570\u76f8\u52a0","question":{"questionId":"1148","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u6709\u5e8f\u6570\u7ec4\u7684\u4ea4\u96c6","question":{"questionId":"1149","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u4e24\u68f5\u4e8c\u53c9\u641c\u7d22\u6811\u4e4b\u548c","question":{"questionId":"1150","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b65\u8fdb\u6570","question":{"questionId":"1151","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d 1 \u7684\u6700\u5927\u6570\u91cf","question":{"questionId":"1152","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 I","question":{"questionId":"1153","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 II","question":{"questionId":"1154","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 III","question":{"questionId":"1155","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Bigram \u5206\u8bcd","question":{"questionId":"1156","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u5230\u53f6\u8def\u5f84\u4e0a\u7684\u4e0d\u8db3\u8282\u70b9","question":{"questionId":"1157","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u5c0f\u5b50\u5e8f\u5217","question":{"questionId":"1159","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d3b\u5b57\u5370\u5237","question":{"questionId":"1160","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5 I","question":{"questionId":"1161","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5II","question":{"questionId":"1162","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5 III","question":{"questionId":"1163","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u4e2d\u7f3a\u5931\u7684\u6570\u5b57","question":{"questionId":"1164","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u6392\u4f1a\u8bae\u65e5\u7a0b","question":{"questionId":"1165","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u629b\u63b7\u786c\u5e01","question":{"questionId":"1166","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5efa\u9020\u8857\u533a\u7684\u6700\u77ed\u65f6\u95f4","question":{"questionId":"1167","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u5199\u96f6","question":{"questionId":"1168","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d7\u6807\u7b7e\u5f71\u54cd\u7684\u6700\u5927\u503c","question":{"questionId":"1169","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u516c\u5171\u8d85\u5e8f\u5217","question":{"questionId":"1170","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u77e9\u9635\u4e2d\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1171","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790 I ","question":{"questionId":"1172","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790 II","question":{"questionId":"1173","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790III","question":{"questionId":"1174","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u53d8\u6362","question":{"questionId":"1175","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u529b\u6263\u6392\u884c\u699c","question":{"questionId":"1176","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6811\u7684\u76f4\u5f84","question":{"questionId":"1177","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u5b57\u7b26\u4e32 III","question":{"questionId":"1178","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 I","question":{"questionId":"1179","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 II","question":{"questionId":"1180","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 III","question":{"questionId":"1181","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 IV","question":{"questionId":"1182","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u6837\u672c\u7edf\u8ba1","question":{"questionId":"1183","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u8f66","question":{"questionId":"1184","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u8109\u6570\u7ec4\u4e2d\u67e5\u627e\u76ee\u6807\u503c","question":{"questionId":"1185","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H2O \u751f\u6210","question":{"questionId":"1186","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u6253\u5370FooBar","question":{"questionId":"1187","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u82b1\u62ec\u53f7\u5c55\u5f00 II","question":{"questionId":"1188","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u5bc6\u6570\u5b57","question":{"questionId":"1189","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u516c\u5171\u533a\u57df","question":{"questionId":"1190","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fd1\u4e49\u8bcd\u53e5\u5b50","question":{"questionId":"1191","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u4eab\u5de7\u514b\u529b","question":{"questionId":"1192","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 V","question":{"questionId":"1193","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u5bfb\u8def","question":{"questionId":"1194","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u7cd6\u679c II","question":{"questionId":"1195","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u4e66\u67b6","question":{"questionId":"1196","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u6790\u5e03\u5c14\u8868\u8fbe\u5f0f","question":{"questionId":"1197","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c0f\u4f17\u4e66\u7c4d","question":{"questionId":"1198","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5341\u516d\u8fdb\u5236\u9b54\u672f\u6570\u5b57","question":{"questionId":"1199","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u533a\u95f4","question":{"questionId":"1200","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6811\u8282\u70b9","question":{"questionId":"1201","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u56de\u6587\u5b50\u6570\u7ec4","question":{"questionId":"1202","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5e8f\u6253\u5370","question":{"questionId":"1203","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u65e5\u65b0\u7528\u6237\u7edf\u8ba1","question":{"questionId":"1204","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IP \u5730\u5740\u65e0\u6548\u5316","question":{"questionId":"1205","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u822a\u73ed\u9884\u8ba2\u7edf\u8ba1","question":{"questionId":"1206","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u70b9\u6210\u6797","question":{"questionId":"1207","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u62ec\u53f7\u7684\u5d4c\u5957\u6df1\u5ea6","question":{"questionId":"1208","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u6709\u9650\u963b\u585e\u961f\u5217","question":{"questionId":"1209","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u76f8\u4ea4\u7684\u63e1\u624b","question":{"questionId":"1213","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u4f4d\u5b66\u751f\u7684\u6700\u9ad8\u6210\u7ee9","question":{"questionId":"1214","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5370\u96f6\u4e0e\u5947\u5076\u6570","question":{"questionId":"1216","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u76f8\u5bf9\u6392\u5e8f","question":{"questionId":"1217","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u6df1\u53f6\u8282\u70b9\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"1218","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8868\u73b0\u826f\u597d\u7684\u6700\u957f\u65f6\u95f4\u6bb5","question":{"questionId":"1219","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7684\u5fc5\u8981\u56e2\u961f","question":{"questionId":"1220","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u4ef7\u591a\u7c73\u8bfa\u9aa8\u724c\u5bf9\u7684\u6570\u91cf","question":{"questionId":"1227","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53f6\u503c\u7684\u6700\u5c0f\u4ee3\u4ef7\u751f\u6210\u6811","question":{"questionId":"1228","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u989c\u8272\u4ea4\u66ff\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1229","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edd\u5bf9\u503c\u8868\u8fbe\u5f0f\u7684\u6700\u5927\u503c","question":{"questionId":"1230","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u5185\u8239\u53ea\u7684\u6570\u76ee","question":{"questionId":"1233","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c N \u4e2a\u6cf0\u6ce2\u90a3\u5951\u6570","question":{"questionId":"1236","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u677f\u4e0a\u7684\u8def\u5f84","question":{"questionId":"1238","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u7684\u4ee5 1 \u4e3a\u8fb9\u754c\u7684\u6b63\u65b9\u5f62","question":{"questionId":"1239","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77f3\u5b50\u6e38\u620f II","question":{"questionId":"1240","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fc7\u53bb30\u5929\u7684\u7528\u6237\u6d3b\u52a8 II","question":{"questionId":"1246","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u51cf\u5143\u7d20\u4f7f\u6570\u7ec4\u5448\u952f\u9f7f\u72b6","question":{"questionId":"1247","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7740\u8272\u6e38\u620f","question":{"questionId":"1248","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5feb\u7167\u6570\u7ec4","question":{"questionId":"1249","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u516c\u5171\u5b50\u5e8f\u5217","question":{"questionId":"1250","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bb5\u5f0f\u56de\u6587","question":{"questionId":"1251","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u7ae0\u6d4f\u89c8 I","question":{"questionId":"1258","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u5e74\u4e2d\u7684\u7b2c\u51e0\u5929","question":{"questionId":"1260","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u5b57\u7b26\u91cd\u590d\u5b50\u4e32\u7684\u6700\u5927\u957f\u5ea6","question":{"questionId":"1261","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u4e2d\u5360\u7edd\u5927\u591a\u6570\u7684\u5143\u7d20","question":{"questionId":"1262","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63b7\u9ab0\u5b50\u7684N\u79cd\u65b9\u6cd5","question":{"questionId":"1263","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u94fe\u8868\u4e2d\u5220\u53bb\u603b\u548c\u503c\u4e3a\u96f6\u7684\u8fde\u7eed\u8282\u70b9","question":{"questionId":"1267","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9910\u76d8\u6808","question":{"questionId":"1270","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u65e0\u6548\u4ea4\u6613","question":{"questionId":"1272","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u5b57\u7b26\u4e32\u6700\u5c0f\u5b57\u6bcd\u51fa\u73b0\u9891\u6b21","question":{"questionId":"1273","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d28\u6570\u6392\u5217","question":{"questionId":"1279","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5065\u8eab\u8ba1\u5212\u8bc4\u4f30","question":{"questionId":"1280","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6784\u5efa\u56de\u6587\u4e32\u68c0\u6d4b","question":{"questionId":"1281","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u5b57\u8c1c","question":{"questionId":"1282","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u4ea4\u7ad9\u95f4\u7684\u8ddd\u79bb","question":{"questionId":"1287","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e00\u6b21\u5f97\u5230\u5b50\u6570\u7ec4\u6700\u5927\u548c","question":{"questionId":"1288","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u5468\u4e2d\u7684\u7b2c\u51e0\u5929","question":{"questionId":"1289","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u6570\u7ec4\u4e25\u683c\u9012\u589e","question":{"questionId":"1290","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u201c\u6c14\u7403\u201d \u7684\u6700\u5927\u6570\u91cf","question":{"questionId":"1297","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u6bcf\u5bf9\u62ec\u53f7\u95f4\u7684\u5b50\u4e32","question":{"questionId":"1298","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u6b21\u4e32\u8054\u540e\u6700\u5927\u5b50\u6570\u7ec4\u4e4b\u548c","question":{"questionId":"1299","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u96c6\u7fa4\u5185\u7684\u300c\u5173\u952e\u8fde\u63a5\u300d","question":{"questionId":"1300","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u683c\u5f0f\u5316\u90e8\u95e8\u8868","question":{"questionId":"1301","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7edd\u5bf9\u5dee","question":{"questionId":"1306","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570 III","question":{"questionId":"1307","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20","question":{"questionId":"1308","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u7ba1\u7406","question":{"questionId":"1309","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u6253\u5370\u5b57\u7b26\u4e32","question":{"questionId":"1316","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u6708\u4ea4\u6613 I","question":{"questionId":"1317","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9526\u6807\u8d5b\u4f18\u80dc\u8005","question":{"questionId":"1318","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u4e00\u65e0\u4e8c\u7684\u51fa\u73b0\u6b21\u6570","question":{"questionId":"1319","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b57\u7b26\u4e32\u4e2d\u7684\u6240\u6709\u76f8\u90bb\u91cd\u590d\u9879 II","question":{"questionId":"1320","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u53ef\u80fd\u4f7f\u5b57\u7b26\u4e32\u76f8\u7b49","question":{"questionId":"1321","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7a7f\u8fc7\u8ff7\u5bab\u7684\u6700\u5c11\u79fb\u52a8\u6b21\u6570","question":{"questionId":"1322","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u6708\u4ea4\u6613II","question":{"questionId":"1328","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73a9\u7b79\u7801","question":{"questionId":"1329","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u5b9a\u5dee\u5b50\u5e8f\u5217","question":{"questionId":"1330","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ec4\u91d1\u77ff\u5de5","question":{"questionId":"1331","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5143\u97f3\u5b57\u6bcd\u5e8f\u5217\u7684\u6570\u76ee","question":{"questionId":"1332","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u8df3\u8868","question":{"questionId":"1337","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u54f2\u5b66\u5bb6\u8fdb\u9910","question":{"questionId":"1340","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u5e73\u8861\u5b57\u7b26\u4e32","question":{"questionId":"1341","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u4ee5\u653b\u51fb\u56fd\u738b\u7684\u7687\u540e","question":{"questionId":"1342","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63b7\u9ab0\u5b50\u6a21\u62df","question":{"questionId":"1343","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u76f8\u7b49\u9891\u7387","question":{"questionId":"1344","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f00\u70b9\u6210\u7ebf","question":{"questionId":"1349","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b50\u6587\u4ef6\u5939","question":{"questionId":"1350","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u66ff\u6362\u5b50\u4e32\u5f97\u5230\u5e73\u8861\u5b57\u7b26\u4e32","question":{"questionId":"1351","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89c4\u5212\u517c\u804c\u5de5\u4f5c","question":{"questionId":"1352","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62a5\u544a\u7cfb\u7edf\u72b6\u6001\u7684\u8fde\u7eed\u65e5\u671f","question":{"questionId":"1357","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u7ed9\u5b9a\u65b9\u7a0b\u7684\u6b63\u6574\u6570\u89e3","question":{"questionId":"1358","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5faa\u73af\u7801\u6392\u5217","question":{"questionId":"1359","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e32\u8054\u5b57\u7b26\u4e32\u7684\u6700\u5927\u957f\u5ea6","question":{"questionId":"1360","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fa\u74f7\u7816","question":{"questionId":"1361","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u98de\u673a\u5ea7\u4f4d\u5206\u914d\u6982\u7387","question":{"questionId":"1362","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u7ebf\u7a0b\u7f51\u9875\u722c\u866b","question":{"questionId":"1368","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u5b57\u7b26\u4f7f\u5f97\u5b57\u7b26\u4e32\u76f8\u540c","question":{"questionId":"1369","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u300c\u4f18\u7f8e\u5b50\u6570\u7ec4\u300d","question":{"questionId":"1370","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u65e0\u6548\u7684\u62ec\u53f7","question":{"questionId":"1371","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u300c\u597d\u6570\u7ec4\u300d","question":{"questionId":"1372","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u4e2a\u5e16\u5b50\u7684\u8bc4\u8bba\u6570","question":{"questionId":"1377","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u6570\u503c\u5355\u5143\u683c\u7684\u6570\u76ee","question":{"questionId":"1378","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u6784 2 \u884c\u4e8c\u8fdb\u5236\u77e9\u9635","question":{"questionId":"1379","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5c01\u95ed\u5c9b\u5c7f\u7684\u6570\u76ee","question":{"questionId":"1380","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f97\u5206\u6700\u9ad8\u7684\u5355\u8bcd\u96c6\u5408","question":{"questionId":"1381","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ef4\u7f51\u683c\u8fc1\u79fb","question":{"questionId":"1386","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u53d7\u6c61\u67d3\u7684\u4e8c\u53c9\u6811\u4e2d\u67e5\u627e\u5143\u7d20","question":{"questionId":"1387","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u88ab\u4e09\u6574\u9664\u7684\u6700\u5927\u548c","question":{"questionId":"1388","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a8\u7bb1\u5b50","question":{"questionId":"1389","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbf\u95ee\u6240\u6709\u70b9\u7684\u6700\u5c0f\u65f6\u95f4","question":{"questionId":"1395","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u53c2\u4e0e\u901a\u4fe1\u7684\u670d\u52a1\u5668","question":{"questionId":"1396","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u63a8\u8350\u7cfb\u7edf","question":{"questionId":"1397","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u505c\u5728\u539f\u5730\u7684\u65b9\u6848\u6570","question":{"questionId":"1398","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u4e95\u5b57\u68cb\u7684\u83b7\u80dc\u8005","question":{"questionId":"1400","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u6d6a\u8d39\u539f\u6599\u7684\u6c49\u5821\u5236\u4f5c\u65b9\u6848","question":{"questionId":"1401","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5168\u4e3a 1 \u7684\u6b63\u65b9\u5f62\u5b50\u77e9\u9635","question":{"questionId":"1402","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u56de\u6587\u4e32 III","question":{"questionId":"1403","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u7684\u5404\u4f4d\u79ef\u548c\u4e4b\u5dee","question":{"questionId":"1406","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6237\u5206\u7ec4","question":{"questionId":"1407","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100002","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100003","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100004","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100005","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100006","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100007","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100008","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100009","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100010","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100011","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100012","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100013","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100014","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100015","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100016","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100017","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100018","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100019","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100020","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100021","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100022","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100023","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100024","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100025","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100026","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100027","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100028","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100029","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100030","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100031","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100032","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100033","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100034","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100035","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100036","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100037","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u78b0\u649e\u6b21\u6570","question":{"questionId":"100038","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e00\u9898","question":{"questionId":"100039","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e8c\u9898","question":{"questionId":"100040","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e09\u9898","question":{"questionId":"100041","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u56db\u9898","question":{"questionId":"100042","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e94\u9898","question":{"questionId":"100043","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u516d\u9898","question":{"questionId":"100044","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e00\u9898","question":{"questionId":"100045","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e8c\u9898","question":{"questionId":"100046","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e09\u9898","question":{"questionId":"100047","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u56db\u9898","question":{"questionId":"100048","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e94\u9898","question":{"questionId":"100049","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u516d\u9898","question":{"questionId":"100050","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u8eab\u4efd\u9a8c\u8bc1\u9898","question":{"questionId":"100051","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u8eab\u4efd\u9a8c\u8bc1\u9898","question":{"questionId":"100052","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u4ea4\u6362\u6b21\u6570\u4f7f\u5f97\u6570\u7ec4\u6709\u5e8f","question":{"questionId":"100065","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u529b\u6263\u8c61\u68cb\u5b66\u5802","question":{"questionId":"100091","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5f0f\u5316\u7b80","question":{"questionId":"100092","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8986\u76d6","question":{"questionId":"100093","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d1 LeetCoin","question":{"questionId":"100094","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u673a\u5668\u4eba\u5927\u5192\u9669","question":{"questionId":"100096","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6590\u6ce2\u90a3\u5951\u6570\u5217","question":{"questionId":"100103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217","question":{"questionId":"100104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56f4\u6210\u4e00\u5708","question":{"questionId":"100105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f","question":{"questionId":"100106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57","question":{"questionId":"100107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c11\u4ea4\u6362\u6b21\u6570 - LC","question":{"questionId":"100125","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u4e92\u8bc4","question":{"questionId":"100129","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7535\u68af","question":{"questionId":"100130","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u9a8c\u8bc1","question":{"questionId":"100136","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d4b\u8bd5","question":{"questionId":"100139","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6df1\u5ea6","question":{"questionId":"100144","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u8fd1\u7684\u4fbf\u5229\u5e97","question":{"questionId":"100145","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u75c5\u6bd2","question":{"questionId":"100146","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d88\u9664\u56de\u6587\u5b50\u4e32","question":{"questionId":"100147","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"PK","question":{"questionId":"100148","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4efb\u52a1\u8ba1\u5212","question":{"questionId":"100149","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56e2\u5efa\u5c0f\u6e38\u620f","question":{"questionId":"100150","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fd\u5bb6\u7ed3\u76df -- 952 \u91cd\u590d","question":{"questionId":"100151","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u503c","question":{"questionId":"100152","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5feb\u9012\u5458\u6d3e\u4ef6","question":{"questionId":"100153","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u8fde\u770b","question":{"questionId":"100154","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684 IP \u5730\u5740","question":{"questionId":"100155","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d4b\u8bd5\u626b\u5730\u673a\u5668\u4eba","question":{"questionId":"100156","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d3b\u8dc3\u7528\u6237","question":{"questionId":"100157","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u5b9a\u5b57\u7b26\u662f\u5426\u552f\u4e00","question":{"questionId":"100158","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u5b9a\u662f\u5426\u4e92\u4e3a\u5b57\u7b26\u91cd\u6392","question":{"questionId":"100159","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"URL\u5316","question":{"questionId":"100160","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u538b\u7f29","question":{"questionId":"100161","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u8f6e\u8f6c","question":{"questionId":"100162","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u91cd\u590d\u8282\u70b9","question":{"questionId":"100163","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u94fe\u8868","question":{"questionId":"100164","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u76f8\u4ea4","question":{"questionId":"100167","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u8def\u68c0\u6d4b","question":{"questionId":"100168","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6808\u7684\u6700\u5c0f\u503c","question":{"questionId":"100169","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5316\u6808\u4e3a\u961f","question":{"questionId":"100170","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8282\u70b9\u95f4\u901a\u8def","question":{"questionId":"100171","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u5408\u4e00","question":{"questionId":"100172","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6808\u6392\u5e8f","question":{"questionId":"100173","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9ad8\u5ea6\u6811","question":{"questionId":"100174","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7279\u5b9a\u6df1\u5ea6\u8282\u70b9\u94fe\u8868","question":{"questionId":"100175","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u5e73\u8861\u6027","question":{"questionId":"100176","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u6cd5\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"100177","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u540e\u7ee7\u8005","question":{"questionId":"100178","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9996\u4e2a\u5171\u540c\u7956\u5148","question":{"questionId":"100179","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63d2\u5165","question":{"questionId":"100180","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u8f6c\u6362","question":{"questionId":"100181","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u914d\u5bf9\u4ea4\u6362","question":{"questionId":"100182","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u6570","question":{"questionId":"100183","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6392\u5217","question":{"questionId":"100184","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u77e9\u9635","question":{"questionId":"100185","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96f6\u77e9\u9635","question":{"questionId":"100186","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e2d\u95f4\u8282\u70b9","question":{"questionId":"100187","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u6c42\u548c","question":{"questionId":"100188","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u897f\u6e38\u8bb0","question":{"questionId":"100189","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"ETC \u901a\u9053","question":{"questionId":"100190","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u5316\u53c2\u8d5b\u961f\u4f0d","question":{"questionId":"100191","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ed1\u767d\u68cb","question":{"questionId":"100193","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2048 \u6e38\u620f","question":{"questionId":"100194","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5806\u76d8\u5b50","question":{"questionId":"100195","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed8\u5236\u76f4\u7ebf","question":{"questionId":"100196","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u6b65\u95ee\u9898","question":{"questionId":"100197","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e42\u96c6","question":{"questionId":"100198","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u5f52\u4e58\u6cd5","question":{"questionId":"100199","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62ec\u53f7","question":{"questionId":"100200","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u989c\u8272\u586b\u5145","question":{"questionId":"100201","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5806\u7bb1\u5b50","question":{"questionId":"100202","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u6570\u8f6c\u5b57\u7b26\u4e32","question":{"questionId":"100203","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u70b9\u4eae\u5723\u8bde\u6811","question":{"questionId":"100206","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab\u91cd\u529b\u7403","question":{"questionId":"100207","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e9\u9910\u9ad8\u5cf0","question":{"questionId":"100208","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"}]}} \ No newline at end of file diff --git a/Week 07/id_106/1122.relative-sort-array.java b/Week 07/id_106/1122.relative-sort-array.java new file mode 100644 index 000000000..46b539d8e --- /dev/null +++ b/Week 07/id_106/1122.relative-sort-array.java @@ -0,0 +1,62 @@ +/* + * @lc app=leetcode id=1122 lang=java + * + * [1122] Relative Sort Array + * + * https://leetcode.com/problems/relative-sort-array/description/ + * + * algorithms + * Easy (66.19%) + * Likes: 301 + * Dislikes: 22 + * Total Accepted: 30.6K + * Total Submissions: 46K + * Testcase Example: '[2,3,1,3,2,4,6,7,9,2,19]\n[2,1,4,3,9,6]' + * + * Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all + * elements in arr2 are also in arr1. + * + * Sort the elements of arr1 such that the relative ordering of items in arr1 + * are the same as in arr2.  Elements that don't appear in arr2 should be + * placed at the end of arr1 in ascending order. + * + * + * Example 1: + * Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] + * Output: [2,2,2,1,4,3,3,9,6,7,19] + * + * + * Constraints: + * + * + * arr1.length, arr2.length <= 1000 + * 0 <= arr1[i], arr2[i] <= 1000 + * Each arr2[i] is distinct. + * Each arr2[i] is in arr1. + * + * + */ + +// @lc code=start +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] cnt = new int[1001]; + for(int n : arr1) cnt[n]++; + int i = 0; + for(int n : arr2) { + while(cnt[n]-- > 0) { + arr1[i++] = n; + } + } + for(int n = 0; n < cnt.length; n++) { + while(cnt[n]-- > 0) { + arr1[i++] = n; + } + } + return arr1; + } +} +// @lc code=end +/** + * + */ diff --git a/Week 07/id_106/493.reverse-pairs.java b/Week 07/id_106/493.reverse-pairs.java new file mode 100644 index 000000000..a7c2150a2 --- /dev/null +++ b/Week 07/id_106/493.reverse-pairs.java @@ -0,0 +1,63 @@ +/* + * @lc app=leetcode id=493 lang=java + * + * [493] Reverse Pairs + * + * https://leetcode.com/problems/reverse-pairs/description/ + * + * algorithms + * Hard (23.82%) + * Likes: 650 + * Dislikes: 97 + * Total Accepted: 30.2K + * Total Submissions: 125.7K + * Testcase Example: '[1,3,2,3,1]' + * + * Given an array nums, we call (i, j) an important reverse pair if i < j and + * nums[i] > 2*nums[j]. + * + * You need to return the number of important reverse pairs in the given + * array. + * + * Example1: + * + * Input: [1,3,2,3,1] + * Output: 2 + * + * + * Example2: + * + * Input: [2,4,3,5,1] + * Output: 3 + * + * + * Note: + * + * The length of the given array will not exceed 50,000. + * All the numbers in the input array are in the range of 32-bit integer. + * + * + */ + +// @lc code=start +class Solution { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length-1); + } + private int mergeSort(int[] nums, int s, int e){ + if(s>=e) return 0; + int mid = s + (e-s)/2; + int cnt = mergeSort(nums, s, mid) + mergeSort(nums, mid+1, e); + for(int i = s, j = mid+1; i<=mid; i++){ + while(j<=e && nums[i]/2.0 > nums[j]) j++; + cnt += j-(mid+1); + } + Arrays.sort(nums, s, e+1); + return cnt; + } +} +// @lc code=end +/** + * 归并排序 + * + */ diff --git a/Week 07/id_106/NOTE.md b/Week 07/id_106/NOTE.md index a6321d6e2..3fc659f62 100644 --- a/Week 07/id_106/NOTE.md +++ b/Week 07/id_106/NOTE.md @@ -1,4 +1,107 @@ -# NOTE +# 20191125-1201学习总结 +本周学习了位运算,布隆过滤器LRU缓存的概念,以及常用的排序算法的概念 +O(n^2) 排序算法 +选择排序,插入排序,冒泡排序 +O(nlogn) 排序算法(需要熟练掌握) +快速排序 归并排序 堆排序 + +代码模板: +快速排序 +```java + +class Quicksort{ + + public static void quickSort(int[] array, int begin, int end) { + if (end <= begin) return; + int pivot = partition(array, begin, end); + quickSort(array, begin, pivot - 1); + quickSort(array, pivot + 1, end); + } + + static int partition(int[] a, int begin, int end) { + // pivot: 标杆位置,counter: 小于pivot的元素的个数 + int pivot = end, counter = begin; + for (int i = begin; i < end; i++) { + if (a[i] < a[pivot]) { + int temp = a[counter]; a[counter] = a[i]; a[i] = temp; + counter++; + } + } + int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp; + return counter; + } + +} +``` + +归并排序 +```java +class Mergesort{ + public static void mergeSort(int[] array, int left, int right) { + + if (right <= left) return; + int mid = (left + right) >> 1; // (left + right) / 2 + + mergeSort(array, left, mid); + mergeSort(array, mid + 1, right); + merge(array, left, mid, right); + + } + + public static void merge(int[] arr, int left, int mid, int right) { + + int[] temp = new int[right - left + 1]; // 中间数组 + int i = left, j = mid + 1, k = 0; + + while (i <= mid && j <= right) { + temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; + } + + while (i <= mid) temp[k++] = arr[i++]; + while (j <= right) temp[k++] = arr[j++]; + + for (int p = 0; p < temp.length; p++) { + arr[left + p] = temp[p]; + } + // 也可以用 System.arraycopy(a, start1, b, start2, length) + } +} +``` + +堆排序 +```java +class Heapsort{ + static void heapify(int[] array, int length, int i) { + int left = 2 * i + 1, right = 2 * i + 2; + int largest = i; + + if (left < length && array[left] > array[largest]) { + largest = left; + } + if (right < length && array[right] > array[largest]) { + largest = right; + } + + if (largest != i) { + int temp = array[i]; array[i] = array[largest]; array[largest] = temp; + heapify(array, length, largest); + } + } + + public static void heapSort(int[] array) { + if (array.length == 0) return; + + int length = array.length; + for (int i = length / 2-1; i >= 0; i--) + heapify(array, length, i); + + for (int i = length - 1; i >= 0; i--) { + int temp = array[0]; array[0] = array[i]; array[i] = temp; + heapify(array, i, 0); + } + } +} +``` diff --git a/Week 07/id_126/LeetCode_146_126.py b/Week 07/id_126/LeetCode_146_126.py new file mode 100644 index 000000000..ef1947913 --- /dev/null +++ b/Week 07/id_126/LeetCode_146_126.py @@ -0,0 +1,31 @@ +from collections import OrderedDict +class LRUCache(OrderedDict): + + def __init__(self, capacity): + """ + :type capacity: int + """ + self.capacity = capacity + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key not in self: + return - 1 + + self.move_to_end(key) + return self[key] + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: void + """ + if key in self: + self.move_to_end(key) + self[key] = value + if len(self) > self.capacity: + self.popitem(last = False) \ No newline at end of file diff --git a/Week 07/id_126/LeetCode_231_126.py b/Week 07/id_126/LeetCode_231_126.py new file mode 100644 index 000000000..e9c93bd1f --- /dev/null +++ b/Week 07/id_126/LeetCode_231_126.py @@ -0,0 +1,3 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and n & (n - 1) == 0 \ No newline at end of file diff --git a/Week 07/id_131/LeetCode_190_131.java b/Week 07/id_131/LeetCode_190_131.java new file mode 100644 index 000000000..0b0159db9 --- /dev/null +++ b/Week 07/id_131/LeetCode_190_131.java @@ -0,0 +1,10 @@ +package com.lzhlyle.leetcode.self.no190; + +public class ReverseBits { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int res = 0b0, i = 0; + while (i++ < 32) res = (res << 1) | ((n >>> (i - 1)) & 1); + return res; + } +} diff --git a/Week 07/id_131/LeetCode_191_131.java b/Week 07/id_131/LeetCode_191_131.java new file mode 100644 index 000000000..d32a041a5 --- /dev/null +++ b/Week 07/id_131/LeetCode_191_131.java @@ -0,0 +1,13 @@ +package com.lzhlyle.leetcode.self.no191; + +public class NumbersOf1Bits { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + n = n & (n - 1); + count++; + } + return count; + } +} diff --git a/Week 07/id_131/LeetCode_231_131.java b/Week 07/id_131/LeetCode_231_131.java new file mode 100644 index 000000000..2890e1980 --- /dev/null +++ b/Week 07/id_131/LeetCode_231_131.java @@ -0,0 +1,7 @@ +package com.lzhlyle.leetcode.self.no231; + +public class PowerOfTwo { + public boolean isPowerOfTwo(int n) { + return (n > 0) && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_131/LeetCode_338_131.java b/Week 07/id_131/LeetCode_338_131.java new file mode 100644 index 000000000..813dadb83 --- /dev/null +++ b/Week 07/id_131/LeetCode_338_131.java @@ -0,0 +1,12 @@ +package com.lzhlyle.leetcode.self.no338; + +public class CountingBits_2 { + // dp + public int[] countBits(int num) { + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_131/LeetCode_51_131.java b/Week 07/id_131/LeetCode_51_131.java new file mode 100644 index 000000000..e5ff4e838 --- /dev/null +++ b/Week 07/id_131/LeetCode_51_131.java @@ -0,0 +1,47 @@ +package com.lzhlyle.leetcode.self.no51; + +import java.util.ArrayList; +import java.util.List; + +public class NQueens_4 { + private List> res; + private int size; + + public List> solveNQueens(int n) { + size = (1 << n) - 1; + res = new ArrayList<>(); + this._locate(0, 0, 0, 0, new int[n]); + return res; + } + + private void _locate(int level, int row, int ld, int rd, int[] solution) { + if (row == size) { + res.add(this.generateSolution(solution)); + return; + } + + int pos = size & (~(row | ld | rd)); + while (pos != 0) { + int p = pos & (-pos); + pos &= pos - 1; + solution[level] = p; + this._locate(level + 1, row | p, (ld | p) << 1, (rd | p) >> 1, solution); + } + } + + private List generateSolution(int[] solution) { + List playout = new ArrayList<>(); + for (int row : solution) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < solution.length; i++) { + builder.append((row >> i & 1) == 1 ? 'Q' : '.'); + } + playout.add(builder.toString()); + } + return playout; + } + + public static void main(String[] args) { + new NQueens_4().solveNQueens(4); + } +} diff --git a/Week 07/id_131/LeetCode_52_131.java b/Week 07/id_131/LeetCode_52_131.java new file mode 100644 index 000000000..1132821ec --- /dev/null +++ b/Week 07/id_131/LeetCode_52_131.java @@ -0,0 +1,26 @@ +package com.lzhlyle.leetcode.self.no52; + +public class NQueensII { + private int size, count; + + public int totalNQueens(int n) { + size = (1 << n) - 1; + count = 0; + this._locate(0, 0, 0); + return count; + } + + private void _locate(int row, int ld, int rd) { + if (row == size) { + count++; + return; + } + + int poss = size & (~(row | ld | rd)); + while (poss != 0) { + int posi = poss & (-poss); + poss &= poss - 1; + this._locate(row | posi, (ld | posi) << 1, (rd | posi) >> 1); + } + } +} diff --git a/Week 07/id_131/LeetCode_56_131.java b/Week 07/id_131/LeetCode_56_131.java new file mode 100644 index 000000000..aef7da052 --- /dev/null +++ b/Week 07/id_131/LeetCode_56_131.java @@ -0,0 +1,35 @@ +package com.lzhlyle.leetcode.recite.no56; + +import java.util.Arrays; + +public class MergeIntervals_2 { + public int[][] merge(int[][] intervals) { + if (intervals == null || intervals.length <= 1) return intervals; + int mergeCount = 0; + for (int i = 0; i < intervals.length; i++) { + for (int j = i + 1; j < intervals.length; j++) { + if (intervals[i][1] >= intervals[j][0] && intervals[i][0] <= intervals[j][1]) { + intervals[j][1] = Math.max(intervals[j][1], intervals[i][1]); + intervals[j][0] = Math.min(intervals[j][0], intervals[i][0]); + intervals[i] = null; + mergeCount++; + break; + } + } + } + + int[][] result = new int[intervals.length - mergeCount][2]; + for (int i = 0, j = 0; j < intervals.length; j++) { + if (intervals[j] != null) result[i++] = intervals[j]; + } + return result; + } + + public static void main(String[] args) { + int[][] intervals = {{1, 4}, {1, 5}, {10, 80}, {0, 6}, {2, 3}}; + // 0, 1, 1, 2, 10 + // 3, 4, 5, 6, 80 + int[][] res = new MergeIntervals_2().merge(intervals); + System.out.println(Arrays.deepToString(res)); + } +} diff --git a/Week 07/id_141/LeetCode_190_141.swift b/Week 07/id_141/LeetCode_190_141.swift new file mode 100644 index 000000000..18a20f872 --- /dev/null +++ b/Week 07/id_141/LeetCode_190_141.swift @@ -0,0 +1,22 @@ +// +// ReverseBits.swift +// algorithm +// +// Created by pingan on 2019/11/28. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//190. 颠倒二进制位 +class ReverseBits { + func reverseBits(_ n: Int) -> Int { + var res = 0; + var m = n; + for _ in 0..<32 { + res <<= 1; + res += m & 1; + m >>= 1; + } + return res; + } +} diff --git a/Week 07/id_141/LeetCode_191_141.swift b/Week 07/id_141/LeetCode_191_141.swift new file mode 100644 index 000000000..7c01057aa --- /dev/null +++ b/Week 07/id_141/LeetCode_191_141.swift @@ -0,0 +1,21 @@ +// +// HammingWeight.swift +// algorithm +// +// Created by pingan on 2019/11/28. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//191. 位1的个数 +class HammingWeight { + func hammingWeight(_ n: Int) -> Int { + var count = 0; + var m = n; + while m != 0 { + m = m & (m - 1); + count += 1; + } + return count; + } +} diff --git a/Week 07/id_141/LeetCode_231_141.swift b/Week 07/id_141/LeetCode_231_141.swift new file mode 100644 index 000000000..e00172a31 --- /dev/null +++ b/Week 07/id_141/LeetCode_231_141.swift @@ -0,0 +1,15 @@ +// +// PowerOfTwo.swift +// algorithm +// +// Created by pingan on 2019/11/28. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation +//231. 2的幂 +class PowerOfTwo { + func powerOfTwo(_ n: Int) -> Bool { + return n != 0 && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_151/LeetCode_1122_151.cpp b/Week 07/id_151/LeetCode_1122_151.cpp new file mode 100644 index 000000000..be5c21965 --- /dev/null +++ b/Week 07/id_151/LeetCode_1122_151.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + map counter; + for (int i : arr1) + counter[i]++; + + int pos = 0; + for (int i = 0; i < arr2.size(); ++i) + while (counter[arr2[i]]-- > 0) + arr1[pos++] = arr2[i]; + for (auto& kv : counter) + while (kv.second-- > 0) + arr1[pos++] = kv.first; + + return arr1; + } +}; diff --git a/Week 07/id_151/LeetCode_191_151.cpp b/Week 07/id_151/LeetCode_191_151.cpp new file mode 100644 index 000000000..00fdea5cf --- /dev/null +++ b/Week 07/id_151/LeetCode_191_151.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + int hammingWeight(uint32_t n) { + int count = 0; + while (n) { + n = n & (n - 1); + ++count; + } + return count; + } +}; diff --git a/Week 07/id_151/LeetCode_231_151.cpp b/Week 07/id_151/LeetCode_231_151.cpp new file mode 100644 index 000000000..8ce5c75bf --- /dev/null +++ b/Week 07/id_151/LeetCode_231_151.cpp @@ -0,0 +1,10 @@ +class Solution { +public: + bool isPowerOfTwo(int n) { + if (n == 0) + return false; + + uint64_t ln = n; + return (ln & (ln - 1)) == 0; + } +}; diff --git a/Week 07/id_151/LeetCode_338_151.cpp b/Week 07/id_151/LeetCode_338_151.cpp new file mode 100644 index 000000000..7c8bfcd0e --- /dev/null +++ b/Week 07/id_151/LeetCode_338_151.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + vector countBits(int num) { + vector ret(num + 1, 0); + for (int i = 1; i <= num; ++i) { + //ret[i] = ret[i & (i - 1)] + ((i & -i) != 0); + ret[i] = ret[i & (i - 1)] + 1; + } + return ret; + } +}; diff --git a/Week 07/id_151/LeetCode_493_151.cpp b/Week 07/id_151/LeetCode_493_151.cpp new file mode 100644 index 000000000..322253ada --- /dev/null +++ b/Week 07/id_151/LeetCode_493_151.cpp @@ -0,0 +1,51 @@ +class Solution { +public: + int reversePairs(vector& nums) { + if (nums.empty()) + return 0; + + int ret = mergeSort(nums, 0, nums.size() - 1); + for (const auto& n : nums) cout << n << ","; + return ret; + } + + int mergeSort(vector& nums, int left, int right) { + if (left >= right) + return 0; + + int mid = left + ((right - left) >> 2); + int r1 = mergeSort(nums, left, mid); + int r2 = mergeSort(nums, mid + 1, right); + + int r3 = merge(nums, left, mid, right); + + return r1 + r2 + r3; + } + + int merge(vector& nums, int left, int mid, int right) { + int ret = 0; + int i = left; + int j = mid + 1; + int k = 0; + + for (int l = left, m = mid + 1; l <= mid; ++l) { + while (m <= right && nums[l] > 2L * nums[m]) + ++m; + // 因为左边是升序的, 所以要+=, 而不能把++ret放到上面去 + ret += m - j; + } + + vector tmp(right - left + 1, 0); + while (i <= mid && j <= right) + tmp[k++] = nums[i] < nums[j] ? nums[i++] : nums[j++]; + + while (i <= mid) + tmp[k++] = nums[i++]; + + while (j <= right) + tmp[k++] = nums[j++]; + + copy(tmp.begin(), tmp.end(), nums.begin() + left); + return ret; + } +}; diff --git a/Week 07/id_151/LeetCode_51_151.cpp b/Week 07/id_151/LeetCode_51_151.cpp new file mode 100644 index 000000000..45c647d93 --- /dev/null +++ b/Week 07/id_151/LeetCode_51_151.cpp @@ -0,0 +1,30 @@ +class Solution { +public: + vector> solveNQueens(int n) { + vector> ret; + vector cur(n, string(n, '.')); + set shu, pie, na; + solve(ret, cur, shu, pie, na, 0, n); + return ret; + } + + void solve(vector>& ret, vector& cur, + set& shu, set& pie, set& na, int level, int n) { + if (level == n) { + ret.push_back(cur); + } + for (int x = 0; x < n; ++x) { + if (! shu.count(x) && ! pie.count(level - x) && ! na.count(x + level)) { + cur[level][x] = 'Q'; + shu.insert(x); + pie.insert(level - x); + na.insert(x + level); + solve(ret, cur, shu, pie, na, level + 1, n); + na.erase(x + level); + pie.erase(level - x); + shu.erase(x); + cur[level][x] = '.'; + } + } + } +}; diff --git a/Week 07/id_151/LeetCode_52_151.cpp b/Week 07/id_151/LeetCode_52_151.cpp new file mode 100644 index 000000000..2c012e0c9 --- /dev/null +++ b/Week 07/id_151/LeetCode_52_151.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int totalNQueens(int n) { + int count = 0; + solve(0, n, 0, 0, 0, count); + + return count; + } + + void solve(int level, int n, uint32_t shu, uint32_t pie, uint32_t na, int& count) { + if (level >= n) { + ++count; + return; + } + + uint32_t bit = (~(shu | pie | na)) & ((1 << n) - 1); + while (bit) { + uint32_t p = bit & -bit; + bit = bit & (bit - 1); + solve(level + 1, n, shu | p, (pie | p) << 1, (na | p) >> 1, count); + } + } +}; diff --git a/Week 07/id_151/LeetCode_56_151.cpp b/Week 07/id_151/LeetCode_56_151.cpp new file mode 100644 index 000000000..e6f69abcc --- /dev/null +++ b/Week 07/id_151/LeetCode_56_151.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + vector> merge(vector>& intervals) { + vector> ret; + + if (intervals.empty()) + return ret; + + sort(intervals.begin(), intervals.end()); + + ret.push_back(intervals[0]); + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i][0] <= ret[ret.size() - 1][1]) { + ret[ret.size() - 1][1] = max(ret[ret.size() - 1][1], intervals[i][1]); + } else { + ret.push_back(intervals[i]); + } + } + + return ret; + } +}; diff --git a/Week 07/id_161/NumberOf1Bits.java b/Week 07/id_161/NumberOf1Bits.java new file mode 100644 index 000000000..ef0b98b12 --- /dev/null +++ b/Week 07/id_161/NumberOf1Bits.java @@ -0,0 +1,11 @@ +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 & (n - 1); + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_161/ReverseBits b/Week 07/id_161/ReverseBits new file mode 100644 index 000000000..4a7fede47 --- /dev/null +++ b/Week 07/id_161/ReverseBits @@ -0,0 +1,13 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int ret = 0; + for(int i = 0; i < 32; i++) { + int current = n & 1; + ret = ret << 1; + ret = ret | current; + n = n >> 1; + } + return ret; + } +} \ No newline at end of file diff --git a/Week 07/id_161/SortArray.java b/Week 07/id_161/SortArray.java new file mode 100644 index 000000000..f37948856 --- /dev/null +++ b/Week 07/id_161/SortArray.java @@ -0,0 +1,25 @@ +public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] m = new int[1001]; + + int[] ref = new int[arr1.length]; + + for(int i = 0; i < arr1.length; i++) { + m[arr1[i]]++; + } + + int cnt = 0; + for(int i = 0; i < arr2.length; i++) { + while(m[arr2[i]] > 0) { + ref[cnt++] = arr2[i]; + m[arr2[i]]--; + } + } + + for(int i = 0; i < 1001; i++) { + while(m[i] > 0) { + ref[cnt++] = i; + m[i]--; + } + } + return ref; +} diff --git a/Week 07/id_171/CountingBitsSol.cs b/Week 07/id_171/CountingBitsSol.cs new file mode 100644 index 000000000..d101cdf08 --- /dev/null +++ b/Week 07/id_171/CountingBitsSol.cs @@ -0,0 +1,27 @@ +namespace Poplar.Algorithm.WeekSeven +{ + /// + /// 比特位计数 + /// https://leetcode.com/problems/counting-bits + /// https://leetcode-cn.com/problems/counting-bits + /// + public class CountingBitsSol + { + /// + /// 比特位计数 + /// 时间复杂度O(n)。 + /// n & (n - 1)是打掉最低位的1,所以n比n & (n - 1)多一个1。 + /// + /// + /// + public int[] CountBits(int num) + { + var container = new int[num < 0 ? 1 : num + 1]; + for (int i = 1; i < num + 1; i++) + { + container[i] = container[i & (i - 1)] + 1; + } + return container; + } + } +} diff --git a/Week 07/id_171/NumberOf1BitsSol.cs b/Week 07/id_171/NumberOf1BitsSol.cs new file mode 100644 index 000000000..c6c13ad78 --- /dev/null +++ b/Week 07/id_171/NumberOf1BitsSol.cs @@ -0,0 +1,40 @@ +namespace Poplar.Algorithm.WeekSeven +{ + /// + /// 位1的个数 + /// https://leetcode.com/problems/number-of-1-bits + /// https://leetcode-cn.com/problems/number-of-1-bits + /// + public class NumberOf1BitsSol + { + public int HammingWeight(uint n) + { + var count = 0; + while (n > 0) + { + count++; + n = n & (n - 1); + } + return count; + } + + /// + /// O(n)的时间复杂度 + /// + /// + /// + public int HammingWeightOne(uint n) + { + var count = 0; + while (n > 0) + { + if ((n & 1) > 0) + { + count++; + } + n = n >> 1; + } + return count; + } + } +} diff --git a/Week 07/id_171/PowerOfTwoSol.cs b/Week 07/id_171/PowerOfTwoSol.cs new file mode 100644 index 000000000..2295c9823 --- /dev/null +++ b/Week 07/id_171/PowerOfTwoSol.cs @@ -0,0 +1,20 @@ +namespace Poplar.Algorithm.WeekSeven +{ + /// + /// 2的幂 + /// https://leetcode.com/problems/power-of-two + /// https://leetcode-cn.com/problems/power-of-two + /// + public class PowerOfTwoSol + { + /// + /// 2的幂 + /// + /// + /// + public bool IsPowerOfTwo(int n) + { + return n > 0 && (n & (n - 1)) == 0; + } + } +} diff --git a/Week 07/id_176/LeetCode_191_176.py b/Week 07/id_176/LeetCode_191_176.py new file mode 100644 index 000000000..820daa71b --- /dev/null +++ b/Week 07/id_176/LeetCode_191_176.py @@ -0,0 +1,9 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + + while n: + n &= n-1 + count += 1 + + return count \ No newline at end of file diff --git a/Week 07/id_176/LeetCode_231_176.py b/Week 07/id_176/LeetCode_231_176.py new file mode 100644 index 000000000..184b117b5 --- /dev/null +++ b/Week 07/id_176/LeetCode_231_176.py @@ -0,0 +1,3 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and n & (n - 1) == 0 diff --git a/Week 07/id_176/NOTE.md b/Week 07/id_176/NOTE.md index a6321d6e2..dc96f42a2 100644 --- a/Week 07/id_176/NOTE.md +++ b/Week 07/id_176/NOTE.md @@ -1,4 +1,150 @@ -# NOTE +## NOTE +### 指定位置的位运算 + +1. 将 x 最右边的 n 位清零:x & (~0 << n) +2. 获取 x 的第 n 位值(0 或者 1): (x >> n) & 1 +3. 获取 x 的第 n 位的幂值:x & (1 << (n -1)) +4. 仅将第 n 位置为 1:x | (1 << n) +5. 仅将第 n 位置为 0:x & (~ (1 << n)) +6. 将 x 最高位至第 n 位(含)清零:x & ((1 << n) - 1) +7. 将第 n 位至第 0 位(含)清零:x & (~ ((1 << (n + 1)) - 1)) + +###实战位运算要点 + +判断奇偶: + x % 2 == 1 —> (x & 1) == 1 x % 2 == 0 —> (x & 1) == 0 + +x >> 1 —> x / 2 + 即: x = x / 2; —> x = x >> 1; + +mid = (left + right) / 2; —> X = X & (X-1) 清零最低位的 1 + X & -X => 得到最低位的 1 + X & ~X => 0 + +###N皇后位运算解法 + +```python +def totalNQueens(self, n): + if n < 1: return [] + self.count = 0 + self.DFS(n, 0, 0, 0, 0) + return self.count + +def DFS(self, n, row, cols, pie, na): + # recursion terminator + if row >= n: + self.count += 1 + return + + bits=(~(cols|pie|na))&((1<> 1) + # 不需要revert cols, pie, na 的状态 +``` + + + +### 布隆过滤器(Bloom Filter) + +一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索 一个元素是否在一个集合中。 + +优点是空间效率和查询时间都远远超过一般的算法, 缺点是有一定的误识别率和删除困难。 + +```python +from bitarray import bitarray +import mmh3 +class BloomFilter: + def __init__(self, size, hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray(size) + self.bit_array.setall(0) + + def add(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + self.bit_array[result] = 1 + + def lookup(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + if self.bit_array[result] == 0: + return "Nope" + return "Probably" + +bf = BloomFilter(500000, 7) +bf.add("dantezhao") +print (bf.lookup("dantezhao")) +print (bf.lookup("yyj")) +``` + + + +###快速排序(Quick Sort) + +数组取标杆 pivot,将小元素放 pivot左边,大元素放右侧,然后依次 对右边和右边的子数组继续快排;以达到整个序列有序。 + +```java +public static void quickSort(int[] array, int begin, int end) { + if (end <= begin) return; + int pivot = partition(array, begin, end); + quickSort(array, begin, pivot - 1); + quickSort(array, pivot + 1, end); +} + +static int partition(int[] a, int begin, int end) { + + // pivot: 标杆位置,counter: 小于pivot的元素的个数 + int pivot = end, counter = begin; + + for (int i = begin; i < end; i++) { + if (a[i] < a[pivot]) { + int temp = a[counter]; a[counter] = a[i]; a[i] = temp; + counter++; + } + } + int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp; + return counter; +} +``` + + + +###归并排序(Merge Sort) — 分治 + +1. 把长度为n的输入序列分成两个长度为n/2的子序列; +2. 对这两个子序列分别采用归并排序; +3. 将两个排序好的子序列合并成一个最终的排序序列。 + +```java +public static void mergeSort(int[] array, int left, int right) { + if (right <= left) return; + int mid = (left + right) >> 1; // (left + right) / 2 + + mergeSort(array, left, mid); + mergeSort(array, mid + 1, right); + merge(array, left, mid, right); +} + +public static void merge(int[] arr, int left, int mid, int right) { + int[] temp = new int[right - left + 1]; // 中间数组 + int i = left, j = mid + 1, k = 0; + + while (i <= mid && j <= right) { + temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; + } + + while (i <= mid) temp[k++] = arr[i++]; + while (j <= right) temp[k++] = arr[j++]; + for (int p = 0; p < temp.length; p++) { + arr[left + p] = temp[p]; + } + // 也可以用 System.arraycopy(a, start1, b, start2, length) +} +``` diff --git a/Week 07/id_181/Leetcode_1122_181.js b/Week 07/id_181/Leetcode_1122_181.js new file mode 100644 index 000000000..0a7bc1bb1 --- /dev/null +++ b/Week 07/id_181/Leetcode_1122_181.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ +// 计数排序 + +var relativeSortArray = function(arr1, arr2) { + let maxValue = Math.max(...arr1); + // 生成最大的数+1的数组,并填充为0 + let bucket = new Array(maxValue+1).fill(0); + let result = []; + + // 对arr1内的数字进行统计 + for(let i = 0;i < arr1.length;i++){ + bucket[arr1[i]]++; + } + // 根据arr2内的数字依次拿出放到result内 + for(let j = 0;j < arr2.length;j++){ + // 直到bucket内对应数字个数为0时才停止 + while(bucket[arr2[j]] > 0){ + result.push(arr2[j]); + bucket[arr2[j]]--; + } + } + // 按升序拿出剩余的数字 + for(let r = 0;r <= maxValue;r++){ + while(bucket[r] > 0){ + result.push(r); + bucket[r]--; + } + } + return result; +} \ No newline at end of file diff --git a/Week 07/id_181/Leetcode_231_181.js b/Week 07/id_181/Leetcode_231_181.js new file mode 100644 index 000000000..553103546 --- /dev/null +++ b/Week 07/id_181/Leetcode_231_181.js @@ -0,0 +1,9 @@ +/* +若 n = 2^x +x 且 x 为自然数(即 n 为 2 的幂),则一定满足以下条件 +n 二进制最高位为 1,其余所有位为 0; +(n−1) 二进制最高位为 0,其余所有位为 1; +*/ +var isPowerOfTwo = function(n) { + return n > 0 && (n & (n - 1)) == 0 +}; \ No newline at end of file diff --git a/Week 07/id_181/NOTE.md b/Week 07/id_181/NOTE.md index a6321d6e2..bd5704fb9 100644 --- a/Week 07/id_181/NOTE.md +++ b/Week 07/id_181/NOTE.md @@ -1,4 +1,153 @@ # NOTE - +## 位运算 +### 位运算符 +| 含义 | 运算符 | 例子 | +| --- | ---- | -- | +| 左移 | << | 0011 => 0110 | +| 右移 | >> | 0110 => 0011 | +| 按位或 | ︳ | 0011 ------- => 10111011 | +| 按位与 | & | 0011 ------- => 10111011 | +| 按位取反 | ~ | 0011 => 1100 | +| 按位异或 (相同为零不同为一)| ^ | 0011 ------- => 10001011 | + +### 位运算实战 +|描述 | 方法 | +| --- | ---- | +| 判断奇 | x %2 == 1 (x & 1) == 1 | +| 判断偶 | x %2 == 0 (x & 1) == 0 | +| 除二 | x = x / 2 x = x >> 1 | +| 清零最低位的1 | x = x & (x-1) | +| 得到最低位的1 | x & -X | +| 得0 | x & ~x | +| 最大32位整数 | 1 << 31 - 1 | +| 最小32位整数 | -1 << 31 | + +## 排序 + +### 1 冒泡排序 + +时间复杂度 O(n^2),空间复杂度 O(1) + +- 比较相邻的元素,如果第一个比第二个大,就交换位置; +- 对每一对相邻元素重复上述动作 +- 针对所有的元素重复以上的步骤,除了最后的一个 +- 重复上面三步,直到最后一步 + +```js +function bubbleSort(arr) { + let len = arr.length; + for (let i = 0; i < len - 1; i++) { + // 针对所有的元素重复以上的步骤,除了最后的一个 + for (let j = 0; j < len - 1 - i; j++) { + // 比较相邻的元素,如果第一个比第二个大,就交换位置; + if (arr[j] > arr[j + 1]) { + let temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = arr[j]; + } + } + } + + return arr; +} +``` + +### 2 选择排序 + +时间复杂度 O(n^2),空间复杂度 O(1) + +- 在未排序的序列中,找到最小(大)元素放到起始位置,然后在从剩余未排序元素中继续找最小元素 + +```js +function selectionSort(arr) { + let len = arr.length; + + var minIndex, temp; + + for (let i = 0; i < arr.length; i++) { + minIndex = i; + for (let j = i + 1; j < arr.length; j++) { + if (arr[j] < arr[minIndex]) { + minIndex = j; + } + } + temp = arr[i]; + arr[i] = arr[minIndex]; + arr[minIndex] = temp; + } + return arr; +} +``` + +### 3 插入排序 + +- 从第一个元素开始,取出下一个元素,跟之前被排序的元素序列从后向前扫描 +- 如果小于已排序元素,则往前移一位, +- 直到大于或等于已排序元素,则放到该位置后面 +- 重复 + +```js +function insertSort(arr) { + let len = arr.length; + let preIndex, current; + + for (let i = 0; i < len; i++) { + current = arr[i]; + preIndex = i - 1; + while ((preIndex >= 0) & (arr[preIndex] > current)) { + arr[preIndex + 1] = arr[preIndex--]; + } + arr[preIndex + 1] = current; + } + return arr; +} +``` + +### 4 归并排序 + +- 分治 +- 将数组拆成 n/2 的子序列 +- 对这两个子序列分别采用归并排序 +- 将这两个排好序的子序列合并成一个最终的排序序列 + +```js +function mergeSort(arr) { + const len = arr.length; + if (len > 2) return arr; + // 将数组拆成 n/2 的子序列 + const middle = len >> 1; + left = arr.slice(0, middle); + right = arr.slice(middle, len); + + return merge(mergeSort(left), mergeSort(right)); +} + +function merge(left, right) { + const result = []; + + while (left.length > 0 && right.length > 0) { + const item = left[0] <= right[0] ? left.shift() : right.shift(); + result.push(item); + } + + while (left.length > 0) { + result.push(left.shift()); + } + while (right.length > 0) { + result.push(right.shift()); + } + + return result; +} +``` + +### 5 快速排序 +> 通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 + + +扩展学习: + +1 [N 皇后位运算代码示例](https://shimo.im/docs/rHTyt8hcpT6D9Tj8/read) +2 [十大经典排序算法(动图演示) - 一像素 - 博客园](https://www.cnblogs.com/onepixel/p/7674659.html) diff --git a/Week 07/id_196/LeetCode_1122_196.py b/Week 07/id_196/LeetCode_1122_196.py new file mode 100644 index 000000000..fdb1f9faf --- /dev/null +++ b/Week 07/id_196/LeetCode_1122_196.py @@ -0,0 +1,50 @@ +#给你两个数组,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] +# +# +# +# +# 提示: +# +# +# arr1.length, arr2.length <= 1000 +# 0 <= arr1[i], arr2[i] <= 1000 +# arr2 中的元素 arr2[i] 各不相同 +# arr2 中的每个元素 arr2[i] 都出现在 arr1 中 +# +# Related Topics 排序 数组 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + arr = [0 for _ in range(1001)] + ans = [] + for i in range(len(arr1)): + arr[arr1[i]] += 1 + for i in range(len(arr2)): + while arr[arr2[i]] > 0: + ans.append(arr2[i]) + arr[arr2[i]] -= 1 + for i in range(len(arr)): + while arr[i] > 0: + ans.append(i) + arr[i] -= 1 + return ans + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_196/LeetCode_146_196.py b/Week 07/id_196/LeetCode_146_196.py new file mode 100644 index 000000000..711d82db7 --- /dev/null +++ b/Week 07/id_196/LeetCode_146_196.py @@ -0,0 +1,70 @@ +#运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +# +# 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +#写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +# +# 进阶: +# +# 你是否可以在 O(1) 时间复杂度内完成这两种操作? +# +# 示例: +# +# LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +# +#cache.put(1, 1); +#cache.put(2, 2); +#cache.get(1); // 返回 1 +#cache.put(3, 3); // 该操作会使得密钥 2 作废 +#cache.get(2); // 返回 -1 (未找到) +#cache.put(4, 4); // 该操作会使得密钥 1 作废 +#cache.get(1); // 返回 -1 (未找到) +#cache.get(3); // 返回 3 +#cache.get(4); // 返回 4 +# +# Related Topics 设计 + + + +#leetcode submit region begin(Prohibit modification and deletion) +from collections import OrderedDict + + +class LRUCache(OrderedDict): + def __init__(self, capacity): + """ + :type capacity: int + """ + self.capacity = capacity + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key not in self: + return - 1 + + self.move_to_end(key) + return self[key] + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: void + """ + if key in self: + self.move_to_end(key) + self[key] = value + if len(self) > self.capacity: + self.popitem(last=False) + + + + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_196/LeetCode_191_196.py b/Week 07/id_196/LeetCode_191_196.py new file mode 100644 index 000000000..c19285aef --- /dev/null +++ b/Week 07/id_196/LeetCode_191_196.py @@ -0,0 +1,57 @@ +#编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 +# +# +# +# 示例 1: +# +# 输入:00000000000000000000000000001011 +#输出:3 +#解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +# +# +# 示例 2: +# +# 输入:00000000000000000000000010000000 +#输出:1 +#解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +# +# +# 示例 3: +# +# 输入:11111111111111111111111111111101 +#输出:31 +#解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +# +# +# +# 提示: +# +# +# 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +# 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +# +# +# +# +# 进阶: +#如果多次调用这个函数,你将如何优化你的算法? +# Related Topics 位运算 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + count = 0 + while n: + count += n & 1 + n >>= 1 + return count + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_196/LeetCode_231_196.py b/Week 07/id_196/LeetCode_231_196.py new file mode 100644 index 000000000..d5a66ef82 --- /dev/null +++ b/Week 07/id_196/LeetCode_231_196.py @@ -0,0 +1,35 @@ +#给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +# +# 示例 1: +# +# 输入: 1 +#输出: true +#解释: 20 = 1 +# +# 示例 2: +# +# 输入: 16 +#输出: true +#解释: 24 = 16 +# +# 示例 3: +# +# 输入: 218 +#输出: false +# Related Topics 位运算 数学 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + + + return n > 0 and n & (n - 1) == 0 + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_196/LeetCode_242_196.py b/Week 07/id_196/LeetCode_242_196.py new file mode 100644 index 000000000..b9d6946e0 --- /dev/null +++ b/Week 07/id_196/LeetCode_242_196.py @@ -0,0 +1,41 @@ +#给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 +# +# 示例 1: +# +# 输入: s = "anagram", t = "nagaram" +#输出: true +# +# +# 示例 2: +# +# 输入: s = "rat", t = "car" +#输出: false +# +# 说明: +#你可以假设字符串只包含小写字母。 +# +# 进阶: +#如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? +# Related Topics 排序 哈希表 + + + +#leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isAnagram(self, s: str, t: str) -> bool: + # 定义默认布尔值参与后续运算 + result = True + # 利用 Python 数据结构 set 去重去序 + set_tmp = set(s) + # 先判断组成字符串的各个字符元素是否一致 + if set_tmp == set(t): + for i in set_tmp: + # 利用逻辑运算符判断各个字符元素的数量一致,均为 True 才输出 True + result = result and (s.count(i) == t.count(i)) + else: + result = False + return (result) + + + +#leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_201/LeetCode_1122_RelativeSortArray b/Week 07/id_201/LeetCode_1122_RelativeSortArray new file mode 100644 index 000000000..4d5ca0439 --- /dev/null +++ b/Week 07/id_201/LeetCode_1122_RelativeSortArray @@ -0,0 +1,60 @@ + +public class LeetCode_1122_RelativeSortArray { + + /** + * 计数排序法思想 + * @param arr1 + * @param arr2 + * @return + */ + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int index = 0; + int[] countNum = new int[1001]; + for (int i: arr1) { + countNum[i]++; + } + for (int j: arr2) { + while (countNum[j]-- > 0) { + arr1[index++] = j; + } + } + for (int i = 0; i < countNum.length; ++i) { + while (countNum[i]-- > 0) { + arr1[index++] = i; + } + } + return arr1; + } + + /** + * #2 优化 降低空间消耗 + * @param arr1 + * @param arr2 + * @return + */ + public int[] relativeSortArray1(int[] arr1, int[] arr2) { + int index = 0, maxValue = arr1[1], minValue = arr1[1]; + for (int i: arr1) { + if (i < minValue) { + minValue = i; + } else if (i > maxValue) { + maxValue = i; + } + } + int[] countNum = new int[maxValue - minValue + 1]; + for (int i: arr1) { + countNum[i - minValue]++; + } + for (int j: arr2) { + while (countNum[j - minValue]-- > 0) { + arr1[index++] = j; + } + } + for (int i = 0; i < countNum.length; ++i) { + while (countNum[i]-- > 0) { + arr1[index++] = i + minValue; + } + } + return arr1; + } +} diff --git a/Week 07/id_201/LeetCode_146_LRUCache b/Week 07/id_201/LeetCode_146_LRUCache new file mode 100644 index 000000000..e6345a535 --- /dev/null +++ b/Week 07/id_201/LeetCode_146_LRUCache @@ -0,0 +1,92 @@ + +import java.util.Hashtable; + +public class LeetCode_146_LRUCache { + public int remain; + private Hashtable hases; + private DLinkedList1 cache; + + public LeetCode146LRUCache1(int capacity) { + hases = new Hashtable<>(); + cache = new DLinkedList1(); + remain = capacity; + } + + public int get(int key) { + DListNode node = hases.get(key); + if (node == null) + return -1; + cache.moveToHead(node); + return node.value; + } + + public void put(int key, int value) { + DListNode node = hases.get(key); + if (node != null) { + node.value = value; + cache.moveToHead(node); + return; + } + if (remain == 0) { + hases.remove(cache.removeTail().key); + remain++; + } + node = new DListNode(); + node.key = key; + node.value = value; + cache.addHead(node); + hases.put(key, node); + remain--; + } +} + + + +/** + * head and tail 伪head and 伪tail + * 简化代码对于特殊情况的处理 null + * 使得插入的元素都作为中间元素处理 + */ +class DLinkedList1 { + public DListNode head; + public DListNode tail; + + public DLinkedList1() { + head = new DListNode(); + tail = new DListNode(); + head.next = tail; + tail.prev = head; + } + + public void moveToHead(DListNode node) { + if (node.prev == null) { + addHead(node); + } else { + remove(node); + addHead(node); + } + } + + public void addHead(DListNode node) { + node.next = head.next; + node.prev = head; + head.next.prev = node; + head.next = node; + } + + public void remove(DListNode node) { + node.prev.next = node.next; + node.next.prev = node.prev; + } + + public DListNode removeTail() { + DListNode node = tail.prev; + remove(node); + return node; + } +} + +class DListNode { + public DListNode prev, next; + public int key, value; +} diff --git a/Week 07/id_201/LeetCode_190_ReverseBits b/Week 07/id_201/LeetCode_190_ReverseBits new file mode 100644 index 000000000..4465ef97c --- /dev/null +++ b/Week 07/id_201/LeetCode_190_ReverseBits @@ -0,0 +1,13 @@ + +public class LeetCode_190_ReverseBits { + + public int reverseBits(int n) { + int reverseN = 0; + for (int i = 0; i < 32; ++i) { + reverseN <<= 1; + reverseN |= (n & 1); + n >>= 1; + } + return reverseN; + } +} diff --git a/Week 07/id_201/LeetCode_191_HammingWeight b/Week 07/id_201/LeetCode_191_HammingWeight new file mode 100644 index 000000000..04c650681 --- /dev/null +++ b/Week 07/id_201/LeetCode_191_HammingWeight @@ -0,0 +1,27 @@ + +public class LeetCode_191_HammingWeight { + + /** + * n & (n - 1) : 消除最低位的1 + * @param n + * @return + */ + public int hammingWeight(int n) { + int hammingWeight = 0; + while (n != 0) { + hammingWeight++; + n &= n - 1; + } + return hammingWeight; + } + + public int hammingWeight1(int n) { + int hammingWeight = 0; + for (int i = 0; i < 32; i++) { + if ((n & 1) == 1) + hammingWeight++; + n = n >> 1; + } + return hammingWeight; + } +} diff --git a/Week 07/id_201/LeetCode_231_PowerOfTwo b/Week 07/id_201/LeetCode_231_PowerOfTwo new file mode 100644 index 000000000..436b9434e --- /dev/null +++ b/Week 07/id_201/LeetCode_231_PowerOfTwo @@ -0,0 +1,5 @@ +public class LeetCode_231_PowerOfTwo { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_201/LeetCode_338_countBits b/Week 07/id_201/LeetCode_338_countBits new file mode 100644 index 000000000..95a82e28c --- /dev/null +++ b/Week 07/id_201/LeetCode_338_countBits @@ -0,0 +1,20 @@ + +public class LeetCode_338_countBits { + public int[] countBits(int n) { + int[] bits = new int[n + 1]; + for (int i = 1; i <= n; ++i) { + bits[i] = hammingWeight(i); + } + return bits; + } + + public int hammingWeight(int n) { + int hammingWeight = 0; + while (n != 0) { + hammingWeight++; + n &= n - 1; + } + return hammingWeight; + } + +} diff --git a/Week 07/id_201/LeetCode_56_intervals b/Week 07/id_201/LeetCode_56_intervals new file mode 100644 index 000000000..787e8e509 --- /dev/null +++ b/Week 07/id_201/LeetCode_56_intervals @@ -0,0 +1,24 @@ + +public class LeetCode_56_intervals { + + public int[][] merge(int[][] intervals) { + int[] intervalNum = new int[intervals.length << 1]; + int index = 0; + for (int[] interval: intervals) { + if (index == 0) { + intervalNum[index++] = interval[0]; + intervalNum[index] = interval[1]; + } else if (intervalNum[index] >= interval[0]) { + intervalNum[index] = interval[1]; + } else { + intervalNum[++index] = interval[0]; + intervalNum[++index] = interval[1]; + } + } + int[][] intervalMerge = new int[(index + 1) >> 1][2]; + for (int i = 0; i <= index; i += 2) { + intervalMerge[i >> 1] = new int[] {intervalNum[i], intervalNum[i + 1]}; + } + return intervalMerge; + } +} diff --git a/Week 07/id_216/Week07.java b/Week 07/id_216/Week07.java new file mode 100644 index 000000000..b233eff45 --- /dev/null +++ b/Week 07/id_216/Week07.java @@ -0,0 +1,47 @@ +/** + * Created by liuyp on 2019/12/8. + */ +public class Week07 { + //191 + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + + } + + //1122 + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] m = new int[1001]; + + int[] ref = new int[arr1.length]; + + for (int i = 0; i < arr1.length; i++) { + m[arr1[i]]++; + } + + int cnt = 0; + for (int i = 0; i < arr2.length; i++) { + while (m[arr2[i]] > 0) { + ref[cnt++] = arr2[i]; + m[arr2[i]]--; + } + } + + for (int i = 0; i < 1001; i++) { + while (m[i] > 0) { + ref[cnt++] = i; + m[i]--; + } + } + return ref; + } + + +} diff --git a/Week 07/id_241/LeetCode_1122_241.java b/Week 07/id_241/LeetCode_1122_241.java new file mode 100644 index 000000000..239ed4a92 --- /dev/null +++ b/Week 07/id_241/LeetCode_1122_241.java @@ -0,0 +1,19 @@ +import java.util.*; +/** + * 数组的相对排序 + */ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] times = new int[1001], res = new int[arr1.length]; + for (int value : arr1) + times[value]++; + int index = 0; + for (int value : arr2) + while (times[value]-- > 0) + res[index++] = value; + for (int i = 0; i <= 1000; i++) + while (times[i]-- > 0) + res[index++] = i; + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_146_241.java b/Week 07/id_241/LeetCode_146_241.java new file mode 100644 index 000000000..a7f91a885 --- /dev/null +++ b/Week 07/id_241/LeetCode_146_241.java @@ -0,0 +1,96 @@ +import java.util.*; +/** + * LRU缓存机制 + */ +class Solution { + static class LRUCache { + + private HashMap map; + private int size = 0; + private int capacity; + private Node head; + private Node tail; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.map = new HashMap<>(); + head = new Node(); + tail = new Node(); + head.next = tail; + tail.prev = head; + } + + public int get(int key) { + if (map.containsKey(key)) { + Node node = map.get(key); + node.prev.next = node.next; + node.next.prev = node.prev; + Node next = this.head.next; + this.head.next = node; + node.prev = this.head; + node.next = next; + next.prev = node; + return node.value; + } + return -1; + } + + public void put(int key, int value) { + if (map.containsKey(key)) + map.get(key).value = value; + if (get(key) == -1) { + Node newNode = new Node(); + newNode.key = key; + newNode.value = value; + Node next = this.head.next; + this.head.next = newNode; + newNode.prev = this.head; + newNode.next = next; + next.prev = newNode; + map.put(key, newNode); + this.size++; + if (this.size > this.capacity) { + Node last = this.tail.prev; + last.prev.next = this.tail; + this.tail.prev = last.prev; + map.remove(last.key); + } + } + } + + static class Node { + private int key; + private int value; + private Node prev; + private Node next; + } + } + + /** + * LRU缓存机制 + * 调用类库 + */ + static class LRUCache2 extends LinkedHashMap { + + private int capacity; + + public LRUCache2(int capacity) { + super(capacity, 0.75f, true); + this.capacity = capacity; + } + + public int get(int key) { + return super.getOrDefault(key, -1); + } + + public void put(int key, int value) { + super.put(key, value); + } + + //默认返回 false,代表不进行最老值的删除,所以需要重写 + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_190_241.java b/Week 07/id_241/LeetCode_190_241.java new file mode 100644 index 000000000..37e701c95 --- /dev/null +++ b/Week 07/id_241/LeetCode_190_241.java @@ -0,0 +1,15 @@ +import java.util.*; +/** + * 颠倒二进制位 + */ +class Solution { + public int reverseBits(int n) { + int ans = 0; + for (int i = 0; i < 32; i++) { + int last = n & 1; + n >>= 1; + ans = ans | (last << (31 - i)); + } + return ans; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_191_241.java b/Week 07/id_241/LeetCode_191_241.java new file mode 100644 index 000000000..20dd5563b --- /dev/null +++ b/Week 07/id_241/LeetCode_191_241.java @@ -0,0 +1,24 @@ +import java.util.*; +/** + *位1的个数 + */ +class Solution { + + public int hammingWeight(int n) { + int index = 32; + int count = (n & 1) == 1 ? 1 : 0; + while (index-- >= 0) { + if (((n = n >> 1) & 1) == 1) count++; + } + return count; + } + + public int hammingWeight2(int n) { + int count = 0; + while (n != 0) { + n &= (n - 1); //将最低位的 1 变为 0,所以能变多少个,就有多少个 1 + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_231_241.java b/Week 07/id_241/LeetCode_231_241.java new file mode 100644 index 000000000..3d042ac83 --- /dev/null +++ b/Week 07/id_241/LeetCode_231_241.java @@ -0,0 +1,9 @@ +import java.util.*; +/** + * 2的幂 + */ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_242_241.java b/Week 07/id_241/LeetCode_242_241.java new file mode 100644 index 000000000..def061b8c --- /dev/null +++ b/Week 07/id_241/LeetCode_242_241.java @@ -0,0 +1,19 @@ +import java.util.*; +/** + * 有效的字母异位词 + */ +class Solution { + public boolean isAnagram2(String s, String t) { + if (s.length() != t.length()) return false; + int[] arr = new int[26]; + for (int i = 0; i < s.length(); i++) { + arr[s.charAt(i) - 'a']++; + arr[t.charAt(i) - 'a']--; + } + for (int c : arr) { + if (c != 0) + return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_338_241.java b/Week 07/id_241/LeetCode_338_241.java new file mode 100644 index 000000000..5d3f865cc --- /dev/null +++ b/Week 07/id_241/LeetCode_338_241.java @@ -0,0 +1,48 @@ +import java.util.*; +/** + * 比特位计数 + */ +class Solution { + /** + * 比特位计数 + * 傻循环 + */ + public int[] countBits(int num) { + int[] arr = new int[num + 1]; + arr[0] = 0; + for (int i = 1; i <= num; i++) { + int count = 0; + int n = i; + while (n != 0) { + count++; + n = n & (n - 1); + } + arr[i] = count; + } + return arr; + } + + /** + * 比特位计数 + * 最后一位置零,在加 1, + */ + public int[] countBits2(int num) { + int arr[] = new int[num + 1]; + for (int i = 1; i <= num; i++) { + arr[i] = arr[i & (i - 1)] + 1; + } + return arr; + } + + /** + * 比特位计数 + * 右移一位,在加上其奇偶性 + */ + public int[] countBits3(int num) { + int arr[] = new int[num + 1]; + for (int i = 1; i <= num; i++) { + arr[i] = arr[i >> 1] + (i & 1); + } + return arr; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_493_241.java b/Week 07/id_241/LeetCode_493_241.java new file mode 100644 index 000000000..17005082f --- /dev/null +++ b/Week 07/id_241/LeetCode_493_241.java @@ -0,0 +1,57 @@ +import java.util.*; +/** + * 2的幂 + */ +class Solution { + /** + * 翻转对(使用归并排序算法) + */ + public int reversePairs(int[] nums) { + if (nums.length < 2) return 0; + return reversePairsHelper(nums, 0, nums.length - 1); + } + + private int reversePairsHelper(int[] nums, int left, int right) { + if (left >= right) return 0; + int mid = (left + right) >> 1; + int count = reversePairsHelper(nums, left, mid) + reversePairsHelper(nums, mid + 1, right); + for (int i = left, j = mid + 1; i <= mid; i++) { + while (j <= right && nums[i] > (long) nums[j] << 1) j++; + count += j - (mid + 1); + } + int[] tmp = new int[right - left + 1]; + int k = 0, l = left, r = mid + 1; + while (l <= mid && r <= right) + tmp[k++] = nums[l] < nums[r] ? nums[l++] : nums[r++]; + while (l <= mid) tmp[k++] = nums[l++]; + while (r <= right) tmp[k++] = nums[r++]; + System.arraycopy(tmp, 0, nums, left, tmp.length); + return count; + } + + /** + * 翻转对(使用归并排序算法) + * 改进版 + */ + public int reversePairs2(int[] nums) { + if (nums.length < 2) return 0; + return reversePairsHelper(nums, 0, nums.length - 1); + } + + private int reversePairsHelper2(int[] nums, int left, int right) { + if (left >= right) return 0; + int mid = (left + right) >> 1; + int count = reversePairsHelper2(nums, left, mid) + reversePairsHelper2(nums, mid + 1, right); + int[] tmp = new int[right - left + 1]; + int k = 0, j = mid + 1, p = mid + 1; + for (int i = left; i <= mid; i++) { + while (j <= right && nums[i] > (long) nums[j] << 1) j++; + while (p <= right && nums[i] > nums[p]) tmp[k++] = nums[p++]; + tmp[k++] = nums[i]; + count += j - mid - 1; + } + while (p <= right) tmp[k++] = nums[p++]; + System.arraycopy(tmp, 0, nums, left, tmp.length); + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_52_241.java b/Week 07/id_241/LeetCode_52_241.java new file mode 100644 index 000000000..d21717b29 --- /dev/null +++ b/Week 07/id_241/LeetCode_52_241.java @@ -0,0 +1,27 @@ +import java.util.*; +/** + * N皇后 II + */ +class Solution { + private int count = 0; + private int max = 0; + + public int totalNQueens(int n) { + max = (1 << n) - 1; + totalNQueensHelper(0, 0, 0); + return count; + } + + private void totalNQueensHelper(int row, int left, int right) { + if (row == max) { + count++; + return; + } + int pos = max & ~(row | left | right); + while (pos != 0) { + int p = pos & -pos; + pos = pos - p; + totalNQueensHelper(row | p, (left | p) << 1, (right | p) >> 1); + } + } +} \ No newline at end of file diff --git a/Week 07/id_241/LeetCode_56_241.java b/Week 07/id_241/LeetCode_56_241.java new file mode 100644 index 000000000..20f84aecc --- /dev/null +++ b/Week 07/id_241/LeetCode_56_241.java @@ -0,0 +1,22 @@ +import java.util.*; +/** + * 合并区间 + */ +class Solution { + public int[][] merge(int[][] intervals) { + if (intervals == null || intervals.length == 0) return new int[0][]; + List list = new ArrayList<>(); + Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); + int i = 0; + while (i < intervals.length) { + int left = intervals[i][0], right = intervals[i][1]; + while (i < intervals.length - 1 && right >= intervals[i + 1][0]) { + i++; + right = Math.max(right, intervals[i][1]); + } + list.add(new int[]{left, right}); + i++; + } + return list.toArray(new int[0][]); + } +} \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_1122_246.py b/Week 07/id_246/LeetCode_1122_246.py new file mode 100644 index 000000000..dff4fdb59 --- /dev/null +++ b/Week 07/id_246/LeetCode_1122_246.py @@ -0,0 +1,39 @@ +''' +relative-sort-array_1122 + +给你两个数组,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] +  + +提示: + +arr1.length, arr2.length <= 1000 +0 <= arr1[i], arr2[i] <= 1000 +arr2 中的元素 arr2[i] 各不相同 +arr2 中的每个元素 arr2[i] 都出现在 arr1 中 +''' + +#计数排序 +def relativeSortArray(arr1, arr2): + arr = [0 for _ in range(1001)] #生成一个1001大小的数组用来存放每个数出现的次数 + ans = [] + for i in range(len(arr1)): + arr[arr1[i]] += 1 + for i in range(len(arr2)): + while arr[arr2[i]] > 0: + ans.append(arr2[i]) + arr[arr2[i]] -= 1 + for i in range(len(arr)): + while arr[i] > 0: + ans.append(i) + arr[i] -= 1 + return ans diff --git a/Week 07/id_246/LeetCode_1244_246.py b/Week 07/id_246/LeetCode_1244_246.py new file mode 100644 index 000000000..a338d16f5 --- /dev/null +++ b/Week 07/id_246/LeetCode_1244_246.py @@ -0,0 +1,63 @@ +''' +design-a-leaderboard_1244 + +请你帮忙来设计这个 Leaderboard 类,使得它有如下 3 个函数: + +addScore(playerId, score): +假如参赛者已经在排行榜上,就给他的当前得分增加 score 点分值并更新排行。 +假如该参赛者不在排行榜上,就把他添加到榜单上,并且将分数设置为 score。 +top(K):返回前 K 名参赛者的 得分总和。 +reset(playerId):将指定参赛者的成绩清零。题目保证在调用此函数前,该参赛者已有成绩,并且在榜单上。 +请注意,在初始状态下,排行榜是空的。 + +  + +示例 1: +输入: +["Leaderboard","addScore","addScore","addScore","addScore","addScore","top","reset","reset","addScore","top"] +[[],[1,73],[2,56],[3,39],[4,51],[5,4],[1],[1],[2],[2,51],[3]] +输出: +[null,null,null,null,null,null,73,null,null,null,141] + +解释: +Leaderboard leaderboard = new Leaderboard (); +leaderboard.addScore(1,73); // leaderboard = [[1,73]]; +leaderboard.addScore(2,56); // leaderboard = [[1,73],[2,56]]; +leaderboard.addScore(3,39); // leaderboard = [[1,73],[2,56],[3,39]]; +leaderboard.addScore(4,51); // leaderboard = [[1,73],[2,56],[3,39],[4,51]]; +leaderboard.addScore(5,4); // leaderboard = [[1,73],[2,56],[3,39],[4,51],[5,4]]; +leaderboard.top(1); // returns 73; +leaderboard.reset(1); // leaderboard = [[2,56],[3,39],[4,51],[5,4]]; +leaderboard.reset(2); // leaderboard = [[3,39],[4,51],[5,4]]; +leaderboard.addScore(2,51); // leaderboard = [[2,51],[3,39],[4,51],[5,4]]; +leaderboard.top(3); // returns 141 = 51 + 51 + 39; +  + +提示: + +1 <= playerId, K <= 10000 +题目保证 K 小于或等于当前参赛者的数量 +1 <= score <= 100 +最多进行 1000 次函数调用 +''' + +class Leaderboard: + def __init__(self): + self.leaders = {} + + def addScore(self, playerId, score): + if playerId not in self.leaders: + self.leaders[playerId] = score + else: + self.leaders[playerId] = self.leaders[playerId] + score + + def top(self, K): + players, sum_score = sorted(self.leaders, + key=lambda x:self.leaders[x], reverse=True), 0 + K = min(K, len(self.leaders)) + for p in players[:K]: + sum_score += self.leaders[p] + return sum_score + + def reset(self, playerId: int) -> None: + self.leaders[playerId] = 0 \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_146_246.py b/Week 07/id_246/LeetCode_146_246.py new file mode 100644 index 000000000..635512c70 --- /dev/null +++ b/Week 07/id_246/LeetCode_146_246.py @@ -0,0 +1,101 @@ +''' +lru-cache_146 + +运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 + +获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 + +进阶: + +你是否可以在 O(1) 时间复杂度内完成这两种操作? + +示例: + +LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); + +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // 返回 1 +cache.put(3, 3); // 该操作会使得密钥 2 作废 +cache.get(2); // 返回 -1 (未找到) +cache.put(4, 4); // 该操作会使得密钥 1 作废 +cache.get(1); // 返回 -1 (未找到) +cache.get(3); // 返回 3 +cache.get(4); // 返回 4 +''' + +#有序字典 +from collections import OrderedDict + +class LRUCache(OrderedDict): + def __init__(self, capacity): + self.capacity = capacity + + def get(self, key): + if key not in self: + return -1 + self.move_to_end(key) + return self[key] + + def put(self, key, value): + if key in self: + self.move_to_end(key) + self[key] = value + if len(self) > self.capacity: + self.popitem(last=False) + +# 哈希 + 双向链表 +class ListNode: + def __init__(self, key=None, value=None): + self.key = key + self.value = value + self.prev = None + self.next = None + +class LRUCache: + def __init__(self, capacity): + self.capacity = capacity + self.hashmap = {} + #新建head和tail + self.head = ListNode() + self.tail = ListNode() + #初始化链表H<->T + self.head.next = self.tail + self.tail.prev = self.head + + def move_node_to_tail(self, key): + node = self.hashmap[key] + #将node拎出来 + node.prev.next = node.next + node.next.prev = node.prev + #将node插入到尾结点前 + node.prev = self.tail.prev + node.next = self.tail + self.tail.prev.next = node + self.tail.prev = node + + def get(self, key): + if key in self.hashmap: + self.move_node_to_tail(key) + res = self.hashmap.get(key, -1) + if res == -1: + return res + else: + return res.value + + def put(self, key, value): + if key in self.hashmap: + self.hashmap[key].value = value + self.move_node_to_tail(key) + else: + if len(self.hashmap) == self.capacity: + self.hashmap.pop(self.head.next.key) + self.head.next = self.head.next.next + self.head.next.prev = self.head + new = ListNode(key, value) + self.hashmap[key] = new + new.prev = self.tail.prev + new.next = self.tail + self.tail.prev.next = new + self.tail.prev = new \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_242_246.py b/Week 07/id_246/LeetCode_242_246.py new file mode 100644 index 000000000..e5d59d280 --- /dev/null +++ b/Week 07/id_246/LeetCode_242_246.py @@ -0,0 +1,24 @@ +''' +valid-anagram_242 + +给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + +示例 1: + +输入: s = "anagram", t = "nagaram" +输出: true +示例 2: + +输入: s = "rat", t = "car" +输出: false +''' + +def isAnagram(s, t): + result = True + set_tmp = set(s) + if set_tmp == set(t): + for i in set_tmp: + result = result and (s.count(i) == t.count(i)) + else: + result = False + return result \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_338_246.py b/Week 07/id_246/LeetCode_338_246.py new file mode 100644 index 000000000..ae9dbff28 --- /dev/null +++ b/Week 07/id_246/LeetCode_338_246.py @@ -0,0 +1,25 @@ +''' +counting-bits_338 + +给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 + +示例 1: +输入: 2 +输出: [0,1,1] +''' + +def countBits_1(num): + # dp问题: dp[i] = dp[i>>1] + (i&1). + # i>>1代表前一个二进制位的次数, + # i&1代表i的末尾是否为1 + dp = [0] + for i in range(1, num+1): + dp.append(dp[i>>1] + (i&1)) + return dp + + +def countBits_2(num): + bits = [0] + for i in range(1, num+1): + bits.append(bits[i&(i-1)]+1) + return bits \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_493_246.py b/Week 07/id_246/LeetCode_493_246.py new file mode 100644 index 000000000..174e9d19c --- /dev/null +++ b/Week 07/id_246/LeetCode_493_246.py @@ -0,0 +1,33 @@ +''' +reverse-pairs_493 + +给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。 + +你需要返回给定数组中的重要翻转对的数量。 + +示例 1: + +输入: [1,3,2,3,1] +输出: 2 +示例 2: + +输入: [2,4,3,5,1] +输出: 3 +注意: + +给定数组的长度不会超过50000。 +输入数组中的所有数字都在32位整数的表示范围内。 +''' + +def reversePairs(nums): + res = [0] + def merge(nums): + if len(nums) <= 1, return nums + left, right = merge(nums[:len(nums//2)]), merge(nums[len(nums)//2:]) + for r in right: + add = len(left) - bisect.bisect(left, 2*r) + if not add: break + res[0] += add + return sorted(left+right) + merge(nums) + return res[0] \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_52_246.py b/Week 07/id_246/LeetCode_52_246.py new file mode 100644 index 000000000..5bc74d2d1 --- /dev/null +++ b/Week 07/id_246/LeetCode_52_246.py @@ -0,0 +1,60 @@ +''' +n_queen_ii_52 + +n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + +给定一个整数 n,返回 n 皇后不同的解决方案的数量。 +''' + +#位运算_1 +def totalNQueens_1(n): + def backtrack(row = 0, hills = 0, next_row = 0, dales = 0, count = 0): + """ + :type row: 当前放置皇后的行号 + :type hills: 主对角线占据情况 [1 = 被占据,0 = 未被占据] + :type next_row: 下一行被占据的情况 [1 = 被占据,0 = 未被占据] + :type dales: 次对角线占据情况 [1 = 被占据,0 = 未被占据] + :rtype: 所有可行解的个数 + """ + if row == n: + count += 1 + else: + # [1 = 未被占据,0 = 被占据],和上述变量含义相反 + free_columns = columns & ~(hills | next_row | dales) + + while free_columns: + # free_columns 的第一个为 '1' 的位 + # 在该列我们放置当前皇后 + curr_column = - free_columns & free_columns + # 并且排除对应的列 + free_columns ^= curr_column + count = backtrack(row+1, + (hills|curr_column) <<1, + next_row|curr_column, + (dales|curr_column) >>1, + count) + return count + # 棋盘所有的列都可放置, + # 即,按位表示为 n 个 '1' + # bin(cols) = 0b1111 (n = 4), bin(cols) = 0b111 (n = 3) + # [1 = 可放置] + columns = (1 << n) - 1 + return backtrack() + + +#位运算_2 +def totalNQueens_2(self, n): + if n<1: return [] + self.count = 0 + self.DFS(n,0,0,0,0) + return self.count + +def DFS(self, n, row, cols, pie, na): + if row >= n: + count += 1 + return + bits = (~(cols|pie|na)) & ((1<>1) \ No newline at end of file diff --git a/Week 07/id_246/LeetCode_56_246.py b/Week 07/id_246/LeetCode_56_246.py new file mode 100644 index 000000000..3b7877242 --- /dev/null +++ b/Week 07/id_246/LeetCode_56_246.py @@ -0,0 +1,51 @@ +''' +merge-intervals_56 + +给出一个区间的集合,请合并所有重叠的区间。 + +示例 1: + +输入: [[1,3],[2,6],[8,10],[15,18]] +输出: [[1,6],[8,10],[15,18]] +解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. +示例 2: + +输入: [[1,4],[4,5]] +输出: [[1,5]] +解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 +''' + +#1 +def merge_1(intervals): + if (not intervals): return [] + n = len(intervals) + intervals.sort() + res = [] + left = intervals[0][0] + right = intervals[0][1] + + for i in range(1, n): + if (intervals[i][0] <= right): + if (intervals[i][1] > right): + right = intervals[i][1] + else: + res.append([left, right]) + left = intervals[i][0] + right = intervals[i][1] + res.append([left, right]) + return res + +#2 +def merge_2(intervals): + intervals = sorted(intervals) + res = [] + n = len(intervals) + i = 0 + while (i (x & 1) == 1 +x % 2 == 0 —> (x & 1) == 0 +2. x >> 1 —> x / 2 +即: x = x / 2; —> x = x >> 1; +mid = (left + right) / 2; —> mid = (left + right) >> 1; +3. X = X & (X-1) 清零最低位的 1 +4. X & -X => 得到最低位的 1 +5. X & ~X => 0 + + +【布隆过滤器】 + +1. 一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索,一个元素是否在一个集合中。 +2. 优点是空间效率和查询时间都远远超过一般的算法, +3. 缺点是有一定的误识别率和删除困难。 + + +[排序] + +1. 选择排序,每次找最小值,然后放到待排序数组的起始位置。 +2. 插入排序,从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 +3. 冒泡排序,嵌套循环,每次查看相邻的元素如果逆序,则交换。 +4. 快速排序,数组取标杆 pivot,将小元素放左边,大元素放右侧,然后依次对右边和右边的子数组继续快排;以达到整个序列有序。 +5. 归并排序,先排序左右子数组,然后合并两个有序子数组 +6. 堆排序,数组元素依次建立小顶堆,依次取堆顶元素,并删除 +7. 计数排序,要求输入的数据必须是有确定范围的整数。将输入的数据值转化为键存储在额外开辟的数组空间中;然后依次把计数大于1的填充回原数组 +8. 桶排序:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。 +9. 基数排序:按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。 \ No newline at end of file diff --git a/Week 07/id_251/LeetCode_146_251.py b/Week 07/id_251/LeetCode_146_251.py new file mode 100644 index 000000000..407540933 --- /dev/null +++ b/Week 07/id_251/LeetCode_146_251.py @@ -0,0 +1,134 @@ +# 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +# +# 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +# 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +# +# 进阶: +# +# 你是否可以在 O(1) 时间复杂度内完成这两种操作? +# +# 示例: +# +# LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +# +# cache.put(1, 1); +# cache.put(2, 2); +# cache.get(1); // 返回 1 +# cache.put(3, 3); // 该操作会使得密钥 2 作废 +# cache.get(2); // 返回 -1 (未找到) +# cache.put(4, 4); // 该操作会使得密钥 1 作废 +# cache.get(1); // 返回 -1 (未找到) +# cache.get(3); // 返回 3 +# cache.get(4); // 返回 4 +# +# Related Topics 设计 + +""" +1 有序字典 +2 哈希表 + 双向链表 +""" + +# leetcode submit region begin(Prohibit modification and deletion) +from collections import OrderedDict +class LRUCache(OrderedDict): + + def __init__(self, capacity): + """ + :type capacity: int + """ + self.capacity = capacity + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key not in self: + return -1 + + self.move_to_end(key) + return self[key] + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: None + """ + if key in self: + self.move_to_end(key) + self[key] = value + if len(self) > self.capacity: + self.popitem(last=False) + + +class DLinkedNode: + def __init__(self): + self.key = 0 + self.value = 0 + self.prev = None + self.next = None + + +class LRUCache2: + def _add_node(self, node): + node.prev = self.head + node.next = self.head.next + + self.head.next.prev = node + self.head.next = node + + def _remove_node(self, node): + node.prev.next, node.next.prev = node.next, node.prev + + def _move_to_head(self, node): + self._remove_node(node) + self._add_node(node) + + def _pop_tail(self): + res = self.tail.prev + self._remove_node(res) + return res + + def __init__(self, capacity): + self.cache = {} + self.size = 0 + self.capacity = capacity + self.head, self.tail = DLinkedNode(), DLinkedNode() + + self.head.next = self.tail + self.tail.prev = self.head + + def get(self, key): + node = self.cache.get(key, None) + if not node: + return -1 + + self._move_to_head(node) + return node.value + + def put(self, key, value): + node = self.cache.get(key) + + if not node: + newNode = DLinkedNode() + newNode.key = key + newNode.value = value + + self.cache[key] = newNode + self._add_node(newNode) + + self.size += 1 + + if self.size > self.capacity: + tail = self._pop_tail() + del self.cache[tail.key] + self.size -= 1 + else: + node.value = value + self._move_to_head(node) + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) diff --git a/Week 07/id_251/LeetCode_191_251.py b/Week 07/id_251/LeetCode_191_251.py new file mode 100644 index 000000000..57ec92ba1 --- /dev/null +++ b/Week 07/id_251/LeetCode_191_251.py @@ -0,0 +1,97 @@ +# 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 +# +# +# +# 示例 1: +# +# 输入:00000000000000000000000000001011 +# 输出:3 +# 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +# +# +# 示例 2: +# +# 输入:00000000000000000000000010000000 +# 输出:1 +# 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +# +# +# 示例 3: +# +# 输入:11111111111111111111111111111101 +# 输出:31 +# 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +# +# +# +# 提示: +# +# +# 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +# 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +# +# +# +# +# 进阶: +# 如果多次调用这个函数,你将如何优化你的算法? +# Related Topics 位运算 + +""" +1 Python自带函数 +2 暴力循环 +3 除二取余 +4 位运算 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + return bin(n).count('1') + + +class Solution2(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + n = bin(n) + count = 0 + for i in n: + if i == '1': + count += 1 + return count + + +class Solution3(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + count = 0 + while n: + res = n % 2 + if res == 1: + count += 1 + n //= 2 + return count + + +class Solution4(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + count = 0 + while n: + count += n & 1 + n >>= 1 + return count diff --git a/Week 07/id_251/LeetCode_231_251.py b/Week 07/id_251/LeetCode_231_251.py new file mode 100644 index 000000000..6b3c90b2b --- /dev/null +++ b/Week 07/id_251/LeetCode_231_251.py @@ -0,0 +1,46 @@ +# 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +# +# 示例 1: +# +# 输入: 1 +# 输出: true +# 解释: 20 = 1 +# +# 示例 2: +# +# 输入: 16 +# 输出: true +# 解释: 24 = 16 +# +# 示例 3: +# +# 输入: 218 +# 输出: false +# Related Topics 位运算 数学 + +""" +1 不断除二 +2 位运算 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + if n == 0: return False + while n % 2 == 0: + n //= 2 + return n == 1 + + +class Solution2(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + return n > 0 and n & (n - 1) == 0 diff --git a/Week 07/id_251/LeetCode_52_251.py b/Week 07/id_251/LeetCode_52_251.py new file mode 100644 index 000000000..ee9923238 --- /dev/null +++ b/Week 07/id_251/LeetCode_52_251.py @@ -0,0 +1,73 @@ +# n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +# +# +# +# 上图为 8 皇后问题的一种解法。 +# +# 给定一个整数 n,返回 n 皇后不同的解决方案的数量。 +# +# 示例: +# +# 输入: 4 +# 输出: 2 +# 解释: 4 皇后问题存在如下两个不同的解法。 +# [ +#  [".Q..",  // 解法 1 +#   "...Q", +#   "Q...", +#   "..Q."], +# +#  ["..Q.",  // 解法 2 +#   "Q...", +#   "...Q", +#   ".Q.."] +# ] +# +# Related Topics 回溯算法 +""" +1 回溯法+位运算剪枝 +2 回溯法 剪枝 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def totalNQueens(self, n): + """ + :type n: int + :rtype: int + """ + self.count = 0 + self.DFS(n, 0, 0, 0, 0) + return self.count + + def DFS(self, n, row, cols, pie, na): + if row >= n: + self.count += 1 + return + + bits = (~(cols | pie | na)) & ((1 << n) - 1) # 得到当前所有的空位 + + while bits: + p = bits & -bits # 取到最低位的1 + bits = bits & (bits - 1) # 表示在p位置放入皇后 + self.DFS(n, row + 1, cols | p, (pie | p) << 1, (na | p) >> 1) + + +class Solution2(object): + def totalNQueens(self, n): + """ + :type n: int + :rtype: int + """ + result = [] + self.dfs([], [], [], n, result) + return len(result) + + def dfs(self, queens, xy_dif, xy_sum, n, result): + p = len(queens) + if p == n: + result.append(queens) + for q in range(n): + if q not in queens and p - q not in xy_dif and p + q not in xy_sum: + self.dfs(queens + [q], xy_dif + [p - q], xy_sum + [p + q], n, result) diff --git a/Week 07/id_256/LeetCode_191_256.js b/Week 07/id_256/LeetCode_191_256.js new file mode 100644 index 000000000..41a0b09a6 --- /dev/null +++ b/Week 07/id_256/LeetCode_191_256.js @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=191 lang=javascript + * + * [191] 位1的个数 + */ + +// @lc code=start +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let sum = 0; + while( n != 0) { + //清零最低位的1 + n &= (n-1); + sum++; + } + return sum; +}; +// @lc code=end + diff --git a/Week 07/id_256/LeetCode_231_256.js b/Week 07/id_256/LeetCode_231_256.js new file mode 100644 index 000000000..ef05aa0f0 --- /dev/null +++ b/Week 07/id_256/LeetCode_231_256.js @@ -0,0 +1,18 @@ +/* + * @lc app=leetcode.cn id=231 lang=javascript + * + * [231] 2的幂 + */ + +// @lc code=start +/** + * @param {number} n + * @return {boolean} + */ +var isPowerOfTwo = function(n) { + //位运算 + // 2的幂数的数字的二进制有且只有一个1,其余均是0 + return n > 0 && n & (n-1) == 0; +}; +// @lc code=end + diff --git a/Week 07/id_256/LeetCode_56_256.js b/Week 07/id_256/LeetCode_56_256.js new file mode 100644 index 000000000..18df951dc --- /dev/null +++ b/Week 07/id_256/LeetCode_56_256.js @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=56 lang=javascript + * + * [56] 合并区间 + */ + +// @lc code=start +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +var merge = function(intervals) { + //暴力 + if(intervals.length <= 0) return []; + intervals.sort( (a,b) => a[0] - b[0]); + let i = 0; + let n = intervals.length; + let res = []; + while (i < n) { + let l = intervals[i][0]; + let r = intervals[i][1]; + while(i < n - 1 && intervals[i+1][0] <= r) { + i++; + r = Math.max(r, intervals[i][1]); + } + res.push([l,r]); + i++; + } + return res; +}; +// @lc code=end + diff --git a/Week 07/id_261/leetcode_190_261.go b/Week 07/id_261/leetcode_190_261.go new file mode 100644 index 000000000..b408d1a9a --- /dev/null +++ b/Week 07/id_261/leetcode_190_261.go @@ -0,0 +1,10 @@ +// leetcode : https://leetcode-cn.com/problems/reverse-bits + +func reverseBits(num uint32) uint32 { + result := uint32(0) + for i := 0; i < 32; i++ { + result = (result<<1)|(num&1) + num = num>>1 + } + return result +} \ No newline at end of file diff --git a/Week 07/id_261/leetcode_191_261.go b/Week 07/id_261/leetcode_191_261.go new file mode 100644 index 000000000..0cfc5b461 --- /dev/null +++ b/Week 07/id_261/leetcode_191_261.go @@ -0,0 +1,10 @@ +// leetcode : https://leetcode-cn.com/problems/number-of-1-bits/ + +func hammingWeight(num uint32) int { + c := 0 + for num > 0 { + num &= (num - 1) + c++ + } + return c +} \ No newline at end of file diff --git a/Week 07/id_261/leetcode_231_261.go b/Week 07/id_261/leetcode_231_261.go new file mode 100644 index 000000000..08384a104 --- /dev/null +++ b/Week 07/id_261/leetcode_231_261.go @@ -0,0 +1,5 @@ +// leetcode : https://leetcode-cn.com/problems/power-of-two/ + +func isPowerOfTwo(n int) bool { + return n > 0 && n & (n - 1) == 0 +} \ No newline at end of file diff --git a/Week 07/id_266/266-Week 07 b/Week 07/id_266/266-Week 07 new file mode 100644 index 000000000..8fe6f00be --- /dev/null +++ b/Week 07/id_266/266-Week 07 @@ -0,0 +1,30 @@ +1.位1的个数(number-of-1-bits) + +// 本题的关键:X = X & (X - 1) 意思是把最低一位清零 +// 例: 0000101 & 0000100 = 0000100 +// 0000110 & 0000101 = 0000100 + + +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + count++; + n &= (n - 1); // 把最低一位清零 + } + return count; + } +} + +2.2的幂(power-of-two) + +# isPowerOfTwo = (n > 0) and (n & (n - 1)) == 0 # 因为有且仅有一位是1,所以打掉它这个数就变成0了 + +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + return n > 0 and n & (n - 1) == 0 diff --git a/Week 07/id_276/LeetCode_190.java b/Week 07/id_276/LeetCode_190.java new file mode 100644 index 000000000..0737a31cd --- /dev/null +++ b/Week 07/id_276/LeetCode_190.java @@ -0,0 +1,35 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + //1 + // int result = 0; + // for (int i = 0; i <= 32; i++) { + // // int tmp = n >> i; + // // tmp = tmp & 1; + // // tmp = tmp << (31 - i); + // // result |= tmp; + // result |=(((n >> i) & 1) << (31-i)); + // } + // return result; + //2 + // int res = 0; + // for (int i = 0; i < 32; ++ i) { + // int temp = n >> i; + // temp = temp & 1; + // if (temp == 0) continue; + // temp = temp <<(31 - i); + // res |= temp; + // } + // return res; + //3 + // int ret=n; + // ret = ret >>> 16 | ret<<16; + // ret = (ret & 0xff00ff00) >>> 8 | (ret & 0x00ff00ff) << 8; + // ret = (ret & 0xf0f0f0f0) >>> 4 | (ret & 0x0f0f0f0f) << 4; + // ret = (ret & 0xcccccccc) >>> 2 | (ret & 0x33333333) << 2; + // ret = (ret & 0xaaaaaaaa) >>> 1 | (ret & 0x55555555) << 1; + // return ret; + //4 ʵִ뷽3ͬ + return Integer.reverse(n); + } +} \ No newline at end of file diff --git a/Week 07/id_276/LeetCode_231.java b/Week 07/id_276/LeetCode_231.java new file mode 100644 index 000000000..f7371730a --- /dev/null +++ b/Week 07/id_276/LeetCode_231.java @@ -0,0 +1,6 @@ +class LeetCode_231{ + public boolean isPowerOfTwo(int n) { + //n & (n-1) һҪǿת + return n > 0 && (int)(n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_276/LeetCode_51.java b/Week 07/id_276/LeetCode_51.java new file mode 100644 index 000000000..bc04b0a8c --- /dev/null +++ b/Week 07/id_276/LeetCode_51.java @@ -0,0 +1,41 @@ +class Solution { + //˼·1 + //к֧ȽϺ + private List> queenPlacement = null; + public List> solveNQueens(int n) { + queenPlacement = new ArrayList<>(); + List plaments = new ArrayList<>(); + String rowFill = ""; + for (int i = 0; i < n; ++ i) rowFill += '.'; + for (int i = 0; i < n; ++ i) plaments.add(rowFill); + + placeQueens(n, 0, plaments); + return queenPlacement; + } + + private void placeQueens(int n, int row, List plaments) { + //termination + if (row == n) { + queenPlacement.add(new ArrayList<>(plaments)); + return; + } + + //process + String preRow = plaments.get(row); + for (int col = 0; col < n; ++ col) { + String newRow = preRow.substring(0,col)+'Q'+preRow.substring(col+1); + plaments.set(row, newRow); + if (isValid(row, col, plaments))placeQueens(n, row+1, plaments); + plaments.set(row, preRow); + } + } + + private boolean isValid(int row, int col, List plaments) { + for (int i = 0; i < row; ++ i) { + int diff = Math.abs(col - plaments.get(i).indexOf('Q')); + if ( diff == 0 || row -i == diff) return false; + } + return true; + } + +} \ No newline at end of file diff --git a/Week 07/id_296/LeetCode_231_296.java b/Week 07/id_296/LeetCode_231_296.java new file mode 100644 index 000000000..19d686a41 --- /dev/null +++ b/Week 07/id_296/LeetCode_231_296.java @@ -0,0 +1,14 @@ +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + */ + +// @lc code=start +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} +// @lc code=end + diff --git a/Week 07/id_296/LeetCode_242_296.java b/Week 07/id_296/LeetCode_242_296.java new file mode 100644 index 000000000..40aa2d5fb --- /dev/null +++ b/Week 07/id_296/LeetCode_242_296.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=242 lang=java + * + * [242] 有效的字母异位词 + */ + +// @lc code=start +class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] str1 = s.toCharArray(); + char[] str2 = t.toCharArray(); + Arrays.sort(str1); + Arrays.sort(str2); + return Arrays.equals(str1, str2); + } +} +// @lc code=end + diff --git a/Week 07/id_301/LeetCode_1122_301.go b/Week 07/id_301/LeetCode_1122_301.go new file mode 100644 index 000000000..96547e336 --- /dev/null +++ b/Week 07/id_301/LeetCode_1122_301.go @@ -0,0 +1,43 @@ +package main + +import ( + "sort" +) + +/** +给你两个数组,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] +*/ +func relativeSortArray(arr1 []int, arr2 []int) []int { + sort.Ints(arr1) + + var res []int + mapArr1 := map[int]int{} + for _, v := range arr1 { + if _, ok := mapArr1[v]; ok { + mapArr1[v]++ + } else { + mapArr1[v] = 1 + } + } + for _, v := range arr2 { + for i := 0; i < mapArr1[v]; i++ { + res = append(res, v) + } + delete(mapArr1, v) + } + for _, v := range arr1 { + for i := 0; i < mapArr1[v]; i++ { + res = append(res, v) + } + delete(mapArr1, v) + } + + return res +} diff --git a/Week 07/id_301/LeetCode_56_301.go b/Week 07/id_301/LeetCode_56_301.go new file mode 100644 index 000000000..8e31ad806 --- /dev/null +++ b/Week 07/id_301/LeetCode_56_301.go @@ -0,0 +1,37 @@ +package main + +import "sort" + +/** +给出一个区间的集合,请合并所有重叠的区间。 + +示例 1: + +输入: [[1,3],[2,6],[8,10],[15,18]] +输出: [[1,6],[8,10],[15,18]] +解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. +示例 2: + +输入: [[1,4],[4,5]] +输出: [[1,5]] +解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 +*/ + +func merge(intervals [][]int) [][]int { + n := len(intervals) + sort.Slice(intervals, func(a, b int) bool { + return intervals[a][0] < intervals[b][0] + }) + + for i := 0; i < n-1; i++ { + if intervals[i][1] >= intervals[i+1][0] { + if intervals[i+1][1] > intervals[i][1] { + intervals[i][1] = intervals[i+1][1] + } + intervals = append(intervals[:i+1], intervals[i+2:]...) + i-- + n-- + } + } + return intervals +} diff --git a/Week 07/id_306/CountingBits.java b/Week 07/id_306/CountingBits.java new file mode 100644 index 000000000..c9bdded85 --- /dev/null +++ b/Week 07/id_306/CountingBits.java @@ -0,0 +1,14 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + * 力扣题目地址:https://leetcode-cn.com/problems/counting-bits + */ +public class CountingBits { + public int[] countBits(int num) { + int[] ans = new int[num + 1]; + for (int i = 1; i <= num; ++i) + ans[i] = ans[i & (i - 1)] + 1; + return ans; + } +} diff --git a/Week 07/id_306/DoubleList.java b/Week 07/id_306/DoubleList.java new file mode 100644 index 000000000..63b0384cb --- /dev/null +++ b/Week 07/id_306/DoubleList.java @@ -0,0 +1,45 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + */ +public class DoubleList { + private Node head, tail; // 头尾虚节点 + private int size; // 链表元素数 + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + // 在链表头部添加节点 x + public void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size++; + } + + // 删除链表中的 x 节点(x 一定存在) + public void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size--; + } + + // 删除链表中最后一个节点,并返回该节点 + public Node removeLast() { + if (tail.prev == head) + return null; + Node last = tail.prev; + remove(last); + return last; + } + + // 返回链表长度 + public int size() { return size; } +} diff --git a/Week 07/id_306/LruCache.java b/Week 07/id_306/LruCache.java new file mode 100644 index 000000000..bb07dca17 --- /dev/null +++ b/Week 07/id_306/LruCache.java @@ -0,0 +1,53 @@ +package sf.week7; + +import java.util.HashMap; + +/** + * Created by LynnSun on 2019/12/3. + * 力扣题目地址:https://leetcode-cn.com/problems/lru-cache + */ +public class LruCache { + // key -> Node(key, val) + private HashMap map; + // Node(k1, v1) <-> Node(k2, v2)... + private DoubleList cache; + // 最大容量 + private int cap; + + public LruCache(int capacity) { + this.cap = capacity; + map = new HashMap<>(); + cache = new DoubleList(); + } + + public int get(int key) { + if (!map.containsKey(key)) + return -1; + int val = map.get(key).val; + // 利用 put 方法把该数据提前 + put(key, val); + return val; + } + + public void put(int key, int val) { + // 先把新节点 x 做出来 + Node x = new Node(key, val); + + if (map.containsKey(key)) { + // 删除旧的节点,新的插到头部 + cache.remove(map.get(key)); + cache.addFirst(x); + // 更新 map 中对应的数据 + map.put(key, x); + } else { + if (cap == cache.size()) { + // 删除链表最后一个数据 + Node last = cache.removeLast(); + map.remove(last.key); + } + // 直接添加到头部 + cache.addFirst(x); + map.put(key, x); + } + } +} diff --git a/Week 07/id_306/MergeIntervals.java b/Week 07/id_306/MergeIntervals.java new file mode 100644 index 000000000..d08c2135e --- /dev/null +++ b/Week 07/id_306/MergeIntervals.java @@ -0,0 +1,62 @@ +package sf.week7; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by LynnSun on 2019/12/4. + * 力扣题目地址:https://leetcode-cn.com/problems/merge-intervals + */ +public class MergeIntervals { + private static class Interval { + int start; + int end; + Interval(int[] interval) { + this.start = interval[0]; + this.end = interval[1]; + } + + int[] toArray() { + return new int[]{this.start, this.end}; + } + } + + private static class IntervalComparator implements Comparator { + + @Override + public int compare(Interval a, Interval b) { + return Integer.compare(a.start, b.start); + } + } + + public int[][] merge(int[][] intervals) { + List intervalsList = new LinkedList<>(); + for (int[] interval : intervals) { + intervalsList.add(new Interval(interval)); + } + intervalsList.sort(new IntervalComparator()); + + LinkedList merged = new LinkedList<>(); + for (Interval interval : intervalsList) { + // if the list of merged intervals is empty or if the current + // interval does not overlap with the previous, simply append it. + if (merged.isEmpty() || merged.getLast().end < interval.start) { + merged.add(interval); + } + // otherwise, there is overlap, so we merge the current and previous + // intervals. + else { + merged.getLast().end = Math.max(merged.getLast().end, interval.end); + } + } + + int i = 0; + int[][] result = new int[merged.size()][2]; + for (Interval mergedInterval : merged) { + result[i] = mergedInterval.toArray(); + i++; + } + return result; + } +} diff --git a/Week 07/id_306/NQueensTwo.java b/Week 07/id_306/NQueensTwo.java new file mode 100644 index 000000000..48c00b41f --- /dev/null +++ b/Week 07/id_306/NQueensTwo.java @@ -0,0 +1,30 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + * 力扣题目地址:https://leetcode-cn.com/problems/n-queens-ii + */ +public class NQueensTwo { + private int size; + private int count; + + private void solve(int row, int ld, int rd) { + if (row == size) { + count++; + return; + } + int pos = size & (~(row | ld | rd)); + while (pos != 0) { + int p = pos & (-pos); + pos -= p; // pos &= pos - 1; + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + solve(0, 0, 0); + return count; + } +} diff --git a/Week 07/id_306/Node.java b/Week 07/id_306/Node.java new file mode 100644 index 000000000..24e09ed18 --- /dev/null +++ b/Week 07/id_306/Node.java @@ -0,0 +1,13 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + */ +public class Node { + public int key, val; + public Node next, prev; + public Node(int k, int v) { + this.key = k; + this.val = v; + } +} diff --git a/Week 07/id_306/NumberOfOneBits.java b/Week 07/id_306/NumberOfOneBits.java new file mode 100644 index 000000000..2ead991d5 --- /dev/null +++ b/Week 07/id_306/NumberOfOneBits.java @@ -0,0 +1,16 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + * 力扣题目地址:https://leetcode-cn.com/problems/number-of-1-bits/ + */ +public class NumberOfOneBits { + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } +} diff --git a/Week 07/id_306/PowerOfTwo.java b/Week 07/id_306/PowerOfTwo.java new file mode 100644 index 000000000..cbbbba44f --- /dev/null +++ b/Week 07/id_306/PowerOfTwo.java @@ -0,0 +1,27 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/3. + * 力扣题目地址:https://leetcode-cn.com/problems/power-of-two + */ +public class PowerOfTwo { + public boolean isPowerOfTwo(int n) { + if (n<=0) + return false; + while (n != 0) { + if ((n & 1) != 0)// 判断是否末位是1 + { + if (n == 1) + return true; + else + return false; + } + n = n >> 1; + } + return true; + } + + public boolean isPowerOfTwoOther(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_306/RelativeSortArray.java b/Week 07/id_306/RelativeSortArray.java new file mode 100644 index 000000000..ece55fa75 --- /dev/null +++ b/Week 07/id_306/RelativeSortArray.java @@ -0,0 +1,34 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/4. + * 力扣题目地址:https://leetcode-cn.com/problems/relative-sort-array + */ +public class RelativeSortArray { + // 桶排序 + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] m = new int[1001]; + + int[] ref = new int[arr1.length]; + + for(int i = 0; i < arr1.length; i++) { + m[arr1[i]]++; + } + + int cnt = 0; + for(int i = 0; i < arr2.length; i++) { + while(m[arr2[i]] > 0) { + ref[cnt++] = arr2[i]; + m[arr2[i]]--; + } + } + + for(int i = 0; i < 1001; i++) { + while(m[i] > 0) { + ref[cnt++] = i; + m[i]--; + } + } + return ref; + } +} diff --git a/Week 07/id_306/ReversePairs.java b/Week 07/id_306/ReversePairs.java new file mode 100644 index 000000000..8e457ac2a --- /dev/null +++ b/Week 07/id_306/ReversePairs.java @@ -0,0 +1,27 @@ +package sf.week7; + +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/12/4. + * 力扣题目地址:https://leetcode-cn.com/problems/reverse-pairs + */ +public class ReversePairs { + public int reversePairs(int[] nums) { + return mergeSort(nums,0,nums.length-1); + } + + private int mergeSort(int[] nums, int s, int e) { + if(s>=e) return 0; + int mid=s+(e-s)/2; + int cnt =mergeSort(nums,s,mid)+mergeSort(nums,mid+1,e); + for(int i=s,j=mid+1;i<=mid;i++){ + while (j<=e && nums[i]/2.0>nums[j]){ + j++; + } + cnt+=j-(mid+1); + } + Arrays.sort(nums,s,e+1); + return cnt; + } +} diff --git a/Week 07/id_306/ValidAnagram.java b/Week 07/id_306/ValidAnagram.java new file mode 100644 index 000000000..d4d7b6ba3 --- /dev/null +++ b/Week 07/id_306/ValidAnagram.java @@ -0,0 +1,21 @@ +package sf.week7; + +/** + * Created by LynnSun on 2019/12/4. + * 力扣题目地址:https://leetcode-cn.com/problems/valid-anagram + */ +public class ValidAnagram { + public boolean isAnagram(String s, String t) { + if(s.length() != t.length()) + return false; + int[] alpha = new int[26]; + for(int i = 0; i< s.length(); i++) { + alpha[s.charAt(i) - 'a'] ++; + alpha[t.charAt(i) - 'a'] --; + } + for(int i=0;i<26;i++) + if(alpha[i] != 0) + return false; + return true; + } +} diff --git a/Week 07/id_311/LeetCode_191_Solution.java b/Week 07/id_311/LeetCode_191_Solution.java new file mode 100644 index 000000000..6b9641b27 --- /dev/null +++ b/Week 07/id_311/LeetCode_191_Solution.java @@ -0,0 +1,11 @@ +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int sum = 0; + while(n != 0){ + sum++; + n &= (n -1); + } + return sum; + } +} diff --git a/Week 07/id_311/LeetCode_231_Solution.java b/Week 07/id_311/LeetCode_231_Solution.java new file mode 100644 index 000000000..b2b88698e --- /dev/null +++ b/Week 07/id_311/LeetCode_231_Solution.java @@ -0,0 +1,5 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n -1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_321/LeetCode_146_321.java b/Week 07/id_321/LeetCode_146_321.java new file mode 100644 index 000000000..412a4ab53 --- /dev/null +++ b/Week 07/id_321/LeetCode_146_321.java @@ -0,0 +1,106 @@ +package week07; + +import java.util.HashMap; + +public class LRUCache146 { + + class LRUCache { + // key -> Node(key, val) + private HashMap map; + // Node(k1, v1) <-> Node(k2, v2)... + private DoubleList cache; + // + private int cap; + + public LRUCache(int capacity) { + this.cap = capacity; + map = new HashMap<>(); + cache = new DoubleList(); + } + + public int get(int key) { + if (!map.containsKey(key)) + return -1; + int val = map.get(key).val; + // put Ѹǰ + put(key, val); + return val; + } + + public void put(int key, int val) { + // Ȱ½ڵ x + Node x = new Node(key, val); + + if (map.containsKey(key)) { + // ɾɵĽڵ㣬µIJ嵽ͷ + cache.remove(map.get(key)); + cache.addFirst(x); + // map жӦ + map.put(key, x); + } else { + if (cap == cache.size()) { + // ɾһ + Node last = cache.removeLast(); + map.remove(last.key); + } + // ֱӵͷ + cache.addFirst(x); + map.put(key, x); + } + } + } + +} + +class Node { + public int key, val; + public Node next, prev; + + public Node(int k, int v) { + this.key = k; + this.val = v; + } +} + +class DoubleList { + private Node head, tail; // ͷβڵ + private int size; // Ԫ + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + // ͷӽڵ x + public void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size++; + } + + // ɾе x ڵ㣨x һڣ + public void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size--; + } + + // ɾһڵ㣬ظýڵ + public Node removeLast() { + if (tail.prev == head) + return null; + Node last = tail.prev; + remove(last); + return last; + } + + // + public int size() { + return size; + } +} diff --git a/Week 07/id_321/LeetCode_190_321.java b/Week 07/id_321/LeetCode_190_321.java new file mode 100644 index 000000000..c088cc8f1 --- /dev/null +++ b/Week 07/id_321/LeetCode_190_321.java @@ -0,0 +1,19 @@ +package week07; + +public class ReverseBits190 { + + public int reverseBits1(int n) { + int result = 0; + for (int i = 0; i <= 32; i++) { + + int tmp = (n >> i) & 1; + + // 2. Ȼͨλ㽫õתλ. + tmp = tmp << (31 - i); + // 3. ٴͨϵһ + result |= tmp; + } + return result; + } + +} diff --git a/Week 07/id_321/LeetCode_191_321.java b/Week 07/id_321/LeetCode_191_321.java new file mode 100644 index 000000000..e9da51bb8 --- /dev/null +++ b/Week 07/id_321/LeetCode_191_321.java @@ -0,0 +1,26 @@ +package week07; + +public class HammingWeight191 { + + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + } + + public int hammingWeight2(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } + +} diff --git a/Week 07/id_321/LeetCode_231_321.java b/Week 07/id_321/LeetCode_231_321.java new file mode 100644 index 000000000..fd264be57 --- /dev/null +++ b/Week 07/id_321/LeetCode_231_321.java @@ -0,0 +1,10 @@ +package week07; + +public class IsPowerOfTwo231 { + + //2nݱһ1λ + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + + } +} diff --git a/Week 07/id_321/LeetCode_338_321.java b/Week 07/id_321/LeetCode_338_321.java new file mode 100644 index 000000000..2784c3618 --- /dev/null +++ b/Week 07/id_321/LeetCode_338_321.java @@ -0,0 +1,19 @@ +package week07; + +public class Solution338 { + + public int[] countBits(int num) { + int[] ans = new int[num + 1]; + for (int i = 0; i <= num; ++i) + ans[i] = popcount(i); + return ans; + } + + private int popcount(int x) { + int count; + for (count = 0; x != 0; ++count) + x &= x - 1; + return count; + } + +} diff --git a/Week 07/id_321/LeetCode_52_321.java b/Week 07/id_321/LeetCode_52_321.java new file mode 100644 index 000000000..428bc8932 --- /dev/null +++ b/Week 07/id_321/LeetCode_52_321.java @@ -0,0 +1,27 @@ +package week07; + +public class NQue52 { + + private int size; + private int count; + + private void solve(int row, int ld, int rd) { + if (row == size) { + count++; + return; + } + int pos = size & (~(row | ld | rd)); + while (pos != 0) { + int p = pos & (-pos); + pos -= p; // pos &= pos - 1; + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + solve(0, 0, 0); + return count; + } +} diff --git a/Week 07/id_336/LeetCode_336_190.js b/Week 07/id_336/LeetCode_336_190.js new file mode 100644 index 000000000..879118f3f --- /dev/null +++ b/Week 07/id_336/LeetCode_336_190.js @@ -0,0 +1,31 @@ +// 解法一:位移 + 拼接 +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function(n) { + let result = 0; + for(let i = 0;i < 32;i++){ + result = (result << 1) + (n & 1); + n >>= 1; + } + return result >>> 0; +}; +// 解法二:位移 + 换位 +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function(n) { + let result = 0; + // result从右往移动空出末位 + n从左往右移动获取末位 + n次 = 倒序 + for(let i = 0;i < 32;i++){ + // 左移空出一位 + result <<= 1 + // n&1获取n的末位,result的末位换成n的末位 + result |= n & 1; + // 右移1位 + n >>= 1; + } + return result >>> 0; +}; diff --git a/Week 07/id_336/LeetCode_336_191.js b/Week 07/id_336/LeetCode_336_191.js new file mode 100644 index 000000000..913e0afa4 --- /dev/null +++ b/Week 07/id_336/LeetCode_336_191.js @@ -0,0 +1,12 @@ +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let sum = 0 + while(n != 0){ + sum++ + n &= (n-1) + } + return sum +}; \ No newline at end of file diff --git a/Week 07/id_336/LeetCode_336_231.js b/Week 07/id_336/LeetCode_336_231.js new file mode 100644 index 000000000..04263eb64 --- /dev/null +++ b/Week 07/id_336/LeetCode_336_231.js @@ -0,0 +1,11 @@ +// 解法:2的幂数的数字的二进制特点 + 位操作 +// 2的幂数的数字的二进制有且只有一个1,其余均是0 +// n & (n-1):清零最低位的1 +// 合起来 n & (n-1) == 0 +/** + * @param {number} n + * @return {boolean} + */ +var isPowerOfTwo = function(n) { + return n > 0 && (n & (n-1)) == 0; +}; diff --git a/Week 07/id_346/LeetCode_146_346.java b/Week 07/id_346/LeetCode_146_346.java new file mode 100644 index 000000000..be8d84409 --- /dev/null +++ b/Week 07/id_346/LeetCode_146_346.java @@ -0,0 +1,117 @@ +package suanfa; + +import java.util.Hashtable; + +/** + * @auther: TKQ + * @Title: LeetCode_146_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-12-01 22:01 + */ +public class LeetCode_146_346 { + class DLinkedNode { + int key; + int value; + DLinkedNode prev; + DLinkedNode next; + } + + private void addNode(DLinkedNode node) { + /** + * Always add the new node right after head. + */ + node.prev = head; + node.next = head.next; + + head.next.prev = node; + head.next = node; + } + + private void removeNode(DLinkedNode node) { + /** + * Remove an existing node from the linked list. + */ + DLinkedNode prev = node.prev; + DLinkedNode next = node.next; + + prev.next = next; + next.prev = prev; + } + + private void moveToHead(DLinkedNode node) { + /** + * Move certain node in between to the head. + */ + removeNode(node); + addNode(node); + } + + private DLinkedNode popTail() { + /** + * Pop the current tail. + */ + DLinkedNode res = tail.prev; + removeNode(res); + return res; + } + + private Hashtable cache = + new Hashtable(); + private int size; + private int capacity; + private DLinkedNode head, tail; + + public LeetCode_146_346(int capacity) { + this.size = 0; + this.capacity = capacity; + + head = new DLinkedNode(); + // head.prev = null; + + tail = new DLinkedNode(); + // tail.next = null; + + head.next = tail; + tail.prev = head; + } + + public int get(int key) { + DLinkedNode node = cache.get(key); + if (node == null) return -1; + + // move the accessed node to the head; + moveToHead(node); + + return node.value; + } + + public void put(int key, int value) { + DLinkedNode node = cache.get(key); + + if (node == null) { + DLinkedNode newNode = new DLinkedNode(); + newNode.key = key; + newNode.value = value; + + cache.put(key, newNode); + addNode(newNode); + + ++size; + + if (size > capacity) { + // pop the tail + DLinkedNode tail = popTail(); + cache.remove(tail.key); + --size; + } + } else { + // update the value. + node.value = value; + moveToHead(node); + } + } +} + +} diff --git a/Week 07/id_346/LeetCode_56_346.java b/Week 07/id_346/LeetCode_56_346.java new file mode 100644 index 000000000..be1bae4b8 --- /dev/null +++ b/Week 07/id_346/LeetCode_56_346.java @@ -0,0 +1,42 @@ +package suanfa; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * @auther: TKQ + * @Title: LeetCode_46_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-12-01 22:24 + */ +public class LeetCode_56_346 { + public int[][] merge(int[][] intervals) { + List res = new ArrayList<>(); + if (intervals == null || intervals.length == 0) + return res.toArray(new int[0][]); + + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + // TODO Auto-generated method stub + return o1[0] - o2[0]; + } + }); + int i = 0; + while (i < intervals.length) { + int left = intervals[i][0]; + int right = intervals[i][1]; + while (i < intervals.length - 1 && right >= intervals[i + 1][0]) { + i++; + right = Math.max(right, intervals[i][1]); + } + res.add(new int[] { left, right }); + i++; + } + return res.toArray(new int[0][]); + } +} diff --git a/Week 07/id_361/NOTE.md b/Week 07/id_361/NOTE.md index a6321d6e2..0b51fed2f 100644 --- a/Week 07/id_361/NOTE.md +++ b/Week 07/id_361/NOTE.md @@ -1,4 +1,82 @@ -# NOTE +## 位运算基础及实战要点 +header 1 | header 2 | 示例 | +---|--- |--- +左移 | << | 0011 => 0110 +右移 | >> | 0110 => 0011 +按位或 | \| | 0011 =>1011 1011 +按位与 | & | 0011 =>0011 1011 +按位取反 | ~ | 0011 => 1100 +异或 | ^ | 0011 ^ 0110 => 0100 + + +XOR -异或 +1. x ^ 0 =X +1. x ^ 1s =~x //注意1S = ~0; +1. x ^ (~x) = 1s +1. x ^ x = 0 +1. c = a ^ b => a ^ c =b,b ^ c = a //交换两个数 +1. a ^ b ^ c =a ^(b^c) = (a^b)^c’ + + +指定位置的位运算 +1. 将x最右边的n位清零: x&(0<< n) +2. 获取x的第n位值(0或者1) : (x>>n) & 1 +3. 获取x的第n位的幂值: x&(1 <<(n-1)) +4. 仅将第n位置为1: x|(1 <(x& 1) ==1 +x%2==0-->(x& 1) ==0 +2. x>>1 ->x/2 +3. X=X& (X-1)清零最低位的1 +4. X&-X=>得到最低位的1 +5. X &~X=> 0 + + + +## 布隆过滤器 +- 优点:优点是空间效率和查询时间都远远超过一般的算法; + +- 缺点:缺点是有一定的误识别率和删除困难。 + +一般用布隆过滤器去查是否存在,有一位为0则肯定不存在,反之可能存在,需要进一步去查询(查库等) + + +- 案例 + 比特币网络 + 分布式系统 (Map Reduce)Hadoop、 search engine + Redis缓存 + 垃圾邮件、评论等过滤 + + +## LRU Cahe + 两要素:大小(缓存的大小,超过该大小,根据替换策略执行替换)、替换策略(超出大小的替换原则) + + 数据结构:Hash Table + Double LinkedList; + 时间复杂度:查询-->O(1);修改、更新-->O(1 + + )替换策略:LFU-least frequently used(最不常用替换)、LRU-least recently used(最近最少使用替换) + +##排序 +![image](https://images2018.cnblogs.com/blog/849589/201804/849589-20180402133438219-1946132192.png) + +- 重点nlogon 堆排序、 快速排序、归并排序 +总体分为 比较类和非比较类 + +![image](https://img2018.cnblogs.com/blog/849589/201903/849589-20190306165258970-1789860540.png) + +###初级 +选择 插入 冒泡 + +###高级 +- 归并排序 (Merge Sort) - 分治 +- 堆排序 +###特殊 +计数排序、桶排序、基数排序 diff --git a/Week 07/id_361/leetCode_191_361.js b/Week 07/id_361/leetCode_191_361.js new file mode 100644 index 000000000..1c1e5812e --- /dev/null +++ b/Week 07/id_361/leetCode_191_361.js @@ -0,0 +1,44 @@ +/** + * @param {number} n - a positive integer + * @return {number} + */ +//任何数字跟掩码1进行逻辑与运算,都可以获得这个数字都最低位 +//检查下一位时,将掩码左移一位 +var hammingWeight = function(n) { + let count = 0; + let mask = 1; + for(let i = 0;i < 32;i++){ + if((n & mask) != 0){ + count++; + } + mask <<= 1; + } + return count; +}; + + +/** + * @param {number} n - a positive integer + * @return {number} + */ +// n数字的二进制的最低位的1总是对应n-1数字的二进制的0 +// 相与后,其它位不变,当前位变成0 +var hammingWeight = function(n) { + let sum = 0 + while(n != 0){ + sum++ + n &= (n-1) + } + return sum +}; + + +/** + * @param {number} n - a positive integer + * @return {number} + */ +//调用函数 +var hammingWeight = function(n) { + return ((n.toString(2).match(/1/g)) ||[]).length; +}; + diff --git a/Week 07/id_361/leetCode_242_361.js b/Week 07/id_361/leetCode_242_361.js new file mode 100644 index 000000000..4c245bc6d --- /dev/null +++ b/Week 07/id_361/leetCode_242_361.js @@ -0,0 +1,44 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +//暴力法 +var isAnagram = function(s, t) { + if(s.length != t.length){ + return false; + } + var sSort = s.split('').sort(); + var tSort = t.split('').sort(); + return sSort.join('') == tSort.join(''); +}; + + +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +//计数排序、hashtable +var isAnagram = function(s, t) { + if(s.length != t.length){ + return false; + } + var result = new Array(26); + for(var i = 0;i<26;i++){ + result[i] = 0; + } + var aCode = 'a'.charCodeAt(); + for(var i = 0;i 0) { + flag = true; + } + return flag; + } +} +// @lc code=end + diff --git a/Week 07/id_366/Leetcode_493_366.java b/Week 07/id_366/Leetcode_493_366.java new file mode 100644 index 000000000..3d1b6616d --- /dev/null +++ b/Week 07/id_366/Leetcode_493_366.java @@ -0,0 +1,42 @@ +/* + * @lc app=leetcode.cn id=493 lang=java + * + * [493] 翻转对 + */ + +// @lc code=start +class Solution { + + public int res; + public int reversePairs(int[] nums) { + res = 0; + mergeSort(nums, 0, nums.length-1); + return res; + } + + public void mergeSort(int[] nums, int left, int right) { + if (right <= left) { + return; + } + int middle = left + (right - left)/2; + mergeSort(nums, left, middle); + mergeSort(nums,middle+1, right); + + //count elements + int count = 0; + for (int l = left, r = middle+1; l <= middle;) { + if (r > right || (long)nums[l] <= 2*(long)nums[r]) { + l++; + res += count; + } else { + r++; + count++; + } + } + + //sort + Arrays.sort(nums, left, right + 1); + } +} +// @lc code=end + diff --git a/Week 07/id_371/Leetcode_064_371.java b/Week 07/id_371/Leetcode_064_371.java new file mode 100644 index 000000000..4d0a132db --- /dev/null +++ b/Week 07/id_371/Leetcode_064_371.java @@ -0,0 +1,9 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-30 11:48 + **/ + +public class Leetcode_064_371 { +} diff --git a/Week 07/id_371/Leetcode_1121_371.java b/Week 07/id_371/Leetcode_1121_371.java new file mode 100644 index 000000000..295c49106 --- /dev/null +++ b/Week 07/id_371/Leetcode_1121_371.java @@ -0,0 +1,50 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-27 08:52 + **/ + +public class Leetcode_1121_371 { + public static void main(String[] args) { + int[] arr1 = {2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 19}, arr2 = {2, 1, 4, 3, 9, 6}; + int[] orderedArr = relativeSortArray(arr1, arr2); + Arrays.stream(orderedArr).forEach(System.out::println); + + } + + /** + * 原解1:选择排序 + * + * @author Shaobo.Qian + * @date 2019/11/27 + */ + public static int[] relativeSortArray(int[] arr1, int[] arr2) { + //0.边界判断 + + //1.依次取出 arr2中的每个元素 + int orderedIndex = 0;//arr2中已排定元素的索引(0~orderedIndex,不包含orderedIndex) + for (int i = 0; i < arr2.length; i++) { + //2.将arr2当前元素在 arr1中的位置排定(双指针) + for (int j = orderedIndex; j < arr1.length; j++) { + if (arr1[j] == arr2[i]) { + swap(orderedIndex, j, arr1); + orderedIndex++; + } + } + } + //3.将 arr1未在 arr2中的出现的元素排定 + if (orderedIndex < arr1.length) { + Arrays.sort(arr1, orderedIndex, arr1.length); + } + return arr1; + } + + private static void swap(int index, int j, int[] arr1) { + int temp = arr1[index]; + arr1[index] = arr1[j]; + arr1[j] = temp; + } +} diff --git a/Week 07/id_371/Leetcode_146_371.java b/Week 07/id_371/Leetcode_146_371.java new file mode 100644 index 000000000..c3ab512e0 --- /dev/null +++ b/Week 07/id_371/Leetcode_146_371.java @@ -0,0 +1,133 @@ +import java.util.HashMap; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-27 08:07 + **/ + +public class Leetcode_146_371 { + + + /** + * 仿解:(双向链表+hashmap) + * + * @author Shaobo.Qian + * @date 2019/11/28 + * @link https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/ + */ + class Node { + int key, value; + Node next, prev; + + public Node(int key, int value) { + this.key = key; + this.value = value; + } + } + + class DoubleList { + private Node head, tail;//头尾虚节点,方便指针操作 + private int size; + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + /** + * 在链表头部添加节点 + * + * @param x + */ + public void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size++; + } + + /** + * 删除某个节点(调用方需保证 Node x 存在) + * + * @param x + */ + public void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size--; + } + + /** + * 删除并返回最后一个节点 + * + * @return + */ + public Node removeLast() { + if (tail.prev == head) return null; //没有节点 + Node last = tail.prev; + remove(last); + return last; + } + + /** + * 返回链表中节点的个数 + * + * @return + */ + public int size() { + return size; + } + } + + class LRUCache { + private HashMap map; + private DoubleList cache; + private int cap; + + + public LRUCache(int capacity) { + this.map = new HashMap<>(); + this.cache = new DoubleList(); + this.cap = capacity; + } + + public int get(int key) { + //1.判断是否存在 + if (!map.containsKey(key)) { + return -1; + } else { + int val = map.get(key).value; + //2.将 node 放在链表头部 + put(key, val); + //3.返回 value + return val; + } + } + + public void put(int key, int value) { + Node x = new Node(key, value); + if (map.containsKey(key)) { + //删除旧节点 + cache.remove(map.get(key)); + //添加新节点 + cache.addFirst(x); + //更新 map + map.put(key, x); + } else { + if (cache.size() == cap) { + Node last = cache.removeLast(); + map.remove(last.key); + } + cache.addFirst(x); + map.put(key, x); + } + + } + } +} diff --git a/Week 07/id_371/Leetcode_191_371.java b/Week 07/id_371/Leetcode_191_371.java new file mode 100644 index 000000000..503d54d03 --- /dev/null +++ b/Week 07/id_371/Leetcode_191_371.java @@ -0,0 +1,48 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-26 18:33 + **/ + +public class Leetcode_191_371 { + public static void main(String[] args) { + + } + + /** + * 仿解1:位掩码 + * @author Shaobo.Qian + * @date 2019/11/26 + * @link https://leetcode-cn.com/problems/number-of-1-bits/solution/wei-1de-ge-shu-by-leetcode/ + */ + public int hammingWeight(int n) { + int bits = 0;//2进制中1的个数 + int mask = 1;//0000 0000 0000 0000 0000 0000 0000 0001 + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + } + + + /** + * 仿解2:位掩码 + * @author Shaobo.Qian + * @date 2019/11/26 + * @link https://leetcode-cn.com/problems/number-of-1-bits/solution/wei-1de-ge-shu-by-leetcode/ + */ + public int hammingWeight1(int n) { + int count = 0; + while (n != 0) { + count++; + n &= (n - 1); + } + return count; + } + + +} diff --git a/Week 07/id_371/Leetcode_231_371.java b/Week 07/id_371/Leetcode_231_371.java new file mode 100644 index 000000000..0ad259195 --- /dev/null +++ b/Week 07/id_371/Leetcode_231_371.java @@ -0,0 +1,18 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-26 19:03 + **/ + +public class Leetcode_231_371 { + public static void main(String[] args) { + boolean res = isPowerOfTwo(8); + System.out.println("res = " + res); + } + + public static boolean isPowerOfTwo(int n) { + + return n > 0 && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_371/Leetcode_338_371.java b/Week 07/id_371/Leetcode_338_371.java new file mode 100644 index 000000000..f3b6427ed --- /dev/null +++ b/Week 07/id_371/Leetcode_338_371.java @@ -0,0 +1,60 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-27 07:35 + **/ + +public class Leetcode_338_371 { + public static void main(String[] args) { + int[] res = countBits2(5); + Arrays.stream(res).forEach(System.out::println); + + } + + /** + * 仿解1:位运算(利用 n&(n-1) 将每一个1清零) + * + * @author Shaobo.Qian + * @date 2019/11/27 + * @link https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode/ + */ + public static int[] countBits1(int num) { + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + int count = popCount(i); + res[i] = count; + } + return res; + } + + private static int popCount(int i) { + int count = 0; + while (i != 0) { + count++; + i &= i - 1; + } + return count; + } + + /** + * 仿解2:位运算+dp(自顶向下) + * + * @author Shaobo.Qian + * @date 2019/11/27 + * @link https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode/ + */ + public static int[] countBits2(int num) { + //a(n) = a(n >> 1) (偶数) + //a(n) = a(n >> 1) + 1(奇数) + + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } + +} diff --git a/Week 07/id_371/Leetcode_493_371.java b/Week 07/id_371/Leetcode_493_371.java new file mode 100644 index 000000000..90d0583d4 --- /dev/null +++ b/Week 07/id_371/Leetcode_493_371.java @@ -0,0 +1,83 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-28 04:59 + **/ + +public class Leetcode_493_371 { + + + public static void main(String[] args) { +// int[] nums = {1, 3, 2, 3, 1}; +// int[] nums = {2,4,3,5,1}; + int[] nums = {2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647}; + int count = reversePairs1(nums); + System.out.println("count = " + count); + } + + /** + * 仿解1:归并排序 + * + * @author Shaobo.Qian + * @date 2019/11/28 + */ + public static int reversePairs1(int[] nums) { + + return mergeSort(nums, 0, nums.length-1); + } + + private static int mergeSort(int[] nums, int begin, int end) { + //1.terminator + if ( begin >= end) return 0; + int mid = begin + ((end - begin) >> 1); + //3.drill down(分治) + int lCount = mergeSort(nums, begin, mid); + int rCount = mergeSort(nums, mid + 1, end); + int nCount = 0; + //2.1找出翻转对,每次取左半边的数组依次和右半边数组中的一个元素比较(因为归并排序后,此时左右两边数组都已经排好序) + for (int left = begin, right = mid + 1; right <= end; right++) { + while (left <= mid && nums[left] <= (long) 2 * nums[right]) left++; //左半边数组剩下的元素相对 当前的nums[right]来说,都是翻转对 + if (left > mid) break; + nCount += mid - left + 1; + } + //2.2将左右两边数组归并排序 + merge(nums, begin, end, mid); + return lCount + rCount + nCount; + } + + private static void merge(int[] nums, int begin, int end, int mid) { + int[] temp = new int[end - begin + 1];//排序后数组,(end - begin + 1)数组大小 + int i = begin, j = mid + 1, k = 0; + //1.左右两边数组元素都没有取完的情况 + while (i <= mid && j <= end) { + temp[k++] = nums[i] <= nums[j] ? nums[i++] : nums[j++]; + } + //2.剩下左边数组还有元素没有取完 + while (i<=mid) temp[k++] = nums[i++]; + //3.剩下左边数组还有元素没有取完 + while (j<=end) temp[k++] = nums[j++]; + //4.用排序后的数组替换原数组 + for (int p = 0; p < temp.length; p++) { + nums[begin + p] = temp[p]; + } + } + + /** + * 原解1. + * + * @author Shaobo.Qian + * @date 2019/11/28 + */ + public static int reversePairs(int[] nums) { + //1.排序 +// Arrays.sort(nums); + int count = 0; + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] > (long) 2 * nums[j]) count++; + } + } + return count; + } +} diff --git a/Week 07/id_371/Leetcode_51_371.java b/Week 07/id_371/Leetcode_51_371.java new file mode 100644 index 000000000..db08f0cbb --- /dev/null +++ b/Week 07/id_371/Leetcode_51_371.java @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-29 08:36 + * @link: https://juejin.im/post/5cbab9a8e51d456e361ed8e5 + * @link: https://www.jianshu.com/p/d16707207de8 + **/ + +public class Leetcode_51_371 { + + private List> results = new ArrayList<>(); + private List result = new ArrayList<>(); + public List> solveNQueens(int n) { + + return null; + } +} diff --git a/Week 07/id_371/Leetcode_52_371.java b/Week 07/id_371/Leetcode_52_371.java new file mode 100644 index 000000000..80ab44cc3 --- /dev/null +++ b/Week 07/id_371/Leetcode_52_371.java @@ -0,0 +1,43 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-28 16:37 + * @link: https://www.jianshu.com/p/d16707207de8 + **/ + +public class Leetcode_52_371 { + public static void main(String[] args) { + int count = totalNQueens(8); + System.out.println("count = " + count); + } + + // private static final int N = 8;// 皇后数量,可拓展为N皇后 + private static int count = 0; //总方法数 + private static int limit;//需要考虑的位数的2进制最大值(n=8,limit = 255(1111 1111)) 说明下一行所有位置都被占用了 + + public static int totalNQueens(int n) { + limit = (1 << n) - 1; + backtrace(n, 0, 0, 0, 0); + return count; + } + + private static void backtrace(int n, int col, int pi, int na, int row) { + if (row == n) { //每一行都放置了皇后,成功数+1 + count++; + return; + } + + int used = col | pi | na; + while (used < limit) { + //获取最右边可以放置皇后的位置 + int using = (used + 1) & (~used);//used +1 (会把最右边的0变为1) & (~used 也会将最右边的0变为1) ===>最右边的0变为1,其它位都变为0,<==== used &(~used) 可以将所有位变为0 + //主对角线(pi)上在下一行占用的位置:limit & ((pi | using) >> 1) + //副对角线(na)上在下一行占用的位置:limit & ((na | using) << 1 + backtrace(n, col | using, limit & ((pi | using) >> 1), limit & ((na | using) << 1), row + 1); + used |= using; //把当前行,刚才已经占用的位置设置为不能放置 + } + } + +} + diff --git a/Week 07/id_371/Leetcode_56_371.java b/Week 07/id_371/Leetcode_56_371.java new file mode 100644 index 000000000..57cc94c7e --- /dev/null +++ b/Week 07/id_371/Leetcode_56_371.java @@ -0,0 +1,85 @@ +import java.util.Arrays; +import java.util.Comparator; +import java.util.Deque; +import java.util.LinkedList; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-11-28 03:39 + **/ + +public class Leetcode_56_371 { + public static void main(String[] args) { + //[[1,3],[2,6],[8,10],[15,18]] ==>[[1,6],[8,10],[15,18]] +// int[][] intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}}; + int[][] intervals = {{1, 4}, {0, 4}}; + int[][] res = merge(intervals); + for (int i = 0; i < res.length; i++) { + Arrays.stream(res[i]).forEach(System.out::println); + } + + } + + /** + * 原解1:降维度+排序 + * + * @author Shaobo.Qian + * @date 2019/11/28 + */ + public static int[][] merge(int[][] intervals) { + if (intervals.length <= 1) return intervals; + //1.根据二维数组第一个数字大小按每一行整体排序 + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] - o2[0]; + } + }); + Deque deque = new LinkedList<>(); + deque.addFirst(intervals[0][0]); + deque.addLast(intervals[0][1]); + //1.降维度 + for (int i = 1; i < intervals.length; i++) { + + int[] interval = intervals[i]; + Integer min = deque.getFirst(); + Integer max = deque.getLast(); + if (interval[1] > max && interval[0] < min) { + deque = new LinkedList<>(); + deque.addFirst(interval[0]); + deque.addLast(interval[1]); + } else if (interval[1] < min) { + deque.addFirst(interval[1]); + deque.addFirst(interval[0]); + } else if (interval[0] > max) { + deque.addLast(interval[0]); + deque.addLast(interval[1]); + } else if (interval[1] > max) { + deque.removeLast(); + deque.addLast(interval[1]); + } else if (interval[0] < min) { + deque.removeFirst(); + deque.addFirst(interval[0]); + } + + } + //2.返回结果 + + return + + transferArr(deque); + + } + + private static int[][] transferArr(Deque deque) { + int size = deque.size(); + int[][] res = new int[size / 2][2]; + for (int i = 0; i < size / 2; i++) { + res[i][0] = (int) deque.pollFirst(); + res[i][1] = (int) deque.pollFirst(); + } + return res; + } +} diff --git a/Week 07/id_381/leetcode_190.py b/Week 07/id_381/leetcode_190.py new file mode 100644 index 000000000..67ec044c5 --- /dev/null +++ b/Week 07/id_381/leetcode_190.py @@ -0,0 +1,8 @@ +class Solution: + def reverseBits(self, n: int) -> int: + res = 0 + for i in range(32): + res <<= 1 + res += n&1 + n >>= 1 + return res diff --git a/Week 07/id_381/leetcode_191.py b/Week 07/id_381/leetcode_191.py new file mode 100644 index 000000000..31b754db8 --- /dev/null +++ b/Week 07/id_381/leetcode_191.py @@ -0,0 +1,7 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n: + count += 1 + n = n & (n-1) + return count diff --git a/Week 07/id_381/leetcode_231.py b/Week 07/id_381/leetcode_231.py new file mode 100644 index 000000000..f0ccda2bc --- /dev/null +++ b/Week 07/id_381/leetcode_231.py @@ -0,0 +1,3 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and n&(n-1) == 0 diff --git a/Week 07/id_381/leetcode_338.py b/Week 07/id_381/leetcode_338.py new file mode 100644 index 000000000..c5194673b --- /dev/null +++ b/Week 07/id_381/leetcode_338.py @@ -0,0 +1,6 @@ +class Solution: + def countBits(self, num: int) -> list: + counts = [0]*(num+1) + for i in range(1, num+1): + counts[i] = counts[i&(i-1)] + 1 + return counts diff --git a/Week 07/id_386/LeetCode_190_386.java b/Week 07/id_386/LeetCode_190_386.java new file mode 100644 index 000000000..4cc97b8af --- /dev/null +++ b/Week 07/id_386/LeetCode_190_386.java @@ -0,0 +1,11 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int res = 0b0, i = 0; // for 换 while + // res 左移不需要暂存,直接用 (res << 1) + // | 代替 + ,使得都是位运算 + // n 无需右移后保存,每次重新移也可,故 (n >>> (i - 1)) + while (i++ < 32) res = (res << 1) | (n >>> (i - 1) & 1); + return res; + } +} diff --git a/Week 07/id_386/LeetCode_231_386.java b/Week 07/id_386/LeetCode_231_386.java new file mode 100644 index 000000000..027b20e09 --- /dev/null +++ b/Week 07/id_386/LeetCode_231_386.java @@ -0,0 +1,11 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + if (n == 0)return false; + if (n == 1)return true; + if (n%2==1)return false; + while(n%2==0){ + n = n>>1; + } + return n==1; + } +} diff --git a/Week 07/id_396/LeetCode_146_396.swift b/Week 07/id_396/LeetCode_146_396.swift new file mode 100644 index 000000000..7678f214f --- /dev/null +++ b/Week 07/id_396/LeetCode_146_396.swift @@ -0,0 +1,122 @@ +// +// LeetCode_221_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit +class LinkListNode: NSObject { + var value: Int + let key: Int + var next: LinkListNode? + var pre: LinkListNode? + init(_ key: Int,_ val: Int) { + self.value = val + self.key = key + } +} + +class DoubleLinkList { + var header: LinkListNode = LinkListNode(-0, -0) + var tail: LinkListNode = LinkListNode(-10, -10) + init() { + header.next = tail + tail.pre = header + } + + func addToHeader(_ node: LinkListNode) { + if header.next! == tail { //第一个插进来的节点 + tail.pre = node + } + node.next = header.next + header.next?.pre = node + + node.pre = header + header.next = node + } + + func moveToFirst(_ node: LinkListNode) { + if node.pre! == header { + return + } + + self.remove(node) + self.addToHeader(node) + } + + func remove(_ node: LinkListNode) { + if node.next! == tail { + node.pre?.next = tail + tail.pre = node.pre + } else { + node.pre?.next = node.next + node.next?.pre = node.pre + } + } + + func removeLast() -> LinkListNode? { + if tail.pre! == header { + return nil + } + let lastNode = tail.pre! + lastNode.pre?.next = tail + tail.pre = lastNode.pre + return lastNode + } + + func printLinkList() { + var temp: LinkListNode? = header + var result = [String]() + while let current = temp { + result.append("-> \(current.value)") + temp = current.next + } + print("result: \(result)") + } +} + +class LRUCache { + + var cache = [Int: LinkListNode]() + let lenght: Int + let linkList = DoubleLinkList() + + init(_ capacity: Int) { + lenght = capacity + } + + func get(_ key: Int) -> Int { + if let tempNode = cache[key] { + linkList.moveToFirst(tempNode) + // print("get \(key) \(tempNode.value)") + // linkList.printLinkList() + // print("cache: \(cache)") + return tempNode.value + } + return -1 + } + + func put(_ key: Int, _ value: Int) { + // print("put \(key)") + //已存在缓存,移动node到第一位 + if let tempNode = cache[key] { + if tempNode.pre != nil { //非表头,移动第一位。改变链表 + linkList.moveToFirst(tempNode) + tempNode.value = value + } + } else { //不在缓存,添加到链表头,判断是否超出缓存,删除尾结点 + let node = LinkListNode(key,value) + linkList.addToHeader(node) + cache[key] = node + // print("count=\(cache.keys.count), lenght:\(lenght)") + if cache.keys.count > lenght { + if let last = linkList.removeLast() { + cache[last.key] = nil + } + } + } + // linkList.printLinkList() + // print("cache: \(cache)") + } +} diff --git a/Week 07/id_396/LeetCode_231_396.swift b/Week 07/id_396/LeetCode_231_396.swift new file mode 100644 index 000000000..d96f4cba8 --- /dev/null +++ b/Week 07/id_396/LeetCode_231_396.swift @@ -0,0 +1,16 @@ +// +// LeetCode_221_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit + +//231 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +class Solution { + func isPowerOfTwo(_ n: Int) -> Bool { + return n & (n - 1) == 0 + } +} + diff --git a/Week 07/id_396/LeetCode_56_396.swift b/Week 07/id_396/LeetCode_56_396.swift new file mode 100644 index 000000000..6c05fbdb4 --- /dev/null +++ b/Week 07/id_396/LeetCode_56_396.swift @@ -0,0 +1,79 @@ +// +// LeetCode_221_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit + +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + //先按第一个数排序 + var sortIntervals = intervals + sort(&sortIntervals, left: 0, right: sortIntervals.count - 1) + + var result = [[Int]]() + //遍历数组,合并区间 + var lastInterval: [Int]?; + for interval in sortIntervals { + guard let lastInter = lastInterval else { + lastInterval = interval + continue + } + //两个不连接 + + if (lastInter[1] < interval[0]){ + result.append(lastInter) + lastInterval = interval + //两个区间有交集 + } else if (lastInter[1] < interval[1]) { + lastInterval![1] = interval[1] + } else if(lastInter[1] >= interval[1]) { //后面的被前面的包含,继续判断下个元素 + //大于不做任何操作 + } + } + + if let last = lastInterval { + result.append(last) + } + return result; + } + + func sort(_ intervals: inout [[Int]], left: Int, right: Int){ + if (left < right) { + let middle = quickSort(&intervals, left: left, right: right) + sort(&intervals, left: left, right: middle - 1) + sort(&intervals, left: middle + 1, right: right) + } + } + + //返回中间那个数值 + func quickSort(_ intervals :inout [[Int]],left: Int, right: Int) -> Int { + + var base = intervals[left] + + //从左边到右边 + var low = left + var high = right + while low < high { + //基准值和最后的比较 + while low < high , base[0] <= intervals[high][0] { + high = high - 1 + } + + intervals[low] = intervals[high] //此时high就空出一个位置 + + //此时基准值应该处于后半部分 + while low < high , base[0] >= intervals[low][0] { + low = low + 1 + } + + intervals[high] = intervals[low] + } + + intervals[low] = base + + return low; + } +} diff --git a/Week 07/id_406/Leetcode_1122_406.py b/Week 07/id_406/Leetcode_1122_406.py new file mode 100644 index 000000000..6082f73d7 --- /dev/null +++ b/Week 07/id_406/Leetcode_1122_406.py @@ -0,0 +1,15 @@ +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + arr = [0 for _ in range(1001)] + ans = [] + for i in range(len(arr1): + arr[arr1[i]] += 1 + for i in range(len(arr2)): + while arr[arr2[i]] > 0: + ans.append(arr2[i]) + arr[arr2[i]] -= 1 + for i in range(len(arr)): + while arr[i] > 0: + ans.append(i) + arr[i] -= 1 + return ans diff --git a/Week 07/id_406/Leetcode_242_406.py b/Week 07/id_406/Leetcode_242_406.py new file mode 100644 index 000000000..084cb5442 --- /dev/null +++ b/Week 07/id_406/Leetcode_242_406.py @@ -0,0 +1,10 @@ +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + result = True + set_tmp = set(s) + if set_tmp == set(t): + for i in set_tmp: + result = result and (s.count(i) == t.count(i)) + else: + result = False + return (result) diff --git a/Week 07/id_431/LeetCode_1122_431.java b/Week 07/id_431/LeetCode_1122_431.java new file mode 100644 index 000000000..9192640ed --- /dev/null +++ b/Week 07/id_431/LeetCode_1122_431.java @@ -0,0 +1,61 @@ +package easy; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author 潘磊明 + * @date 2019/12/5 + */ +public class RelativeSortArray { +// public int[] relativeSortArray(int[] arr1, int[] arr2) { +// List list1 = new ArrayList<>(); +// List list2 = new ArrayList<>(); +// int[] arr = new int[arr1.length]; +// Map> map = new HashMap<>(); +// for (int i = 0; i < arr1.length; i++) { +// if(!map.containsKey(arr1[i])) map.put(arr1[i], new ArrayList<>()); +// map.get(arr1[i]).add(arr1[i]); +// } +// for (int i = 0; i < arr2.length; i++) { +// list1.addAll(map.get(arr2[i])); +// map.remove(arr2[i]); +// } +// for (List list : map.values()) { +// list2.addAll(list); +// } +// Collections.sort(list2); +// for(int i = 0; i < list1.size(); i++) { +// arr[i] = list1.get(i); +// } +// for (int i = 0; i < list2.size(); i++) { +// arr[list1.size() + i] = list2.get(i); +// } +// return arr; +// } + + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] array = new int[1001]; + for(int i : arr1) array[i]++; + int tmp = 0; + for (int i : arr2) { + while(array[i] != 0) { + arr1[tmp] = i; + array[i]--; + tmp++; + } + } + for (int i = 0; i < array.length; i++) { + if (array[i] == 0) continue; + while (array[i] != 0) { + arr1[tmp] = i; + array[i]--; + tmp++; + } + } + return arr1; + } +} diff --git a/Week 07/id_431/LeetCode_1244_431.java b/Week 07/id_431/LeetCode_1244_431.java new file mode 100644 index 000000000..96fea4c26 --- /dev/null +++ b/Week 07/id_431/LeetCode_1244_431.java @@ -0,0 +1,85 @@ +package medium; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.TreeMap; + +/** + * @author 潘磊明 + * @date 2019/12/6 + */ +public class Leaderboard { + Map> scoreMap; + Map playerMap; + + public Leaderboard() { + scoreMap = new TreeMap<>(new MyComparator()); + playerMap = new HashMap<>(); + } + + public void addScore(int playerId, int score) { + if (playerMap.containsKey(playerId)) { + Integer lastScore = playerMap.get(playerId); + Integer newScore = score + lastScore; + playerMap.put(playerId, newScore); + List playerList = scoreMap.get(lastScore); + Integer newPlayerId = playerId; + playerList.remove(newPlayerId); + List newPlayerList = scoreMap.getOrDefault(newScore, new ArrayList<>()); + newPlayerList.add(playerId); + scoreMap.put(newScore, newPlayerList); + } else { + playerMap.put(playerId, score); + List playerList = scoreMap.getOrDefault(score, new ArrayList<>()); + playerList.add(playerId); + scoreMap.put(score, playerList); + } + } + + public int top(int K) { + int res = 0; + for (Map.Entry> entry : scoreMap.entrySet()) { + List playerList = entry.getValue(); + if (K > 0) { + if (playerList.size() < K) { + res += playerList.size() * entry.getKey(); + K -= playerList.size(); + } else { + res += entry.getKey() * K; + K = 0; + } + } else { + break; + } + } + return res; + } + + public void reset(int playerId) { + Integer score = playerMap.get(playerId); + playerMap.put(playerId, 0); +// playerMap.remove(playerId); + List playerList = scoreMap.get(score); + Integer newPlayerId = playerId; + playerList.remove(newPlayerId); + if (playerList.isEmpty()) { + scoreMap.remove(score); + } + List newPlayerList = scoreMap.getOrDefault(0, new ArrayList<>()); + newPlayerList.add(newPlayerId); + scoreMap.put(0, newPlayerList); + } +} + +class MyComparator implements Comparator { + + @Override + public int compare(Integer i1, Integer i2) { + return i2 - i1; + } + +} diff --git a/Week 07/id_431/LeetCode_146_431.java b/Week 07/id_431/LeetCode_146_431.java new file mode 100644 index 000000000..d37950c41 --- /dev/null +++ b/Week 07/id_431/LeetCode_146_431.java @@ -0,0 +1,105 @@ +package medium; + +import java.util.HashMap; +import java.util.Map; + +/** + * 使用双向链表和hashMap实现或者直接使用LinkedHashMap + * @author 潘磊明 + * @date 2019/12/5 + */ +public class LRUCache { + DoubleNode head; + DoubleNode tail; + int size; + int capacity; + Map> map; + + public LRUCache(int capacity) { + this.head = new DoubleNode<>(Integer.MAX_VALUE, Integer.MAX_VALUE); + this.tail = new DoubleNode<>(Integer.MAX_VALUE, Integer.MAX_VALUE); + this.head.next = this.tail; + this.tail.prev = this.head; + this.size = 0; + this.capacity = capacity; + map = new HashMap<>(); + } + + /** + * 缓存的数据是否超出最大数量 + * @return + */ + private boolean isFull() { + return this.size > this.capacity; + } + + /** + * 删除节点 + * @param doubleNode + */ + private void removeNode(DoubleNode doubleNode) { + DoubleNode prev = doubleNode.prev; + DoubleNode next = doubleNode.next; + prev.next = next; + next.prev = prev; + } + + /** + * 添加节点 + * @param doubleNode + */ + private void addNode(DoubleNode doubleNode) { + DoubleNode tmp = head.next; + head.next = doubleNode; + doubleNode.next = tmp; + doubleNode.prev = head; + tmp.prev = doubleNode; + } + + /** + * 将节点移动到头部 + * @param doubleNode + */ + private void moveNodeToHead(DoubleNode doubleNode) { + removeNode(doubleNode); + addNode(doubleNode); + } + + public int get(int key) { + if (!map.containsKey(key)) return -1; + DoubleNode tmp = map.get(key); + moveNodeToHead(tmp); + return tmp.value; + } + + public void put(int key, int value) { + //先判断是否已经存在 + if (map.containsKey(key)) { + DoubleNode tmp = map.get(key); + tmp.value = value; + moveNodeToHead(tmp); + }else { + DoubleNode doubleNode = new DoubleNode<>(key, value); + map.put(key, doubleNode); + addNode(doubleNode); + size++; + if (isFull()) { + map.remove(tail.prev.key); + removeNode(tail.prev); + size--; + }; + } + } + + class DoubleNode { + DoubleNode prev; + DoubleNode next; + T value; + T key; + + DoubleNode(T key, T value){ + this.value = value; + this.key = key; + } + } +} diff --git a/Week 07/id_431/LeetCode_190_431.java b/Week 07/id_431/LeetCode_190_431.java new file mode 100644 index 000000000..5cae14849 --- /dev/null +++ b/Week 07/id_431/LeetCode_190_431.java @@ -0,0 +1,16 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/30 + */ +public class ReverseBits { + public int reverseBits(int n) { + int result = 0; + for(int i = 0;i < 32;i++){ + result = (result << 1) + (n & 1); + n >>= 1; + } + return result >>> 0; + } +} diff --git a/Week 07/id_431/LeetCode_191_431.java b/Week 07/id_431/LeetCode_191_431.java new file mode 100644 index 000000000..f98043ae1 --- /dev/null +++ b/Week 07/id_431/LeetCode_191_431.java @@ -0,0 +1,31 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/29 + */ +public class NumberOf1Bits { + /** + * 使用掩码 + * @param n + * @return + */ +// public int hammingWeight(int n) { +// int count = 0; +// int mask = 1; +// for (int i = 0; i < 32; i++) { +// if ((n & mask) != 0) count++; +// mask <<= 1; +// } +// return count; +// } + + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + n &= n - 1; + count++; + } + return count; + } +} diff --git a/Week 07/id_431/LeetCode_231_431.java b/Week 07/id_431/LeetCode_231_431.java new file mode 100644 index 000000000..95afc2795 --- /dev/null +++ b/Week 07/id_431/LeetCode_231_431.java @@ -0,0 +1,11 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/11/30 + */ +public class PowerOfTwo { + public boolean isPowerOfTwo(int n) { + return (n > 0 && (n & n - 1) == 0); + } +} diff --git a/Week 07/id_431/LeetCode_242_431.java b/Week 07/id_431/LeetCode_242_431.java new file mode 100644 index 000000000..28511d638 --- /dev/null +++ b/Week 07/id_431/LeetCode_242_431.java @@ -0,0 +1,99 @@ +package easy; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @author 潘磊明 + * @date 2019/10/23 + */ +public class ValidAnagram { + +// public boolean isAnagram(String s, String t) { +// if (s.length() != t.length()) return false; +// if (s.equals(t)) return true; +// Map map = new HashMap<>(); +// for (int i = 0; i < s.length(); i++) { +// String v1 = s.substring(i, i + 1); +// String v2 = t.substring(i, i + 1); +// if (map.containsKey(v1)) { +// map.put(v1, map.get(v1) + 1); +// } else { +// map.put(v1, 1); +// } +// if (map.containsKey(v2)) { +// map.put(v2, map.get(v2) - 1); +// } else { +// map.put(v2, -1); +// } +// } +// for (Integer val : map.values()) { +// if (val != 0) return false; +// } +// return true; +// } + +// public boolean isAnagram(String s, String t) { +// if (s.equals(t)) return true; +// //使用HashMap +// Map map = new HashMap<>(); +// char[] sArray = s.toCharArray(); +// char[] tArray = t.toCharArray(); +// for (int i = 0; i < sArray.length; i++) { +// if (!map.containsKey(sArray[i])){ +// map.put(sArray[i], 0); +// } +// map.put(sArray[i], map.get(sArray[i]) + 1); +// } +// for (int i = 0; i < tArray.length; i++) { +// if (!map.containsKey(tArray[i])) return false; +// map.put(tArray[i], map.get(tArray[i]) - 1); +// if (map.get(tArray[i]) == 0) { +// map.remove(tArray[i]); +// } +// } +// return map.isEmpty(); +// } + +// public boolean isAnagram(String s, String t) { +// if (s.equals(t)) return true; +// if (s.length() != t.length()) return false; +// char[] sArray = s.toCharArray(); +// char[] tArray = t.toCharArray(); +// Arrays.sort(sArray); +// Arrays.sort(tArray); +// for(int i = 0; i < sArray.length; i++) { +// if (sArray[i] != tArray[i]) { +// return false; +// } +// } +// return true; +// } + + /** + * 精彩代码 + * @param s + * @param t + * @return + */ +// public boolean isAnagram(String s, String t) { +// int[] alphabet = new int[26]; +// for (int i = 0; i < s.length(); i++) alphabet[s.charAt(i) - 'a']++; +// for (int i = 0; i < t.length(); i++) alphabet[t.charAt(i) - 'a']--; +// for (int i : alphabet) if (i != 0) return false; +// return true; +// } + + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) return false; + char[] sc = s.toCharArray(); + char[] tc = t.toCharArray(); + Arrays.sort(sc); + Arrays.sort(tc); + for (int i = 0; i < sc.length; i++) { + if (sc[i] != tc[i]) return false; + } + return true; + } +} diff --git a/Week 07/id_436/Leetcode_1122_436.java b/Week 07/id_436/Leetcode_1122_436.java new file mode 100644 index 000000000..1f7439907 --- /dev/null +++ b/Week 07/id_436/Leetcode_1122_436.java @@ -0,0 +1,33 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] result = new int[arr1.length]; + List left = new ArrayList(); + Map map = new HashMap(); + for (int num : arr2) { + map.put(num, 0); + } + for (int num : arr1) { + if (map.containsKey(num)) { + map.put(num, map.getOrDefault(num, 0) + 1); + } else { + left.add(num); + } + } + int index = 0, i = 0; + while (i < result.length && index < arr2.length) { + int count = map.get(arr2[index]); + while (count > 0) { + result[i++] = arr2[index]; + count--; + } + index++; + } + if (left.size() > 0) { + Collections.sort(left); + for (int j = 0; j < left.size(); ++j) { + result[i++] = left.get(j); + } + } + return result; + } +} diff --git a/Week 07/id_436/Leetcode_146_436.java b/Week 07/id_436/Leetcode_146_436.java new file mode 100644 index 000000000..3d707da87 --- /dev/null +++ b/Week 07/id_436/Leetcode_146_436.java @@ -0,0 +1,37 @@ +class LRUCache { + int capacity; + Map map; + public LRUCache(int capacity) { + this.capacity = capacity; + this.map = new LinkedHashMap(); + } + + public int get(int key) { + if (map.get(key) == null) { + return -1; + } + int val = map.remove(key); + map.put(key, val); + return val; + } + + public void put(int key, int value) { + if (map.containsKey(key)) { + map.remove(key); + map.put(key, value); + return; + } + if (map.size() >= capacity){ + int head = map.keySet().iterator().next(); + map.remove(head); + } + map.put(key, value); + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ diff --git a/Week 07/id_446/LeetCode_191_446.cpp b/Week 07/id_446/LeetCode_191_446.cpp new file mode 100644 index 000000000..34ea0863d --- /dev/null +++ b/Week 07/id_446/LeetCode_191_446.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + int hammingWeight(uint32_t n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } +}; \ No newline at end of file diff --git a/Week 07/id_446/LeetCode_231_446.cpp b/Week 07/id_446/LeetCode_231_446.cpp new file mode 100644 index 000000000..ed01aa371 --- /dev/null +++ b/Week 07/id_446/LeetCode_231_446.cpp @@ -0,0 +1,6 @@ +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +}; \ No newline at end of file diff --git a/Week 07/id_451/LeetCode_146_451.go b/Week 07/id_451/LeetCode_146_451.go new file mode 100644 index 000000000..dc9af7efe --- /dev/null +++ b/Week 07/id_451/LeetCode_146_451.go @@ -0,0 +1,43 @@ + +type Node struct { + k, v int +} +type LRUCache struct { + l *list.List + m map[int]*list.Element + len int +} + +func Constructor(capacity int) LRUCache { + return LRUCache{ + l: list.New(), + len: capacity, + m: make(map[int]*list.Element), + } +} + +func (lru *LRUCache) Get(key int) int { + ptr, ok := lru.m[key] + if !ok { + return -1 + } + lru.l.MoveToFront(ptr) + return ptr.Value.(Node).v +} + +func (lru *LRUCache) Put(key int, value int) { + + ptr, ok := lru.m[key] + if ok { + lru.l.Remove(ptr) + } + e := lru.l.PushFront(Node{key, value}) + lru.m[key] = e + if lru.l.Len() > lru.len { + e = lru.l.Back() + delete(lru.m, e.Value.(Node).k) + lru.l.Remove(e) + return + } +} + diff --git a/Week 07/id_451/LeetCode_231_451.go b/Week 07/id_451/LeetCode_231_451.go new file mode 100644 index 000000000..f1599b632 --- /dev/null +++ b/Week 07/id_451/LeetCode_231_451.go @@ -0,0 +1,6 @@ +func isPowerOfTwo(n int) bool { + if n&(n-1) == 0 && n != 0 { + return true + } + return false +} diff --git a/Week 07/id_466/LeetCode_146_466.java b/Week 07/id_466/LeetCode_146_466.java new file mode 100644 index 000000000..f3fe48431 --- /dev/null +++ b/Week 07/id_466/LeetCode_146_466.java @@ -0,0 +1,169 @@ +//运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +// +// 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +//写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +// +// 进阶: +// +// 你是否可以在 O(1) 时间复杂度内完成这两种操作? +// +// 示例: +// +// LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +// +//cache.put(1, 1); +//cache.put(2, 2); +//cache.get(1); // 返回 1 +//cache.put(3, 3); // 该操作会使得密钥 2 作废 +//cache.get(2); // 返回 -1 (未找到) +//cache.put(4, 4); // 该操作会使得密钥 1 作废 +//cache.get(1); // 返回 -1 (未找到) +//cache.get(3); // 返回 3 +//cache.get(4); // 返回 4 +// +// Related Topics 设计 +package com.aseara.leetcode.editor.cn.a146; + +import java.util.HashMap; +import java.util.Map; + +/** + * desc: 146.LRU缓存机制
    + * Date: 2019/11/26
    + * + * @author qiujingde + */ +class LruCacheTest { + + public static void main(String[] args) { + LRUCache cache = new LRUCache( 2 ); + + cache.put(1, 1); + cache.put(2, 2); + System.out.println(cache.get(1)); // 1 + cache.put(3, 3); + System.out.println(cache.get(2)); // -1 + cache.put(4, 4); + System.out.println(cache.get(1)); // -1 + System.out.println(cache.get(3)); // 3 + System.out.println(cache.get(4)); + + + cache = new LRUCache( 3 ); + cache.put(1, 1); + cache.put(2, 2); + cache.put(3, 3); + cache.put(4, 4); + + System.out.println(cache.get(4)); // 4 + System.out.println(cache.get(3)); // 3 + System.out.println(cache.get(2)); // 2 + System.out.println(cache.get(1)); // -1 + + cache.put(5, 5); + System.out.println(cache.get(1)); // -1 + System.out.println(cache.get(2)); // 2 + System.out.println(cache.get(3)); // 3 + System.out.println(cache.get(4)); // -1 + System.out.println(cache.get(5)); // 5 + } +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class LRUCache { + + private Map map = new HashMap<>(); + private Deque deque = new Deque(); + private int remain; + + public LRUCache(int capacity) { + this.remain = capacity; + } + + public int get(int key) { + Node node = getNode(key); + return node == null ? -1 : node.val; + } + + public void put(int key, int value) { + Node node = getNode(key); + if (node != null) { + node.val = value; + return; + } + node = new Node(key, value); + deque.add(node); + map.put(key, node); + if (remain > 0) { + remain --; + return; + } + Node remove = deque.remove(); + map.remove(remove.key); + } + + private Node getNode(int key) { + Node node = map.get(key); + if (node == null) { + return null; + } + deque.remove(node); + deque.add(node); + return node; + } + + static class Deque { + Node head = new Node(0, 0); + Node tail = new Node(0, 0); + + Deque() { + tail.pre = head; + head.next = tail; + } + + void add(Node node) { + node.pre = head; + node.next = head.next; + head.next.pre = node; + head.next = node; + } + + void remove(Node node) { + Node pre = node.pre; + Node next = node.next; + pre.next = next; + next.pre = pre; + } + + Node remove() { + if (tail.pre == head) { + return null; + } + Node result = tail.pre; + result.pre.next = tail; + tail.pre = result.pre; + return result; + } + } + + static class Node { + final int key; + int val; + Node pre; + Node next; + + Node(int key, int val) { + this.key = key; + this.val = val; + } + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_191_466.java b/Week 07/id_466/LeetCode_191_466.java new file mode 100644 index 000000000..3e90f305d --- /dev/null +++ b/Week 07/id_466/LeetCode_191_466.java @@ -0,0 +1,80 @@ +//编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 +// +// +// +// 示例 1: +// +// 输入:00000000000000000000000000001011 +//输出:3 +//解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +// +// +// 示例 2: +// +// 输入:00000000000000000000000010000000 +//输出:1 +//解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +// +// +// 示例 3: +// +// 输入:11111111111111111111111111111101 +//输出:31 +//解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +// +// +// +// 提示: +// +// +// 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +// 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +// +// +// +// +// 进阶: +//如果多次调用这个函数,你将如何优化你的算法? +// Related Topics 位运算 +package com.aseara.leetcode.editor.cn.a191; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 191.位1的个数
    + * Date: 2019/11/26
    + * + * @author qiujingde + */ +class NumberOf1Bits { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(0, solution.hammingWeight(0)); + assertEquals(1, solution.hammingWeight(1)); + assertEquals(1, solution.hammingWeight(2)); + assertEquals(2, solution.hammingWeight(3)); + assertEquals(1, solution.hammingWeight(4)); + assertEquals(2, solution.hammingWeight(5)); + assertEquals(2, solution.hammingWeight(6)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int cnt = 0; + while (n != 0) { + n = n & (n - 1); + cnt ++; + } + return cnt; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_231_466.java b/Week 07/id_466/LeetCode_231_466.java new file mode 100644 index 000000000..5fd7d33d1 --- /dev/null +++ b/Week 07/id_466/LeetCode_231_466.java @@ -0,0 +1,54 @@ +//给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +// +// 示例 1: +// +// 输入: 1 +//输出: true +//解释: 20 = 1 +// +// 示例 2: +// +// 输入: 16 +//输出: true +//解释: 24 = 16 +// +// 示例 3: +// +// 输入: 218 +//输出: false +// Related Topics 位运算 数学 +package com.aseara.leetcode.editor.cn.a231; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * desc: 231.2的幂
    + * Date: 2019/11/26
    + * + * @author qiujingde + */ +class PowerOfTwo { + private Solution solution = new Solution(); + + @Test + void test1() { + assertFalse(solution.isPowerOfTwo(0)); + assertTrue(solution.isPowerOfTwo(1)); + assertTrue(solution.isPowerOfTwo(2)); + assertFalse(solution.isPowerOfTwo(3)); + assertTrue(solution.isPowerOfTwo(4)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_338_466.java b/Week 07/id_466/LeetCode_338_466.java new file mode 100644 index 000000000..0f7847f6c --- /dev/null +++ b/Week 07/id_466/LeetCode_338_466.java @@ -0,0 +1,59 @@ +//给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 +// +// 示例 1: +// +// 输入: 2 +//输出: [0,1,1] +// +// 示例 2: +// +// 输入: 5 +//输出: [0,1,1,2,1,2] +// +// 进阶: +// +// +// 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗? +// 要求算法的空间复杂度为O(n)。 +// 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。 +// +// Related Topics 位运算 动态规划 +package com.aseara.leetcode.editor.cn.a338; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * desc: 338.比特位计数
    + * Date: 2019/11/25
    + * + * @author qiujingde + */ +class CountingBits { + private Solution solution = new Solution(); + + @Test + void test1() { + assertArrayEquals(new int[]{0}, solution.countBits(0)); + assertArrayEquals(new int[]{0, 1}, solution.countBits(1)); + assertArrayEquals(new int[]{0, 1, 1}, solution.countBits(2)); + assertArrayEquals(new int[]{0, 1, 1, 2}, solution.countBits(3)); + assertArrayEquals(new int[]{0, 1, 1, 2, 1}, solution.countBits(4)); + assertArrayEquals(new int[]{0, 1, 1, 2, 1, 2}, solution.countBits(5)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int[] countBits(int num) { + int[] result = new int[num + 1]; + for (int i = 1; i <= num; i++) { + result[i] += result[i & (i - 1)] + 1; + } + return result; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_493_466.java b/Week 07/id_466/LeetCode_493_466.java new file mode 100644 index 000000000..ebc16c7c9 --- /dev/null +++ b/Week 07/id_466/LeetCode_493_466.java @@ -0,0 +1,174 @@ +//给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。 +// +// 你需要返回给定数组中的重要翻转对的数量。 +// +// 示例 1: +// +// +//输入: [1,3,2,3,1] +//输出: 2 +// +// +// 示例 2: +// +// +//输入: [2,4,3,5,1] +//输出: 3 +// +// +// 注意: +// +// +// 给定数组的长度不会超过50000。 +// 输入数组中的所有数字都在32位整数的表示范围内。 +// +// Related Topics 排序 树状数组 线段树 二分查找 分治算法 +package com.aseara.leetcode.editor.cn.a493; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 493.翻转对
    + * Date: 2019/11/28
    + * + * @author qiujingde + */ +class ReversePairs { + private Solution solution = new Solution(); + + @Test + void test1() { + int[] test1 = {1,3,2,3,1}; + assertEquals(2, solution.reversePairs(test1)); + + int[] test2 = {2147483647,2147483647,-2147483647,-2147483647,-2147483647,2147483647}; + assertEquals(9, solution.reversePairs(test2)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int reversePairs(int[] nums) { + if (nums == null || nums.length < 2) { + return 0; + } + return method2(nums); + } + + private int merge(int[] nums, int l, int r) { + if (l == r) { + return 0; + } + int mid = (l + r) >> 1; + int cnt = merge(nums, l, mid); + cnt += merge(nums,mid + 1, r); + + int[] tmp = new int[r - l + 1]; + int i = l, j = mid + 1; + int k = 0; + + int n = mid + 1; + for (int m = l; m <= mid; m++) { + for (; n <= r; n++) { + if (nums[m] > 2L * nums[n]) { + cnt += mid - m + 1; + } else { + break; + } + } + } + + while (i <= mid && j <= r) { + tmp[k++] = nums[i] > nums[j] ? nums[j++] : nums[i++]; + } + if (i <= mid) { + System.arraycopy(nums, i, tmp, k, mid - i + 1); + } + if (j <= r) { + System.arraycopy(nums, j, tmp, k, r - j + 1); + } + System.arraycopy(tmp, 0, nums, l, tmp.length); + return cnt; + } + + private int method2(int[] nums) { + int[] copy = nums.clone(); + Arrays.sort(copy); + BinaryIndexedTree bit = new BinaryIndexedTree(nums.length); + int cnt = 0; + + for (int i = nums.length - 1; i > 0; i--) { + int num = nums[i]; + cnt += bit.query(lowBound(copy, (num >> 1) - (~num & 1))); + bit.update(lowBound(copy, num), 1); + } + + return cnt; + } + + private int lowBound(int[] list, long num) { + for (int i = 0; i < list.length; i++) { + if (list[i] >= num) { + return i; + } + } + return list.length; + } + +} + +class BinaryIndexedTree { + private int[] bitArr; + + public BinaryIndexedTree(int n) { + bitArr = new int[n + 1]; + } + + public BinaryIndexedTree(int[] list) { + bitArr = new int[list.length + 1]; + System.arraycopy(list, 0, bitArr, 1, list.length); + for (int i = 1; i < bitArr.length - 1; i++) { + int j = i + (i & -i); + if (j < bitArr.length) { + bitArr[j] += bitArr[i]; + } + } + } + + public void update(int idx, int delta) { + for (int i = idx + 1; i < bitArr.length; i += (i & -i)) { + bitArr[i] += delta; + } + } + + public int query(int idx) { + int result = 0; + for (int i = idx + 1; i > 0; i -= (i & -i)) { + result += bitArr[i]; + } + return result; + } + + public int range(int from, int to) { + if (from > to) { + return 0; + } + if (from == 0) { + return query(to); + } + int and = (from - 1) & to; + return query(to - and) - query(from - and - 1); + } + + public int up(int idx) { + return range(idx, bitArr.length - 2); + } +} + +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_51_466.java b/Week 07/id_466/LeetCode_51_466.java new file mode 100644 index 000000000..318983839 --- /dev/null +++ b/Week 07/id_466/LeetCode_51_466.java @@ -0,0 +1,162 @@ +//n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +// +// +// +// 上图为 8 皇后问题的一种解法。 +// +// 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 +// +// 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 +// +// 示例: +// +// 输入: 4 +//输出: [ +// [".Q..", // 解法 1 +// "...Q", +// "Q...", +// "..Q."], +// +// ["..Q.", // 解法 2 +// "Q...", +// "...Q", +// ".Q.."] +//] +//解释: 4 皇后问题存在两个不同的解法。 +// +// Related Topics 回溯算法 +package com.aseara.leetcode.editor.cn.a51; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * desc: 51.N皇后
    + * Date: 2019/11/22
    + * + * @author qiujingde + */ +class NQueens { + private Solution solution = new Solution(); + + @Test + void test1() { + System.out.println(solution.solveNQueens(1)); + System.out.println(solution.solveNQueens(4)); + System.out.println(solution.solveNQueens(8)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> solveNQueens(int n) { + if (n < 1) { + return null; + } + return method2(n); + } + + private List> method1(int n) { + List> resultStore = new LinkedList<>(); + + // init chars + char[] chars = new char[n]; + Arrays.fill(chars, '.'); + + boolean[] col = new boolean[n]; + // 撇 + boolean[] left = new boolean[2 * n]; + // 捺 + boolean[] right = new boolean[2 * n]; + + // 位置记录 + LinkedList stack = new LinkedList<>(); + + dfs(0, stack, n, col, left, right, resultStore, chars); + + return resultStore; + } + + private void dfs(int row, LinkedList stack, int n, + boolean[] col, boolean[] left, boolean[] right, + List> resultStore, char[] chars) { + if (row == n) { + // 遍历完成,合法数据 + resultStore.add(to2D(chars, stack)); + return; + } + + for (int i = 0; i < n; i++) { + if (!col[i] && !left[i - row + n] && !right[i + row]) { + stack.add(i); + col[i] = true; + left[i - row + n] = true; + right[i + row] = true; + + dfs(row + 1, stack, n, col, left, right, resultStore, chars); + + right[i + row] = false; + left[i - row + n] = false; + col[i] = false; + stack.removeLast(); + } + } + } + + private List to2D(char[] chars, List result) { + List results = new LinkedList<>(); + for (int index : result) { + chars[index] = 'Q'; + results.add(new String(chars)); + chars[index] = '.'; + } + return results; + } + + private List> method2(int n) { + List> store = new LinkedList<>(); + LinkedList stack = new LinkedList<>(); + + // init chars + char[] chars = new char[n]; + Arrays.fill(chars, '.'); + + dfs2(n, 0, 0, 0, 0, store, stack, chars); + + return store; + } + + private void dfs2(int n, int row, int cols, int pl, int pr, List> store, LinkedList stack, + char[] chars) { + if (row == n) { + store.add(to2D2(chars, stack)); + } + int pos = (~(cols | pl | pr)) & ((1 << n) - 1); + while (pos != 0) { + int p = pos & (-pos); + pos = pos & (pos - 1); + stack.add(p); + dfs2(n, row + 1, cols | p, (pl | p) << 1, (pr | p) >> 1, store, stack, chars); + stack.removeLast(); + } + } + + private List to2D2(char[] chars, List result) { + List results = new LinkedList<>(); + int n = chars.length; + for (int p : result) { + int index = n - 1 - Integer.numberOfTrailingZeros(p); + chars[index] = 'Q'; + results.add(new String(chars)); + chars[index] = '.'; + } + return results; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_52_466.java b/Week 07/id_466/LeetCode_52_466.java new file mode 100644 index 000000000..fe8b912c2 --- /dev/null +++ b/Week 07/id_466/LeetCode_52_466.java @@ -0,0 +1,122 @@ +//n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +// +// +// +// 上图为 8 皇后问题的一种解法。 +// +// 给定一个整数 n,返回 n 皇后不同的解决方案的数量。 +// +// 示例: +// +// 输入: 4 +//输出: 2 +//解释: 4 皇后问题存在如下两个不同的解法。 +//[ +// [".Q..",  // 解法 1 +//  "...Q", +//  "Q...", +//  "..Q."], +// +// ["..Q.",  // 解法 2 +//  "Q...", +//  "...Q", +//  ".Q.."] +//] +// +// Related Topics 回溯算法 +package com.aseara.leetcode.editor.cn.a52; + +import org.junit.jupiter.api.Test; + +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 52.N皇后 II
    + * Date: 2019/11/22
    + * + * @author qiujingde + */ +class NQueensIi { + private Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(1, solution.totalNQueens(1)); + assertEquals(2, solution.totalNQueens(4)); + assertEquals(92, solution.totalNQueens(8)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public int totalNQueens(int n) { + if (n < 1) { + return 0; + } + return method2(n); + } + + private int method1(int n) { + AtomicInteger counter = new AtomicInteger(0); + boolean[] col = new boolean[n]; + // 撇 + boolean[] left = new boolean[2 * n]; + // 捺 + boolean[] right = new boolean[2 * n]; + // 位置记录 + LinkedList stack = new LinkedList<>(); + dfs(0, stack, n, col, left, right, counter); + return counter.get(); + } + + private void dfs(int row, LinkedList stack, int n, + boolean[] col, boolean[] left, boolean[] right, + AtomicInteger counter) { + if (row == n) { + // 遍历完成,合法数据 + counter.getAndIncrement(); + return; + } + for (int i = 0; i < n; i++) { + if (!col[i] && !left[i - row + n] && !right[i + row]) { + stack.add(i); + col[i] = true; + left[i - row + n] = true; + right[i + row] = true; + + dfs(row + 1, stack, n, col, left, right, counter); + + right[i + row] = false; + left[i - row + n] = false; + col[i] = false; + stack.removeLast(); + } + } + } + + private int method2(int n) { + return dfs2(0, 0, 0, 0, n); + } + + private int dfs2(int row, int cols, int pl, int pr, int n) { + if (row == n) { + return 1; + } + int cnt = 0; + int pos = (~(cols | pl | pr)) & ((1 << n) - 1); + while (pos != 0) { + int p = pos & (-pos); + pos = pos & (pos - 1); + cnt += dfs2(row + 1, cols | p, (pl | p) << 1, (pr | p) >> 1, n); + } + return cnt; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_466/LeetCode_56_466.java b/Week 07/id_466/LeetCode_56_466.java new file mode 100644 index 000000000..1829d1f09 --- /dev/null +++ b/Week 07/id_466/LeetCode_56_466.java @@ -0,0 +1,149 @@ +//给出一个区间的集合,请合并所有重叠的区间。 +// +// 示例 1: +// +// 输入: [[1,3],[2,6],[8,10],[15,18]] +//输出: [[1,6],[8,10],[15,18]] +//解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. +// +// +// 示例 2: +// +// 输入: [[1,4],[4,5]] +//输出: [[1,5]] +//解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 +// Related Topics 排序 数组 +package com.aseara.leetcode.editor.cn.a56; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * desc: 56.合并区间
    + * Date: 2019/11/27
    + * + * @author qiujingde + */ +class MergeIntervals { + private Solution solution = new Solution(); + + @Test + void test1() { + int[][] intervals1 = {{1,3},{2,6},{8,10},{15,18}}; + int[][] expected1 = {{1,6},{8,10},{15,18}}; + assertArrayEquals(expected1, solution.merge(intervals1)); + + int[][] intervals2 = {{1,4},{4,5}}; + int[][] expected2 = {{1,5}}; + assertArrayEquals(expected2, solution.merge(intervals2)); + + int[][] intervals3 = {{2,3},{4,6},{5,7},{3,4}}; + int[][] expected3 = {{2,7}}; + assertArrayEquals(expected3, solution.merge(intervals3)); + + int[][] intervals4 = {{1,4},{0,0}}; + int[][] expected4 = {{0,0},{1,4}}; + assertArrayEquals(expected4, solution.merge(intervals4)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int[][] merge(int[][] intervals) { + if (intervals == null || intervals.length < 2) { + return intervals; + } + return merge3(intervals); + } + + private int[][] merge1(int[][] intervals) { + List result = new ArrayList<>(intervals.length); + Arrays.sort(intervals, Comparator.comparingInt(i -> i[0])); + for (int i = 0; i < intervals.length; i++) { + int[] mer = new int[2]; + mer[0] = intervals[i][0]; + int end = intervals[i][1]; + while (i + 1 < intervals.length && end >= intervals[i + 1][0]) { + i ++; + end = Math.max(end, intervals[i][1]); + } + mer[1] = end; + result.add(mer); + } + return result.toArray(new int[0][0]); + } + + // 归并排序实现 + private int[][] merge2(int[][] intervals, int start, int end) { + if (start == end) { + return new int[][] {intervals[start]}; + } + int mid = (start + end) >> 1; + int[][] left = merge2(intervals, start, mid); + int[][] right = merge2(intervals, mid + 1, end); + List result = new ArrayList<>(end - start); + int i = 0, j = 0; + while (i < left.length && j < right.length) { + int[] min = left[i][0] < right[j][0] ? left[i++] : right[j++]; + int l = min[0]; + int r = min[1]; + + while ((i < left.length && r >= left[i][0]) || (j < right.length && r >= right[j][0])) { + if (i < left.length && r >= left[i][0]) { + r = Math.max(r, left[i++][1]); + } + if (j < right.length && r >= right[j][0]) { + r = Math.max(r, right[j++][1]); + } + } + result.add(new int[] {l, r}); + } + for(; i < left.length; i++) { + result.add(left[i]); + } + for(; j < right.length; j++) { + result.add(right[j]); + } + return result.toArray(new int[0][0]); + } + + // + private int[][] merge3(int[][] intervals) { + if (intervals == null || intervals.length < 2) { + return intervals; + } + int cnt = 0; + for (int i = 0; i < intervals.length; i++) { + for (int j = i + 1; j < intervals.length; j++) { + if (intervals[i][1] >= intervals[j][0] && intervals[i][0] <= intervals[j][1]) { + if (intervals[i][0] < intervals[j][0]) { + intervals[j][0] = intervals[i][0]; + } + if (intervals[i][1] > intervals[j][1]) { + intervals[j][1] = intervals[i][1]; + } + intervals[i] = null; + cnt ++; + break; + } + } + } + int[][] result = new int[intervals.length - cnt][]; + for (int i = 0, j = 0; i < intervals.length; i++) { + if (intervals[i] != null) { + result[j++] = intervals[i]; + } + } + return result; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_471/LeetCode_190_471.java b/Week 07/id_471/LeetCode_190_471.java new file mode 100644 index 000000000..8990274b2 --- /dev/null +++ b/Week 07/id_471/LeetCode_190_471.java @@ -0,0 +1,13 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int res = 0; + for (int i = 0; i < 32; i++) { + res = res << 1; + res += n & 1; + n = n >> 1; + } + + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_471/LeetCode_191_471.java b/Week 07/id_471/LeetCode_191_471.java new file mode 100644 index 000000000..2e2b3ca19 --- /dev/null +++ b/Week 07/id_471/LeetCode_191_471.java @@ -0,0 +1,12 @@ +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 & (n - 1); + count++; + } + + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_471/LeetCode_231_471.java b/Week 07/id_471/LeetCode_231_471.java new file mode 100644 index 000000000..aeaac1421 --- /dev/null +++ b/Week 07/id_471/LeetCode_231_471.java @@ -0,0 +1,5 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_471/LeetCode_338_471.java b/Week 07/id_471/LeetCode_338_471.java new file mode 100644 index 000000000..03c0d0f01 --- /dev/null +++ b/Week 07/id_471/LeetCode_338_471.java @@ -0,0 +1,14 @@ +class Solution { + //dp[i] = dp[i / 2] + (i & 1); + public int[] countBits(int num) { + int dp[] = new int[num + 1]; + int results[] = new int[num + 1]; + + for (int i = 1; i <= num; i++) { + dp[i] = dp[i & (i - 1)] + 1; + results[i] = dp[i]; + } + + return results; + } +} \ No newline at end of file diff --git a/Week 07/id_471/LeetCode_51_471.java b/Week 07/id_471/LeetCode_51_471.java new file mode 100644 index 000000000..ab5172c7a --- /dev/null +++ b/Week 07/id_471/LeetCode_51_471.java @@ -0,0 +1,38 @@ +class Solution { + public List> solveNQueens(int n) { + int col[] = new int[n]; + int line1[] = new int[2 * n]; + int line2[] = new int[2 * n]; + List> results = new ArrayList<>(); + List result = new ArrayList<>(); + dfs(n, 0, col, line1, line2, result, results); + return results; + } + + public void dfs(int n, int row, int colLine[], int[] line1, int[] line2, List result, List> results) { + if (result.size() == n) { + results.add(new ArrayList<>(result)); + return; + } + + char[] s = new char[n]; + Arrays.fill(s, '.'); + for (int col = 0; col < s.length; col++) { + int id1 = col - row + n; + int id2 = col + row; + if (colLine[col] == 0 && line1[id1] == 0 && line2[id2] == 0) { + colLine[col] = 1; + line1[id1] = 1; + line2[id2] = 1; + s[col] = 'Q'; + result.add(new String(s)); + dfs(n, row + 1, colLine, line1, line2, result, results); + s[col] = '.'; + result.remove(result.size() - 1); + colLine[col] = 0; + line1[id1] = 0; + line2[id2] = 0; + } + } + } +} \ No newline at end of file diff --git a/Week 07/id_471/LeetCode_52_471.java b/Week 07/id_471/LeetCode_52_471.java new file mode 100644 index 000000000..a0f0b0122 --- /dev/null +++ b/Week 07/id_471/LeetCode_52_471.java @@ -0,0 +1,23 @@ +class Solution { + private int count; + public int totalNQueens(int n) { + int size = (1 << n) - 1; + count = 0; + dfs(0, 0, 0, size); + return count; + } + + public void dfs(int row, int pie, int na, int size) { + if (row == size) { + count++; + return; + } + + int pos = size & (~(row | pie | na)); + while (pos != 0) { + int p = pos & (-pos); + pos -= p; + dfs(row | p, (pie | p) >> 1, (na | p) << 1, size); + } + } +} \ No newline at end of file diff --git a/Week 07/id_476/LeetCode_1122_476.java b/Week 07/id_476/LeetCode_1122_476.java new file mode 100644 index 000000000..6c79b3812 --- /dev/null +++ b/Week 07/id_476/LeetCode_1122_476.java @@ -0,0 +1,56 @@ +public class LeetCode_1122_RelativeSortArray { + public static void main(String[] args) { + Solution solution = new LeetCode_1122_RelativeSortArray().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + + class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + // 计数排序 + int[] counterArr = new int[1001]; + for (int num : arr1) { + counterArr[num] += 1; + } + int[] res = new int[arr1.length]; + int i = 0; + for (int num : arr2) { + while (counterArr[num] > 0) { + res[i++] = num; + counterArr[num] -= 1; + } + } + for (int j = 0; j < counterArr.length; j++) { + while (counterArr[j] > 0) { + res[i++] = j; + counterArr[j] -= 1; + } + } + return res; + } + } + + class Solution1 { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + + int counter = 0; + for (int num : arr2) { + for (int i = counter; i < arr1.length; i++) { + if (arr1[i] == num) { + int temp = arr1[i]; + arr1[i] = arr1[counter]; + arr1[counter] = temp; + counter++; + } + } + } + if (counter < arr1.length) { + Arrays.sort(arr1, counter, arr1.length); + } + return arr1; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 07/id_476/LeetCode_146_476.java b/Week 07/id_476/LeetCode_146_476.java new file mode 100644 index 000000000..c2559aaaf --- /dev/null +++ b/Week 07/id_476/LeetCode_146_476.java @@ -0,0 +1,45 @@ +public class LeetCode_146_LruCache { + public static void main(String[] args) { + // Solution solution = new LeetCode_146_LruCache().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class LRUCache { + + private float loadFactor = 1.0f; + private LinkedHashMap cache; + private int cacheSize; + + public LRUCache(int capacity) { + + this.cacheSize = capacity; + this.cache = new LinkedHashMap(capacity, loadFactor, true) { + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > LRUCache.this.cacheSize; + } + }; + } + + public int get(int key) { + + return cache.getOrDefault(key, -1); + } + + public void put(int key, int value) { + + cache.put(key, value); + } + } + + /** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 07/id_476/LeetCode_191_476.java b/Week 07/id_476/LeetCode_191_476.java new file mode 100644 index 000000000..4fc30e877 --- /dev/null +++ b/Week 07/id_476/LeetCode_191_476.java @@ -0,0 +1,51 @@ +public class LeetCode_191_NumberOf1Bits { + public static void main(String[] args) { + Solution solution = new LeetCode_191_NumberOf1Bits().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + + int res = 0; + while (n != 0) { + res += (n & 1); + n >>>= 1; + } + return res; + } + } + + public class Solution2 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + + int res = 0; + while (n != 0) { + res++; + n &= (n - 1); + } + return res; + } + } + + public class Solution1 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + + int res = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + res++; + } + mask <<= 1; + } + return res; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 07/id_476/LeetCode_338_476.java b/Week 07/id_476/LeetCode_338_476.java new file mode 100644 index 000000000..d67221b40 --- /dev/null +++ b/Week 07/id_476/LeetCode_338_476.java @@ -0,0 +1,35 @@ +public class LeetCode_338_CountingBits { + public static void main(String[] args) { + Solution solution = new LeetCode_338_CountingBits().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int[] countBits(int num) { + + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } + } + + class Solution1 { + public int[] countBits(int num) { + + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + if ((i & 1) == 1) { + res[i] = res[i >> 1] + 1; + } else { + res[i] = res[i >> 1]; + } + } + return res; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 07/id_476/LeetCode_56_476.java b/Week 07/id_476/LeetCode_56_476.java new file mode 100644 index 000000000..08242417a --- /dev/null +++ b/Week 07/id_476/LeetCode_56_476.java @@ -0,0 +1,60 @@ +public class LeetCode_56_MergeIntervals { + public static void main(String[] args) { + Solution solution = new LeetCode_56_MergeIntervals().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int[][] merge(int[][] intervals) { + + if (intervals == null || intervals.length == 0) { + return intervals; + } + List res = new ArrayList<>(); + Arrays.sort(intervals, Comparator.comparingInt(o -> o[0])); + + int i = 0; + while (i < intervals.length) { + int left = intervals[i][0]; + int right = intervals[i][1]; + while (i < intervals.length - 1 && right >= intervals[i + 1][0]) { + right = Math.max(right, intervals[i + 1][1]); + i++; + } + res.add(new int[]{left, right}); + i++; + } + return res.toArray(new int[0][]); + } + } + + class Solution1 { + public int[][] merge(int[][] intervals) { + + if (intervals == null || intervals.length == 0) { + return intervals; + } + List res = new ArrayList<>(); + Arrays.sort(intervals, Comparator.comparingInt(o -> o[0])); + + for (int i = 0; i < intervals.length; i++) { + int left = intervals[i][0]; + int right = intervals[i][1]; + for (int j = i + 1; j < intervals.length; j++) { + if (right >= intervals[j][0]) { + // 前面区间的右区间包含了该区间的左区间 + right = Math.max(right, intervals[j][1]); + i++; + } else { + break; + } + } + res.add(new int[]{left, right}); + } + return res.toArray(new int[0][]); + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 07/id_476/Sort.java b/Week 07/id_476/Sort.java new file mode 100644 index 000000000..917440761 --- /dev/null +++ b/Week 07/id_476/Sort.java @@ -0,0 +1,182 @@ +package com.markdown.leetcode.editor.cn; + +import java.util.PriorityQueue; +import java.util.Random; + +/** + * 排序算法 + * + * @author Mark Li + * @version 1.0.0 + * @since 2019/12/1 + */ +public class Sort { + + public static void main(String[] args) { + + int[] array = new int[10]; + Random random = new Random(10); + for (int i = 0; i < array.length; i++) { + array[i] = random.nextInt(100); + System.out.println(array[i]); + } + + Sort sort = new Sort(); + + // sort.bubbleSort(array); + + // sort.insertionSort(array); + + // sort.selectionSort(array); + + // sort.quickSort(array); + + // sort.mergeSort(array); + + sort.heapSort(array); + + System.out.println("----------"); + for (int i : array) { + System.out.println(i); + } + } + + /** + * 冒泡排序 + * 稳定 + */ + private void bubbleSort(int[] array) { + + int length = array.length; + for (int i = 0; i < length - 1; i++) { + for (int j = 0; j < length - 1 - i; j++) { + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + } + } + + /** + * 插入排序 + * 稳定 + */ + private void insertionSort(int[] array) { + + int length = array.length; + for (int i = 1; i < length; i++) { + int current = array[i]; + int pre = i - 1; + while (pre >= 0 && array[pre] > current) { + array[pre + 1] = array[pre]; + pre--; + } + array[pre + 1] = current; + } + } + + /** + * 选择排序 + * 不稳定 + */ + private void selectionSort(int[] array) { + + int length = array.length; + for (int i = 0; i < length - 1; i++) { + int min = i; + for (int j = i + 1; j < length; j++) { + if (array[min] > array[j]) { + min = j; + } + } + int temp = array[i]; + array[i] = array[min]; + array[min] = temp; + } + } + + /** + * 快速排序 + * 不稳定 + */ + private void quickSort(int[] array) { + + quickSort(array, 0, array.length - 1); + } + private void quickSort(int[] array, int begin, int end) { + + if (begin >= end) return; + + int pivot = partition(array, begin, end); + quickSort(array, begin, pivot - 1); + quickSort(array, pivot + 1, end); + } + private int partition(int[] array, int begin, int end) { + // 小于 array[pivot] 的元素个数 + int counter = begin; + for (int i = begin; i < end; i++) { + if (array[i] < array[end]) { + int temp = array[counter]; + array[counter] = array[i]; + array[i] = temp; + counter++; + } + } + int temp = array[end]; + array[end] = array[counter]; + array[counter] = temp; + return counter; + } + + /** + * 归并排序 + * 稳定 + */ + private void mergeSort(int[] array) { + + mergeSort(array, 0, array.length - 1); + } + private void mergeSort(int[] array, int begin, int end) { + + if (begin >= end) return; + int middle = begin + (end - begin) / 2; + mergeSort(array, begin, middle); + mergeSort(array, middle + 1, end); + merge(array, begin, middle, end); + } + private void merge(int[] array, int begin, int middle, int end) { + + int left = begin, right = middle + 1; + int[] temp = new int[end - begin + 1]; + int tempIndex = 0; + while (left <= middle && right <= end) { + temp[tempIndex++] = array[left] <= array[right] ? array[left++] : array[right++]; + } + while (left <= middle) { + temp[tempIndex++] = array[left++]; + } + while (right <= end) { + temp[tempIndex++] = array[right++]; + } + for (int num: temp) { + array[begin++] = num; + } + } + + /** + * 堆排序 + * 不稳定 + */ + private void heapSort(int[] array) { + + PriorityQueue queue = new PriorityQueue<>(array.length); + for (int num : array) { + queue.offer(num); + } + for (int i = 0; i < array.length; i++) { + array[i] = queue.poll(); + } + } +} diff --git a/Week 07/id_491/LeetCode_1122_491.java b/Week 07/id_491/LeetCode_1122_491.java new file mode 100644 index 000000000..32547ec2d --- /dev/null +++ b/Week 07/id_491/LeetCode_1122_491.java @@ -0,0 +1,30 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int max = 0; + for (int i = 0; i < arr1.length; i++) { + if(arr1[i] > max) { + max = arr1[i]; + } + } + + int[] memo = new int[max + 1]; + for (int i = 0; i < arr1.length; i++) { + memo[arr1[i]] = memo[arr1[i]] + 1; + } + int j = 0; + for (int p = 0; p < arr2.length; p++) { + for (int k = 0; k < memo[arr2[p]]; k++) { + arr1[j++] = arr2[p]; + } + memo[arr2[p]] = 0; + } + + for (int i = 0; i < memo.length; i++) { + for (int k = 0; k < memo[i]; k++) { + arr1[j++] = i; + } + } + + return arr1; + } +} diff --git a/Week 07/id_491/LeetCode_146_491.java b/Week 07/id_491/LeetCode_146_491.java new file mode 100644 index 000000000..c00a0a08d --- /dev/null +++ b/Week 07/id_491/LeetCode_146_491.java @@ -0,0 +1,90 @@ +class LRUCache { + + class DoubleLinkedListNode { + public int key; + public int value; + public DoubleLinkedListNode prev; + public DoubleLinkedListNode next; + } + + private Map memo; + private DoubleLinkedListNode head; + private DoubleLinkedListNode tail; + private int size; + private int capacity; + + private void add(DoubleLinkedListNode newNode) { + newNode.next = tail; + newNode.prev = tail.prev; + tail.prev.next = newNode; + tail.prev = newNode; + size++; + } + + private DoubleLinkedListNode pop() { + if (head.next == tail) { + return null; + } + size--; + DoubleLinkedListNode first = head.next; + head.next = first.next; + head.next.prev = head; + return first; + } + + private void moveToTail(DoubleLinkedListNode node) { + if (this.size == 1) { + return; + } else { + node.prev.next = node.next; + node.next.prev = node.prev; + node.prev = tail.prev; + node.next = tail; + tail.prev.next = node; + tail.prev = node; + } + } + + public LRUCache(int capacity) { + this.capacity = capacity; + this.memo = new HashMap<>(capacity); + this.size = 0; + this.head = new DoubleLinkedListNode(); + this.tail = new DoubleLinkedListNode(); + this.head.next = tail; + this.tail.prev = head; + } + + public int get(int key) { + if(memo.containsKey(key)) { + DoubleLinkedListNode temp = memo.get(key); + this.moveToTail(temp); + return temp.value; + } + return -1; + } + + public void put(int key, int value) { + DoubleLinkedListNode temp = null; + if(memo.containsKey(key)) { + temp = memo.get(key); + temp.value = value; + this.moveToTail(temp); + } else { + temp = new DoubleLinkedListNode(); + temp.key = key; + temp.value = value; + if(this.size == this.capacity) { + DoubleLinkedListNode deleted = this.pop(); + this.memo.remove(deleted.key); + } + this.add(temp); + this.memo.put(key, temp); + } + } +} + +/** + * Your LRUCache object will be instantiated and called as such: LRUCache obj = + * new LRUCache(capacity); int param_1 = obj.get(key); obj.put(key,value); + */ diff --git a/Week 07/id_491/LeetCode_190_491.java b/Week 07/id_491/LeetCode_190_491.java new file mode 100644 index 000000000..3439fc8e3 --- /dev/null +++ b/Week 07/id_491/LeetCode_190_491.java @@ -0,0 +1,12 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + int mask = 1; + for(int i = 0 ;i < 32; i++) { + result = (result << 1) + (n & mask); + n = n >> 1; + } + return result; + } +} diff --git a/Week 07/id_491/LeetCode_191_491.java b/Week 07/id_491/LeetCode_191_491.java new file mode 100644 index 000000000..625db9d45 --- /dev/null +++ b/Week 07/id_491/LeetCode_191_491.java @@ -0,0 +1,17 @@ +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + long temp = n; + if(temp < 0) { + temp = (Integer.MAX_VALUE + 1L) * 2L + temp; + } + + int result = 0; + while(temp != 0) { + result += temp % 2; + temp = temp >> 1 ; + } + + return result; + } +} diff --git a/Week 07/id_491/LeetCode_231_491.java b/Week 07/id_491/LeetCode_231_491.java new file mode 100644 index 000000000..0c2686299 --- /dev/null +++ b/Week 07/id_491/LeetCode_231_491.java @@ -0,0 +1,5 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_491/LeetCode_242_491.java b/Week 07/id_491/LeetCode_242_491.java new file mode 100644 index 000000000..d3b0534e4 --- /dev/null +++ b/Week 07/id_491/LeetCode_242_491.java @@ -0,0 +1,21 @@ +class Solution { + public boolean isAnagram(String s, String t) { + if (s == null || t == null || s.length() != t.length()) { + return false; + } + int[] bitMap = new int[26]; + for (int i = 0; i < s.length(); i++) { + int tempS = s.charAt(i) - 97; + int tempT = t.charAt(i) - 97; + bitMap[tempS] = bitMap[tempS] + 1; + bitMap[tempT] = bitMap[tempT] - 1; + } + + for (int i = 0; i < 26; i++) { + if (bitMap[i] != 0) { + return false; + } + } + return true; + } +} diff --git a/Week 07/id_491/LeetCode_493_491.java b/Week 07/id_491/LeetCode_493_491.java new file mode 100644 index 000000000..032cbb814 --- /dev/null +++ b/Week 07/id_491/LeetCode_493_491.java @@ -0,0 +1,58 @@ +public class Solution { + + public int reversePairs(int[] nums) { + if(nums.length <= 1) { + return 0; + } + return mergeSort(nums, 0 , nums.length - 1); + } + + public static int mergeSort(int[] array, int begin, int end) { + int result = 0; + if (begin == end) { + return 0; + } + + int mid = (begin + end) / 2; + result += mergeSort(array, begin, mid); + result += mergeSort(array, mid + 1, end); + result += merge(array, begin, mid, end); + return result; + } + + public static int merge(int[] array, int begin, int mid, int end) { + int result = 0; + int firstBegin = begin; + int secondBegin = mid + 1; + int j = 0; + int[] memo = new int[end - begin + 1]; + + while (firstBegin <= mid && secondBegin <= end) { + if(array[firstBegin] > 2L * array[secondBegin]) { + result += mid - firstBegin + 1; + secondBegin++; + } else { + firstBegin++; + } + } + + firstBegin = begin; + secondBegin = mid + 1; + while (firstBegin <= mid && secondBegin <= end) { + memo[j++] = array[firstBegin] < array[secondBegin] ? array[firstBegin++] : array[secondBegin++]; + } + + while (firstBegin <= mid) { + memo[j++] = array[firstBegin++]; + } + + while (secondBegin <= end) { + memo[j++] = array[secondBegin++]; + } + + for (int i = 0; i < memo.length; i++) { + array[begin++] = memo[i]; + } + return result; + } +} diff --git a/Week 07/id_491/LeetCode_51_491.java b/Week 07/id_491/LeetCode_51_491.java new file mode 100644 index 000000000..10337f846 --- /dev/null +++ b/Week 07/id_491/LeetCode_51_491.java @@ -0,0 +1,42 @@ +class Solution { + + private List> result = new ArrayList<>(); + + public List> solveNQueens(int n) { + int[] row = new int[n]; + int lie = 0; + int pie = 0; + int na = 0; + recursion(0, n, row, lie, pie, na); + return result; + } + + void recursion(int current, int n, int[] row, int lie, int pie, int na) { + if (current == n) { + List tempResult = new ArrayList<>(); + for (int i = 0; i < n; i++) { + StringBuilder sb = new StringBuilder(); + for(int j = 0; j < n; j++) { + if(row[i] == j) { + sb.append("Q"); + } else { + sb.append("."); + } + } + tempResult.add(sb.toString()); + } + this.result.add(tempResult); + } + + for (int i = 0; i < n; i++) { + if ((lie & (1 << i)) == 0 + && (pie & (1 << (i + current))) == 0 + && (na & ( 1 << (current + n - 1 - i))) == 0) { + row[current] = i; + recursion(current + 1, n, row, lie + (1 << i), pie + (1 << (i + current)), na + (1 << (current + n - 1 - i))); + row[current] = 0; + } + } + + } +} diff --git a/Week 07/id_491/LeetCode_52_491.java b/Week 07/id_491/LeetCode_52_491.java new file mode 100644 index 000000000..a7b0b95e4 --- /dev/null +++ b/Week 07/id_491/LeetCode_52_491.java @@ -0,0 +1,20 @@ +class Solution { + private int count; + public int totalNQueens(int n) { + recursion(0, n, 0, 0, 0); + return this.count; + } + + void recursion(int current, int n, int lie, int pie, int na) { + if (current == n) { + this.count++; + } + + for (int i = 0; i < n; i++) { + if ((lie & (1 << i)) == 0 && (pie & (1 << (i + current))) == 0 && (na & ( 1 << (current + n - 1 - i))) == 0) { + recursion(current + 1, n, lie + (1 << i), pie + (1 << (i + current)), na + (1 << (current + n - 1 - i))); + } + } + + } +} diff --git a/Week 07/id_491/LeetCode_56_491.java b/Week 07/id_491/LeetCode_56_491.java new file mode 100644 index 000000000..38a8af8d5 --- /dev/null +++ b/Week 07/id_491/LeetCode_56_491.java @@ -0,0 +1,44 @@ +class Solution { + public int[][] merge(int[][] intervals) { + if (intervals.length <= 1) { + return intervals; + } + + List result = new ArrayList<>(); + List nextList = new ArrayList<>(); + int[] temp = intervals[0]; + boolean doCombine = false; + for (int i = 1; i < intervals.length; i++) { + if(temp[1] < intervals[i][1]) { + if(temp[1] >= intervals[i][0] && temp[1] <= intervals[i][1]) { + temp[0] = Math.min(temp[0], intervals[i][0]); + temp[1] = Math.max(temp[1], intervals[i][1]); + doCombine = true; + } else { + nextList.add(intervals[i]); + } + } else { + if(intervals[i][1] >= temp[0] && intervals[i][1] <= temp[1]) { + temp[0] = Math.min(temp[0], intervals[i][0]); + temp[1] = Math.max(temp[1], intervals[i][1]); + doCombine = true; + } else { + nextList.add(intervals[i]); + } + } + } + + if(doCombine) { + nextList.add(temp); + } else { + result.add(temp); + } + + if(nextList.size() > 0) { + int[][] nextResult = merge(nextList.toArray(new int[nextList.size()][])); + result.addAll(Arrays.asList(nextResult)); + } + + return result.toArray(new int[result.size()][]); + } +} diff --git a/Week 07/id_501/week07/LeetCode_1122_501.java b/Week 07/id_501/week07/LeetCode_1122_501.java new file mode 100644 index 000000000..1d7d1b938 --- /dev/null +++ b/Week 07/id_501/week07/LeetCode_1122_501.java @@ -0,0 +1,30 @@ +package homework.week07; + +/** + * 1122. 数组的相对排序 + * https://leetcode-cn.com/problems/relative-sort-array/ + * @author tangxy + * @date 2019-12-01 + */ +public class LeetCode_1122_501 { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] arr = new int[1001]; + for (int i : arr1) { + arr[i]++; + } + int index = 0; + for (int i : arr2) { + while(arr[i] > 0){ + arr1[index ++] = i; + arr[i] --; + } + } + for(int i = 0;i<1001;i++){ + while (arr[i] > 0){ + arr1[index++] = i; + arr[i]--; + } + } + return arr1; + } +} diff --git a/Week 07/id_501/week07/LeetCode_231_501.java b/Week 07/id_501/week07/LeetCode_231_501.java new file mode 100644 index 000000000..c6417ecb5 --- /dev/null +++ b/Week 07/id_501/week07/LeetCode_231_501.java @@ -0,0 +1,13 @@ +package homework.week07; + +/** + * 231. 2的幂 + * https://leetcode-cn.com/problems/power-of-two/ + * @author tangxy + * @date 2019-12-01 + */ +public class LeetCode_231_501 { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_501/week07/LeetCode_242_501.java b/Week 07/id_501/week07/LeetCode_242_501.java new file mode 100644 index 000000000..a25c025b9 --- /dev/null +++ b/Week 07/id_501/week07/LeetCode_242_501.java @@ -0,0 +1,26 @@ +package homework.week07; + +/** + * 242. 有效的字母异位词 + * https://leetcode-cn.com/problems/valid-anagram + * @author tangxy + * @date 2019-12-01 + */ +public class LeetCode_242_501 { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] table = new int[26]; + for (int i = 0; i < s.length(); i++) { + table[s.charAt(i) - 'a']++; + } + for (int i = 0; i < t.length(); i++) { + table[t.charAt(i) - 'a']--; + if (table[t.charAt(i) - 'a'] < 0) { + return false; + } + } + return true; + } +} diff --git a/Week 07/id_506/LeetCode_190_506.java b/Week 07/id_506/LeetCode_190_506.java new file mode 100644 index 000000000..59cdd346f --- /dev/null +++ b/Week 07/id_506/LeetCode_190_506.java @@ -0,0 +1,17 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int i = 0; + for (int index = 0; index < 32; index++){ + + i = i << 1; + if ((n & 1) == 1){ + i ++; + } + + n = n >> 1; + } + + return i; + } +} \ No newline at end of file diff --git a/Week 07/id_506/LeetCode_231_506.java b/Week 07/id_506/LeetCode_231_506.java new file mode 100644 index 000000000..574298ca7 --- /dev/null +++ b/Week 07/id_506/LeetCode_231_506.java @@ -0,0 +1,5 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && ((n & (n -1)) == 0); + } +} \ No newline at end of file diff --git a/Week 07/id_506/LeetCode_338_506.java b/Week 07/id_506/LeetCode_338_506.java new file mode 100644 index 000000000..e53944997 --- /dev/null +++ b/Week 07/id_506/LeetCode_338_506.java @@ -0,0 +1,17 @@ +class Solution { + public int[] countBits(int num) { + + int[] result = new int[num+1]; + result[0] = 0; + for(int i = 1; i < num + 1 ; i++){ + if ((i & 1) == 1){ + result[i] = result[i - 1] + 1; + }else{ + result[i] = result[i >> 1]; + } + + } + + return result; + } +} \ No newline at end of file diff --git a/Week 07/id_516/Leetcode_1122_516.java b/Week 07/id_516/Leetcode_1122_516.java new file mode 100644 index 000000000..6245848c1 --- /dev/null +++ b/Week 07/id_516/Leetcode_1122_516.java @@ -0,0 +1,18 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] count = new int[1001]; + for (int n : arr1) count[n]++; + int i = 0; + for (int n : arr2) { + while (count[n]-- > 0) { + arr1[i++] = n; + } + } + for (int n = 0; n < count.length; n++) { + while (count[n]-- > 0) { + arr1[i++] = n; + } + } + return arr1; + } +} diff --git a/Week 07/id_516/Leetcode_242_516.java b/Week 07/id_516/Leetcode_242_516.java new file mode 100644 index 000000000..4382de522 --- /dev/null +++ b/Week 07/id_516/Leetcode_242_516.java @@ -0,0 +1,9 @@ +public class Solution { + public boolean isAnagram(String s,String t) { + int[] alphabet = new int[26]; + for (int i = 0; i < s.length(); i++) alphabet[s.charAt(i) - 'a']++; + for (int i = 0; i < t.length(); i++) alphabet[t.chatAt(i) - 'a']--; + for (int i : alphabet) if (i != 0) return false; + return true; + } +} diff --git a/Week 07/id_516/NOTE.md b/Week 07/id_516/NOTE.md index a6321d6e2..0a1853aab 100644 --- a/Week 07/id_516/NOTE.md +++ b/Week 07/id_516/NOTE.md @@ -1,4 +1,632 @@ -# NOTE +1. # Week07 - + + ## 位运算 + + - 位运算符 + - 算数移位与逻辑移位 + - 位运算的应用 + + + + > | : 按位或 : 有1则为1 + > + > & : 按位与 : 有0则为0 + > + > ~ : 按位取反 : 取反 + > + > ^ : 按位异或 : 相同为0不同为1 + + + + ### XOR-异或 + + > 异或:相同为0,不同为1,也可以用『不进位加法』来理解 + > + > 异或操作的一些特点: + > + > x ^ 0 = x + > + > x ^ 1s = ~x // 1s = ~0 + > + > x ^ (~x) = 1s + > + > x ^ x = 0 + > + > c = a ^ b = > a ^ c = b,b ^ c = a //交换两个数 + > + > a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative + + + + ### 指定位置的位运算 + + 1. 将x最右边的n位清零: x & (~0 << n) => x & (1\*(64-n)0\*n) + 2. 获取x的第n位值 (0 或者 1): (x >> n) & 1 + 3. 获取x的第n位的幂值: x & (1 << (n - 1)) + 4. 仅将第n位置为1: x | (1 << n) + 5. 仅将第n位置为0: x & (~(1 << n)) + 6. 将x最高位至第n位(含) 清零: x & ((1 << n) - 1) + 7. 将第n位至第0位(含)清零: x & (~((1 << (n + 1)) - 1)) + + + + ### 实战位运算要点 + + - 判断奇偶性 + - x % 2 == 1 -> (x & 1) == 1 + - x % 2 == 0 -> (x & 1) == 0 + - 除以2 乘以 2 + - x /= 2 -> x = x >> 1 + - x *= 2 -> x = x << 1 + - x = x & (x - 1) 清零最低位的1 + - x = 0110 1000 -> x - 1 = 0110 0111 + - 0110 0000 + - x & -x 得到最低位的1 + - x & ~x = 0 + + + + ### 题目 + + + + ```java + public int hammingWeigth(int n) { + int sum = 0; + while (n != 0) { + sum ++; + n &= (n - 1); + } + return sum; + } + ``` + + + + ```java + public boolean isPowerOfTwo(int n) { + if (n < 0) return false; + int sum = 0; + while(n != 0) { + if (sum > 1) return false; + sum ++; + n &= (n - 1); + } + return sum == 1; + } + ``` + + + + ```java + public int reverssseBits(int n) { + int ans = 0; + for (int i = 0; i < 32 ;i++) { + ans = (ans << 1) + (n & 1); + n >>= 1; + } + return ans >>> 0; + } + ``` + + + + ```python + def totalNQueens(self, n): + if n < 1: return [] + self.count = 0 + self.DFS(n, 0, 0, 0, 0) + return self.count + + def DFS(self, n, row, cols, pie, na): + if row >= n: + self.count += 1 + return + bits = (~(cols | pie | na)) & ((1 << n) - 1) # 得到当前所有的空位 + while bits: + p = bits & -bits + bits = bits & (bits - 1) + self.DFS(n, row + 1, cols | p, (pie | p) << 1, (na | p) >> 1) + + ``` + + + + ```java + class Solution { + private int size; + private int count; + + private void solve(int row,int ld,int rd) { + if (row == size) { + count ++; + return; + } + int pos = size & (~(row | ld | rd)); + while (pos != 0) { + int p = pos & (-pos); + pos -= p; + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + solve(0,0,0); + return count; + } + } + ``` + + + + 338 + + ```c++ + vector countBits(int num) { + vector bits(num+1, 0); + for (int i = 1; i <= num; i++) { + bits[i] += bits[i & (i - 1)] + 1; + } + return bits; + } + ``` + + + + + + + + ## Bloom Filter + + > 一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检测一个元素是否在一个集合中。 + > + > 优点是 空间效率和查询时间都远远超过一般的算法。 + > + > 缺点是有一定的误识别率和删除困难 + + + + ```python + from bitarray import bitarray + import mmh3 + + class BloomFilter: + def __init__(self, size, hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray(size) + self.bit_array.setall(0) + + def add(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + self.bit_array[result] = 1 + def lookup(self, s): + for seed in range(self.hash_num): + if self.bit_array[result] == 0: + return "Nope" + return "Probably" + + bf = BloomFilter(500000,7) + bf.add("dantezhao") + print(bf.lookup("dantezhao")) + print(bf.lookup("yyj")) + ``` + + + + + + ```java + public class BloomFilter implements Cloneable { + private BitSet hashes; + private RandomInRange prng; + private int k; + private static final double LN2 = 0.6931471805599453; + + public BloomFilter(int n,int m) { + k = (int) Math.rount(LN2 * m / n); + if (k <= 0) k = 1; + this.hashes = new BitSet(m); + this.prng = new RandomInRange(m,k); + } + + public BloomFilter(int n) { + this(n,1024 * 1024 * 8); + } + + + public void add(Object o) { + prng.init(o); + for (RandomInRange r: prng) hashes.set(r.value); + } + + public boolean contains(Object o) { + prng.init(o); + for (RandomInRange r: prng) + if (!hashes.get(r.value)) + return false; + return true; + } + + + public void clear() { + hashes.clear(); + } + + public BloomFilter clone() throws CloneNotSupportedException { + return (BloomFilter) super.clone(); + } + + + public int hashCode() { + return hashes.hashCode() ^ k; + } + + public boolean equals(BloomFilter other) { + return this.hashes.equals(other.hashes) && this.k == other.k; + } + + + public void merge(BloomFilter other) { + if (other.k != this.k || other.hashes.size() != this.hashes.size()) { + throw new IllegalArgumentException("Incompatible bloom filters"); + } + this.hashes.or(other.hashes); + } + + + private class RandomInRange implements Iterable,Iterator { + private Random prng; + private int max; + private int count; + private int i = 0; + private int value; + + RandomInRange(int maximum, int k) { + max = maximum; + count = k; + prng = new Random(); + } + + public void init(Object o) { + prng.setSeed(o.hashCode()); + } + + + public Iterator iterator() { + i = 0; + return this; + } + + + public RandomInRange next() { + i ++; + value = prng.nextInt() % max; + if (value < 0) value = -value; + return this; + } + + public boolean hasNext() { + return i < count; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + } + ``` + + + + + + ## LRU Cache + + > lease recent used Cache + > + > 两个要素: 大小、替换策略 + > + > Hash Table + Doulbe LinkedList + > + > O(1) 查询 + > + > O(1) 修改、更新 + + + + ### 替换策略 + + > https://en.wikipedia.org/wiki/Cache_replacement_policies + + + + ```python + class LRUCache(object): + def __init__(self, capacity): + self.dic = collections.OrderedDict() + self.remain = capacity + + def get(self, key): + if key not in self.dic: + return -1 + v = self.dic.pop(key) + self.dic[key] = v + return v + + def put(self, key, value): + if key in self.dic: + self.dic.pop(key) + else: + if self.remain > 0: + self.remain -= 1 + else: + self.dic.popitem(last=False) + self.dic[key] = value + + ``` + + + + + + ## 排序 + + 1. 比较类排序 + + 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 + + 2. 非比较类排序 + + 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 + + + + ### 初级排序 + + 1. 选择排序 + + ```java + public int[] selectSort(int[] arr]) { + int len = arr.length; + int minIndex,temp; + + for (int i = 0; i < len - 1;i++) { + minIndex = i; + for (int j = i + 1; j < len;j++ ) { + if (arr[j] < arr[minIndex]) { + minIndex = k; + } + } + temp = arr[i]; + arr[i] = arr[minIndex]; + arr[minIndex] = temp; + } + return arr; + } + + ``` + + + + 2. 插入排序 + + ```java + public int[] insertionSort(int[] arr) { + int len = arr.length; + int preIndex,current; + for (int i = 1;i < len;i++) { + preIndex = i - 1; + current = arr[i]; + while ( preIndex >= 0 && arr[preIndex] > current) { + arr[preIndex + 1] = arr[preIndex]; + preIndex --; + } + arr[preIndex + 1] = current; + } + return arr; + } + + ``` + + + + 3. 冒泡排序 + + + + + + ### 高级排序 + + 1. 快速排序 + + > 数组取标杆pivot,将小元素放在pivot左边,大元素放右边,然后依次对右边和右边的子数组继续快排;以达到整个序列有序。 + + ```java + public static void quickSort(int[] array, int begin, int end) { + if (end <= begin) return ; + int pivot = partition(array, begin, end); + quickSort(array, begin, privot - 1); + quickSort(array, pivot + 1, end); + } + + public int partition(int[] a, int begin, int end){ + int pivot = end, counter = begin; + for (int i = begin; i < end; i++) { + if (a[i] < a[pivot]) { + int temp = a[counter]; + a[counter] = a[i]; + a[i] = temp; + count++; + } + } + int temp = a[pivot]; + a[pivot] = a[counter]; + a[counter] = temp; + return counter; + } + + ``` + + + + 2. 归并排序 + + > 分治 + > + > 1. 把长度为n的输入序列分成两个长度为n/2的子序列; + > 2. 对这两个子序列分别采用归并排序; + > 3. 将两个排序好的子序列合并成一个最终的排序序列。 + + ```java + public static void mergeSort(int[] array, int left, int right) { + if (right <= left) return; + int mid = (left + right) >> 1; + mergeSort(array, left, mid); + mergeSort(array, mid + 1, right); + merge(array, left, mid, right); + } + + public static void merge(int[] arr, int left, int mid, int right) { + int[] temp = new int[right - left + 1]; + int i = left, j = mid + 1, k = 0; + while (i <= mid && j <= right) { + temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; + } + while (i <= mid) temp[k++] = arr[i++]; + while (j <= right) temp[k++] = arr[j++]; + for (int p = 0; p < temp.length; p++) { + arr[left + p] = temp[p]; + } + } + + ``` + + + + 3. 堆排序 + + > 堆排序(Heap sort) -堆插入 O(logN),取最大、小值 O(1) + > + > 1. 数组元素依次建立小顶堆 + > 2. 依次取顶堆元素,并删除 + + ```c++ + public static void heapSort(int[] array) { + if (array.length == 0) return ; + int length = array.length; + for (int i = length / 2 - 1; i>= 0; i--) + heapify(array, length, i); + + for (int i = length - 1; i >= 0; i--) { + int temp = array[0]; array[0] = array[i]; array[i] temp; + heapify(array, i, 0); + } + } + + static void heapify(int[] array, int length, int i) { + int left = 2 * i + 1, right = 2 * i + 2; + int largetest = i; + if (left < length && array[left] > array[largest]) { + largest = leftChild; + } + if (right < length && array[right] > array[largest]) { + largest = right; + } + if (largest != i) { + int temp = array[i]; array[i] = array[largest]; array[largest] = temp; + heapify(array, length, largest); + } + } + + ``` + + + + ### 特殊排序 + + + + 1. 计数排序 + 2. 桶排序 + 3. 基排序 + + + + + + + + ## 题目 + + 1. [242 ]() + + > 给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。 + + + + 2. [56 合并区间]() + + > 合并区间 + + 3. [493 翻转对]() + + ```java + public class Solution { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length - 1); + } + + private int mergeSort(int[] nums,int s,int e) { + if (s >= e) return 0; + int mid = s + (e - s) / 2; + int cnt = mergeSort(nums, s, mid) + mergeSort(nums, mid + 1, e); + for (int i = s, j = mid + 1; i <= mid; i++) { + while (j <= e && nums[i] / 2.0 > nums[j]) j++; + cnt += j - (mid + 1); + } + Arrays.sort(nums, s, e + 1); + return cnt; + } + } + + ``` + + ```java + public class Solution { + public int reversePairs(int[] nums) { + if (nums == null || nums.length == 0) return 0; + return mergeeSort(nums, 0, nums.length - 1); + } + + private int mergeSort(int[] nums,int l ,int r) { + if (l >= r) return 0; + int mid = l + (r - 1) / 2; + int count = mergeSort(nums, l, mid) + mergeeSort(nums, mid + 1,r); + int[] cache = new int[r - l + 1]; + for (int j = mid + 1, j <= r ; j ++,c++) { + while (i <= mid && nums[i] <= 2 * (long) nums[j]) i++; + while (t <= mid && nums[t] < nums[j]) cache[c++] = nums[t++]; + cache[c] = nums[j]; + count += mid - i + 1; + } + while (t <= mid) cache[c++] = nums[t++]; + System.arraycopy(cache, 0, nums, l, r - l + 1); + return count; + } + } + + ``` + + + + ## 总结 + + 这周感觉不是很难,花的时间也不是特别多,自身的事情也有点多,希望复习上周的课程也没有能实现。时间还是需要在平时多多挤出来,才能有成效哦。 \ No newline at end of file diff --git "a/Week 07/id_521/\345\274\202\344\275\215\350\257\215.js" "b/Week 07/id_521/\345\274\202\344\275\215\350\257\215.js" new file mode 100644 index 000000000..ca1e59a94 --- /dev/null +++ "b/Week 07/id_521/\345\274\202\344\275\215\350\257\215.js" @@ -0,0 +1,15 @@ +var isAnagram = function(s, t) { + let arrS = Array.prototype.slice + .call(s) + .sort() + .toString() + let arrT = Array.prototype.slice + .call(t) + .sort() + .toString() + + if (arrS === arrT) { + return true + } + return false +} diff --git "a/Week 07/id_521/\347\233\270\345\257\271\346\216\222\345\272\217.js" "b/Week 07/id_521/\347\233\270\345\257\271\346\216\222\345\272\217.js" new file mode 100644 index 000000000..ce9c9fb27 --- /dev/null +++ "b/Week 07/id_521/\347\233\270\345\257\271\346\216\222\345\272\217.js" @@ -0,0 +1,21 @@ +var relativeSortArray = function(arr1, arr2) { + let maxValue = Math.max(...arr1) + let bucket = new Array(maxValue + 1).fill(0) + let result = [] + for (let i = 0; i < arr1.length; i++) { + bucket[arr1[i]]++ + } + for (let j = 0; j < arr2.length; j++) { + while (bucket[arr2[j]] > 0) { + result.push(arr2[j]) + bucket[arr2[j]]-- + } + } + for (let r = 0; r <= maxValue; r++) { + while (bucket[r] > 0) { + result.push(r) + bucket[r]-- + } + } + return result +} diff --git a/Week 07/id_536/leetcode_190_536.cpp b/Week 07/id_536/leetcode_190_536.cpp new file mode 100644 index 000000000..13f53cd27 --- /dev/null +++ b/Week 07/id_536/leetcode_190_536.cpp @@ -0,0 +1,33 @@ +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1λ + ******/ + uint32_t helper1(uint32_t n) { + uint32_t res = 0; + for(int i = 0; i< 32; ++i) { + res <<= 1; + res += n & 1; + n >>= 1; + } + return res; + } + + uint32_t reverseBits(uint32_t n) { + uint32_t res; + res = helper1(n); + return res; + } +}; + +int main() +{ + Solution s; + uint32_t res = s.reverseBits(00000010100101000001111010011100); + cout << res << endl; + return 0; +} diff --git a/Week 07/id_536/leetcode_191_536.cpp b/Week 07/id_536/leetcode_191_536.cpp new file mode 100644 index 000000000..d22064406 --- /dev/null +++ b/Week 07/id_536/leetcode_191_536.cpp @@ -0,0 +1,69 @@ +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1ģʮתơȡģ + ʱ临ӶȣO(1) + ռ临ӶȣO(1) + *******/ + int helper1(uint32_t n) { + int res = 0; + while(n) { + //if(n % 2) + if(n & 1) + ++ res; + n >>= 1; + } + return res; + } + + /***** + ⷨ2ѭλƶ + ʱ临ӶȣO(1) + ռ临ӶȣO(1) + *******/ + int helper2(uint32_t n) { + int res = 0; + uint32_t mask = 1; + for(int i = 0; i < 32; ++i) { + if(n & mask) + ++ res; + mask <<= 1; + } + return res; + } + + /***** + ⷨ3λ + ʱ临ӶȣO(1) + ռ临ӶȣO(1) + *******/ + int helper3(uint32_t n) { + int res = 0; + while(n) { + ++ res; + n &= (n - 1);// nn-1㣬һ1λ0 + } + return res; + } + + int hammingWeight(uint32_t n) { + int res; + //res = helper1(n);//ģʮתƣִʱ0ms + res = helper2(n);//ѭλƶִʱ8ms + //res = helper3(n);//λɣִʱ4ms + return res; + } +}; + +int main() +{ + Solution s; + uint32_t n = 00000000000000000000000000001011; + int res = s.hammingWeight(n); + cout << res << endl; + return 0; +} diff --git a/Week 07/id_536/leetcode_231_536.cpp b/Week 07/id_536/leetcode_231_536.cpp new file mode 100644 index 000000000..3e3d47ec7 --- /dev/null +++ b/Week 07/id_536/leetcode_231_536.cpp @@ -0,0 +1,63 @@ +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1λɣ11 + ******/ + bool helper1(int n) { + int cnt = 0; + while(n) { + ++ cnt; + n &= (n-1); + if(cnt == 2) + return false; + } + return true; + } + + /***** + ⷨ2λ + ******/ + bool helper2(int n) { + return (n&(n-1)) == 0; + } + + /***** + ⷨ3ģʮתƣȡģ + ******/ + bool helper3(int n) { + int cnt = 0; + while(n) { + if(n & 1) + ++ cnt; + n >>= 1; + if(cnt == 2) + return false; + } + return true; + } + + bool isPowerOfTwo(int n) { + if(n <= 0) + return false; + bool res; + //res = helper1(n); + res = helper2(n); + //res = helper3(n); + return res; + } +}; + +int main() +{ + Solution s; + bool res = s.isPowerOfTwo(2); + if(res) + cout << "true" << endl; + else + cout << "false" << endl; + return 0; +} diff --git a/Week 07/id_536/leetcode_338_536.cpp b/Week 07/id_536/leetcode_338_536.cpp new file mode 100644 index 000000000..ab07fe6df --- /dev/null +++ b/Week 07/id_536/leetcode_338_536.cpp @@ -0,0 +1,57 @@ +#include +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1̬滮 + 1״̬P(x)xɶƺ1ĸ + 2״̬̣P(x) = P(x/2) + x%2; + 3ʼP(0) = 0; + ʱ临ӶȣO(n) + ռ临ӶȣO(n) + ******/ + vector helper1(int num) { + vector res(num+1); + res[0] = 0; + for(int i = 1; i <= num; ++ i) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } + + /***** + ⷨ2̬滮 + 1״̬P(x)xɶƺ1ĸ + 2״̬̣P(x) = P(x&(x-1)) + 1; + 3ʼP(0) = 0; + ʱ临ӶȣO(n) + ռ临ӶȣO(n) + ******/ + vector helper2(int num) { + vector res(num+1); + res[0] = 0; + for(int i = 1; i <= num; ++ i) { + res[i] = res[i & (i-1)] + 1; + } + return res; + } + + vector countBits(int num) { + vector res; + //res = helper1(num); + res = helper2(num); + return res; + } +}; + +int main() +{ + Solution s; + vector res = s.countBits(5); + for(int i = 0; i< res.size(); ++ i) + cout << res[i]; + return 0; +} diff --git a/Week 07/id_546/LeetCode_242_546.cs b/Week 07/id_546/LeetCode_242_546.cs new file mode 100644 index 000000000..13d146fe3 --- /dev/null +++ b/Week 07/id_546/LeetCode_242_546.cs @@ -0,0 +1,71 @@ +using System; +using System.Linq; + +namespace Easy +{ + /// + /// 242. 有效的字母异位词 + /// + public class ValidAnagram + { + //字母异位词: + //一边单词字母出现的频率等于另一边单词出现的频率但字母位置可以不一样 + //两边单词个数不同肯定为 false + + /// + /// 解法一:暴力解法 + /// + /// + /// + /// + public static bool IsAnagram(String s, String t) + { + if (s.Length != t.Length) + { + return false; + } + + var arrA = s.ToCharArray(); + var arrB = t.ToCharArray(); + + Array.Sort(arrA); + Array.Sort(arrB); + + //使用SequenceEqual比较值 + return arrA.SequenceEqual(arrB); + + //错误的比较数组值,Equals来自于Object的比较,而不是单纯的值比较 + //var error = arrA.Equals(arrB); + } + + /// + /// 解法二:使用字符小标,hash存储 + /// + /// + /// + /// + public static bool IsAnagram2(String s, String t) + { + if (s.Length != t.Length) + { + return false; + } + + int[] alphabet = new int[26]; + for (int i = 0; i < s.Length; i++) + { + alphabet[s[i] - 'a']++; + alphabet[t[i] - 'a']--; + } + return !alphabet.Any(i => i != 0); + } + + public static void Run() + { + + + bool b = IsAnagram("anagram", "nagaram"); + Console.WriteLine(b); + } + } +} \ No newline at end of file diff --git a/Week 07/id_546/LeetCode_338_546.cs b/Week 07/id_546/LeetCode_338_546.cs new file mode 100644 index 000000000..f94ef1ac9 --- /dev/null +++ b/Week 07/id_546/LeetCode_338_546.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Medium +{ + /// + /// 338. 比特位计数 + /// + public class CountingBits + { + public int[] CountBits(int num) + { + + int[] bits = new int[num + 1]; + + for (int i = 1; i <= num; i++) + { + + bits[i] += bits[(i & (i - 1))] +1; + } + return bits; + } + } +} diff --git a/Week 07/id_546/LeetCode_52_546.cs b/Week 07/id_546/LeetCode_52_546.cs new file mode 100644 index 000000000..1040b05f0 --- /dev/null +++ b/Week 07/id_546/LeetCode_52_546.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hard +{ + /// + /// 52. N皇后 II + /// + public class NQueensII + { + private int size; + private int count; + private void Solve(int row, int ld, int rd) + { + if (row == size) + { + count++; + return; + } + int pos = size & (~(row | ld | rd)); + while (pos != 0) + { + int p = pos & (-pos); + pos -= p; // pos &= pos - 1; + Solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + public int TotalNQueens(int n) + { + count = 0; + size = (1 << n) - 1; + Solve(0, 0, 0); + return count; + } + + } + +} diff --git a/Week 07/id_551/LeetCode_1122_551.py b/Week 07/id_551/LeetCode_1122_551.py new file mode 100644 index 000000000..a79302b40 --- /dev/null +++ b/Week 07/id_551/LeetCode_1122_551.py @@ -0,0 +1,21 @@ +class Solution(object): + def relativeSortArray(self, arr1, arr2): + """ + :type arr1: List[int] + :type arr2: List[int] + :rtype: List[int] + """ + ans = [ 0 for _ in range(1001) ] + result = [] + for i in range(len(arr1)): + ans[arr1[i]] += 1 + for j in range(len(arr2)): + while ans[arr2[j]] > 0: + result.append(arr2[j]) + ans[arr2[j]] -= 1 + + for k in range(len(ans)): + while ans[k] > 0: + result.append(k) + ans[k] -= 1 + return result diff --git a/Week 07/id_551/LeetCode_242_551.py b/Week 07/id_551/LeetCode_242_551.py new file mode 100644 index 000000000..b394d025b --- /dev/null +++ b/Week 07/id_551/LeetCode_242_551.py @@ -0,0 +1,18 @@ +class Solution(object): + def isAnagram(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + s = [i for i in s] + t = [i for i in t] + s.sort() + t.sort() + if len(s) != len(t): + return False + for i in range(len(s)): + if s[i] != t[i]: + return False + return True + diff --git a/Week 07/id_556/LeetCode_190_556.py b/Week 07/id_556/LeetCode_190_556.py new file mode 100644 index 000000000..4be2f3b69 --- /dev/null +++ b/Week 07/id_556/LeetCode_190_556.py @@ -0,0 +1,6 @@ +class Solution: + def reverseBits(self, n: int) -> int: + res = bin(n)[2:] + res = res.zfill(32) + res = res[::-1] [::-1]代表从后向前取值,每次步进值为1 + return int(res, base=2) \ No newline at end of file diff --git a/Week 07/id_556/LeetCode_191_556.py b/Week 07/id_556/LeetCode_191_556.py new file mode 100644 index 000000000..fc4d68eec --- /dev/null +++ b/Week 07/id_556/LeetCode_191_556.py @@ -0,0 +1,3 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + return bin(n).count('1') \ No newline at end of file diff --git a/Week 07/id_556/LeetCode_231_556.py b/Week 07/id_556/LeetCode_231_556.py new file mode 100644 index 000000000..2d904e0d8 --- /dev/null +++ b/Week 07/id_556/LeetCode_231_556.py @@ -0,0 +1,3 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return (n > 0) and bin(n).count('1')==1 \ No newline at end of file diff --git a/Week 07/id_556/NOTE.md b/Week 07/id_556/NOTE.md index a6321d6e2..ef5b69ac6 100644 --- a/Week 07/id_556/NOTE.md +++ b/Week 07/id_556/NOTE.md @@ -2,3 +2,112 @@ +## Bit Operation + +位运算:直接对整数在内存中的二进制位进行操作,处理速度很快 + +一元运算符: + +- 左移 << +- 右移 >> +(新位补0,老位去除) +- 按位取反 ~ + +二元运算符: +- 按位或 |(有1则1) +- 按位与 &(有0则0) +- 按位异或 ^ (同0异1) + +应用: + +``` +1. 交换两数: +c=a^b +a^c=b +b^c=a + +2. x右边n位清零:x&(~0<>n) & 1 + +4. 获取x第n位的幂值:x&(1<<(n-1)) + +5. 将第n位置为1:x!(1<>1 + +11. 将**最低位的1**变为0:x&(x-1) + +12. 只保留最低的1:x&-x + +> 计算机运算中采用补码表示负数,因此-x是x取反再加1 +``` + + +## Bloom Filter + +HashTable+链式存储:存储全部数据到内存空间 + +如果只需要一个判断是否在集合中的数据结构,则不需要存储数据本身。因此设计了Bloom Filter,用一个很长的二进制向量和一系列随机映射函数将元素对应到多个二进制位中,可以很高效地判断一个元素是否在一个集合中。它的空间效率和查询时间远超一般算法,但存在一定的误识别率,且删除困难。 + +查询测试元素时,只要有一位为0,则一定不在;但全为1,不一定在(因此Filter常用于快速查询的缓存,相当于在不存在时剪枝后续操作)。 + + +## LRU Cache + +采用的缓存替换策略:最近最少使用(Least Recently Use,即最新的元素放到最前),通常使用HashTable + DoubleEnd LinkedList实现,具有O(1)的查询、修改、更新效率 + +### 排序算法 + +1. 比较类排序:时间复杂度不能突破O(nlogn): +- 交换:冒泡,快速 +- 插入:简单插入、希尔 +- 选择:简单选择、堆排序 +- 归并:二路、多路 + +2. 非比较类排序:不通过比较来确定元素前后次序,可以突破下界,以线性时间完成 +- 计数排序 +- 桶排序 +- 基数排序 + +> 准备面试时,重点看O(nlogn)的排序:快速、桶排、归并 + +初级排序O(n^2): +- Selection sort + - 每次选择最小值放到数组起始位置 + - 找剩余元素最小值O(n),需要找n次 + +- Insertion sort: + - 对于未排序数据,在已排序列中从后往前扫描找位置插入,保持前子序列为有序(从前到后逐步构建) + - 寻找插入位置O(n),内层循环挪动O(n) +- Bubble sort: + - 嵌套循环,每次查看相邻元素,如果逆序则交换 + - 循环一次可以冒好一个元素 + +高级排序O(nlong) +- 快速排序 + - 使用分治法,递归地把小于基准值元素的子数列和大于基准值元素的子数列排序 + - 数组取标杆pivot(中间、左右均可),将小(大)于pivot的元素都放在pivot左(右)边,依次递归对左右子数组进行快速排序 + +- 归并排序 + - 采用分治法,把长度为n的输入序列分成两个长度为n/2的子序列; + - 对这两个子序列分别采用归并排序;将两个排序好的子序列合并成一个最终的排序序列 + +- 堆排序 + - 堆是一颗每个结点的值都大于等于或小于等于其左右孩子结点值的完全二叉树,存储为数组,从1开始存储数据,i的左子节点为2*i,右子节点为2*i+1 + - 将元素组织为最大或最小堆(O(n)),将堆顶元素与堆数组的末尾元素进行交换,递归地调整堆(O(logn)),将堆顶元素再与末尾元素进行交换 + - 将元素取出,得到有序序列 + - 插入/删除O(nlogn),取最值O(1) + +特殊排序O(n) +- 计数排序 +- 桶排序 +- 基数排序 \ No newline at end of file diff --git a/Week 07/id_556/SortFuntions.py b/Week 07/id_556/SortFuntions.py new file mode 100644 index 000000000..c73ef1924 --- /dev/null +++ b/Week 07/id_556/SortFuntions.py @@ -0,0 +1,198 @@ +import random +from collections import deque + + +def bubble_sort(arr): + length = len(arr) + for i in range(length - 1): + for j in range(length - 1 - i): + if arr[j] > arr[j + 1]: + arr[j], arr[j + 1] = arr[j + 1], arr[j] + return arr + + +def selection_sort(arr): + length = len(arr) + for i in range(length - 1): + min_index = i + for j in range(i + 1, length): + if arr[j] < arr[min_index]: + min_index = j + arr[i], arr[min_index] = arr[min_index], arr[i] + return arr + + +def insertion_sort(arr): + length = len(arr) + for i in range(1, length): + pre_index = i - 1 + current = arr[i] + while pre_index >= 0 and arr[pre_index] > current: + arr[pre_index + 1] = arr[pre_index] + pre_index -= 1 + arr[pre_index + 1] = current + return arr + + +def merge_sort(arr): + length = len(arr) + if length < 2: + return arr + mid = length >> 1 + left = arr[:mid] + right = arr[mid:] + return merge(merge_sort(left), merge_sort(right)) + + +def merge(left, right): + res = [] + while len(left) > 0 and len(right) > 0: + # while left and right: + res.append(left.pop(0) if left[0] < right[0] else right.pop(0)) + res = res + left + right + return res + + +def merge_sort2(arr, l, r): + if l < r: + mid = l + ((r - l) >> 1) + merge_sort2(arr, l, mid) + merge_sort2(arr, mid + 1, r) + merge2(arr, l, mid, r) + return arr + + +def merge2(arr, l, mid, r): + temp = [0] * (r - l + 1) + i = l + j = mid + 1 + k = 0 + while i <= mid and j <= r: + if arr[i] < arr[j]: + temp[k] = arr[i] + i += 1 + else: + temp[k] = arr[j] + j += 1 + k += 1 + while i <= mid: + temp[k] = arr[i] + i += 1 + k += 1 + while j <= r: + temp[k] = arr[j] + j += 1 + k += 1 + for i in range(len(temp)): + arr[l + i] = temp[i] + + +def merge_sort_in_place(arr, l, r): + if l < r: + mid = l + ((r - l) >> 1) + merge_sort_in_place(arr, l, mid) + merge_sort_in_place(arr, mid + 1, r) + merge_in_place(arr, l, mid, r) + return arr + + +def merge_in_place(arr, l, mid, r): + left = arr[l:mid + 1] + right = arr[mid + 1:r + 1] + k = l + while left and right: + arr[k] = left.pop(0) if left[0] < right[0] else right.pop(0) + k += 1 + tail = left if left else right + for n in tail: + arr[k] = n + k += 1 + + +def quick_sort(arr, l, r): + if l < r: + i, j = l, r + pivot = arr[l] + while i != j: + while j > i and arr[j] > pivot: + j -= 1 + if j > i: + arr[i] = arr[j] + i += 1 + while i < j and arr[i] < pivot: + i += 1 + if i < j: + arr[j] = arr[i] + j -= 1 + arr[i] = pivot + quick_sort(arr, l, i - 1) + quick_sort(arr, i + 1, r) + return arr + + +def quick_sort2(arr, l, r): + if l >= r: + return arr + pivot = partition(arr, l, r) + quick_sort(arr, l, pivot - 1) + quick_sort(arr, pivot + 1, r) + return arr + + +def partition(arr, l, r): + pivot = r + counter = l + for i in range(l, r): + if arr[i] < arr[pivot]: + arr[counter], arr[i] = arr[i], arr[counter] + counter += 1 + arr[pivot], arr[counter] = arr[counter], arr[pivot] + return counter + + +def heap_sort(arr): + # index start from 1 + heap = deque(arr) + heap.appendleft(0) + + length = len(heap) - 1 + # the last node with children + last_non_left = length >> 1 + for i in range(last_non_left): + heapify(heap, last_non_left - i, length) + + for i in range(length - 1): + heap[1], heap[length - i] = heap[length - i], heap[1] + heapify(heap, 1, length - i - 1) + + return [heap[i] for i in range(1, len(heap))] + + +def heapify(heap, start, end): + tmp = heap[start] + i = start + j = i * 2 + + while j <= end: + if j < end and heap[j] < heap[j + 1]: + j += 1 + if tmp < heap[j]: + heap[i] = heap[j] + i = j + j = i * 2 + else: + break + heap[i] = tmp + + +if __name__ == "__main__": + arr = [random.randint(-100, 100) for _ in range(10)] + # print(bubble_sort(arr)) + # print(selection_sort(arr)) + # print(insertion_sort(arr)) + # print(merge_sort(arr)) + # print(merge_sort_in_place(arr, 0, len(arr) - 1)) + # print(merge_sort2(arr, 0, len(arr) - 1)) + # print(quick_sort(arr, 0, len(arr) - 1)) + print(quick_sort2(arr, 0, len(arr) - 1)) + print(heap_sort(arr)) \ No newline at end of file diff --git a/Week 07/id_566/leetcode_146_566.php b/Week 07/id_566/leetcode_146_566.php new file mode 100644 index 000000000..d573e4e34 --- /dev/null +++ b/Week 07/id_566/leetcode_146_566.php @@ -0,0 +1,43 @@ +capacity = $capacity; + } + + function get($key) { + if(array_key_exists($key,$this->map)){ + unset($this->list[array_search($key,$this->list)]); + array_push($this->list,$key); + return $this->map[$key]; + }else{ + return -1; + } + } + + function put($key, $value) { + if(array_key_exists($key,$this->map)){ + unset($this->list[array_search($key,$this->list)]); + }else{ + if(count($this->list) == $this->capacity){ + $dkey = array_shift($this->list); + unset($this->map[$dkey]); + } + } + $this->map[$key] = $value; + array_push($this->list,$key); + } +} +?> \ No newline at end of file diff --git a/Week 07/id_566/leetcode_191_566.php b/Week 07/id_566/leetcode_191_566.php new file mode 100644 index 000000000..fcd8e9763 --- /dev/null +++ b/Week 07/id_566/leetcode_191_566.php @@ -0,0 +1,25 @@ + 0) { + $count += $n & 1; + $n = $n >> 1; + } + + return $count; + } +} +?> \ No newline at end of file diff --git a/Week 07/id_571/leetcode_191_571.js b/Week 07/id_571/leetcode_191_571.js new file mode 100644 index 000000000..152ed8d7a --- /dev/null +++ b/Week 07/id_571/leetcode_191_571.js @@ -0,0 +1,25 @@ +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let count = 0; + while (n !== 0) { + count++; + n = n & (n - 1); + } + return count; +}; + +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let count = 0; + while (n !== 0) { + count += (n & 1) + n = n >>> 1 + } + return count; +}; \ No newline at end of file diff --git a/Week 07/id_571/leetcode_231_571.js b/Week 07/id_571/leetcode_231_571.js new file mode 100644 index 000000000..b1ada6d6e --- /dev/null +++ b/Week 07/id_571/leetcode_231_571.js @@ -0,0 +1,10 @@ +/** + * @param {number} n + * @return {boolean} + */ +var isPowerOfTwo = function(n) { + let helper = n & (n - 1); + return n > 0 && helper === 0; +}; + +isPowerOfTwo(2); diff --git a/Week 07/id_576/LeetCode_190_576.java b/Week 07/id_576/LeetCode_190_576.java new file mode 100644 index 000000000..50d64e5b5 --- /dev/null +++ b/Week 07/id_576/LeetCode_190_576.java @@ -0,0 +1,20 @@ +/** + * LeetCode_190_576 + */ +public class LeetCode_190_576 { + + public int reverseBits(int n) { + int res = 0; + for (int i = 0; i < 32; i++) { + // 由低到高位逐个取出 + int tmp = n >> i; + // 取有效位 + tmp = tmp & 1; + // 通过位运算将其放置到反转后的位置 + tmp = tmp << (31 - i); + // 将上述结果再次结合到一起 + res |= tmp; + } + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_576/LeetCode_338_576.java b/Week 07/id_576/LeetCode_338_576.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 07/id_576/LeetCode_52_576.java b/Week 07/id_576/LeetCode_52_576.java new file mode 100644 index 000000000..bf76df713 --- /dev/null +++ b/Week 07/id_576/LeetCode_52_576.java @@ -0,0 +1,36 @@ +/** + * LeetCode_52_576 + */ +public class LeetCode_52_576 { + private int size; + private int count; + + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + solve(0, 0, 0); + return count; + } + + private void solve(int row, int ld, int rd) { + if (row == size) { + count++; + System.out.println("count = " + count); + return; + } + int pos = size & (~(row | ld | rd)); + while (pos != 0) { + int p = pos & (-pos); //取到最低位的1 + pos -= p; // pos &= pos - 1,表示在pos位置放皇后 + System.out.println("row = "+ Integer.toBinaryString(row) + " "+ "pos = " + Integer.toBinaryString(pos)); + solve(row | p, (ld | p) << 1, (rd | p) >> 1); + } + } + + public static void main(String[] args) { + LeetCode_52_576 lc = new LeetCode_52_576(); + System.out.println("solution:" + lc.totalNQueens(4)); + + } + +} \ No newline at end of file diff --git a/Week 07/id_586/leetcode_1122.cc b/Week 07/id_586/leetcode_1122.cc new file mode 100644 index 000000000..c1feab5b7 --- /dev/null +++ b/Week 07/id_586/leetcode_1122.cc @@ -0,0 +1,26 @@ +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_map m; + for(auto it : arr1) + m[it]++; + + vector res; + for(auto it : arr2){ + while(m[it]){ + res.push_back(it); + m[it]--; + } + } + vector temp; + for(auto it : m){ + int x = it.second; + while(x) + temp.push_back(it.first), x--; + } + sort(temp.begin(), temp.end()); + for(auto it : temp) + res.push_back(it); + return res; + } +}; diff --git a/Week 07/id_586/leetcode_231.cc b/Week 07/id_586/leetcode_231.cc new file mode 100644 index 000000000..bcdd7cb45 --- /dev/null +++ b/Week 07/id_586/leetcode_231.cc @@ -0,0 +1,6 @@ +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +}; diff --git a/Week 07/id_586/leetcode_56.cc b/Week 07/id_586/leetcode_56.cc new file mode 100644 index 000000000..90ab24f1d --- /dev/null +++ b/Week 07/id_586/leetcode_56.cc @@ -0,0 +1,25 @@ +class Solution { +public: + static bool comparator(const vector& first, const vector& second){ + if (first[0] == second[0]) + return first[1] < second[1]; + return first[0] < second[0]; + } + vector> merge(vector>& intervals) { + int index1, index2; + sort (intervals.begin(), intervals.end(), comparator); + + for (index1 = 0; index1 < intervals.size(); index1++ ) { + for (index2 = index1 + 1; index2 < intervals.size(); index2++) { + if (intervals[index2].front() <= intervals[index1].back()) { + intervals[index1].back() = max(intervals[index1].back(), intervals[index2].back()); + } + else + break; + } + intervals.erase(intervals.begin() + index1 + 1, intervals.begin() + index2); + } + + return intervals; + } +}; diff --git a/Week 07/id_591/LeetCode_242_591.js b/Week 07/id_591/LeetCode_242_591.js new file mode 100644 index 000000000..500def9c5 --- /dev/null +++ b/Week 07/id_591/LeetCode_242_591.js @@ -0,0 +1,33 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +/* +var isAnagram = function(s, t) { + s = s.split("").sort().join(""); + t = t.split("").sort().join(""); + return s == t; +}; +*/ +let isAnagram = function(s, t) { + if(s.length != t.length){ + return false; + } + let counter = []; + for (let i = 0; i < 26; i++) { + counter[i] = 0; + } + for(let i = 0; i< s.length; i++){ + counter[s[i].charCodeAt() - 97]++; + } + + for(let i = 0; i< t.length; i++){ + counter[t[i].charCodeAt() - 97]-- + if(counter[t[i].charCodeAt() - 97] < 0){ + return false; + } + } + return true; + }; + \ No newline at end of file diff --git a/Week 07/id_591/LeetCode_338_591.js b/Week 07/id_591/LeetCode_338_591.js new file mode 100644 index 000000000..e05be73e6 --- /dev/null +++ b/Week 07/id_591/LeetCode_338_591.js @@ -0,0 +1,21 @@ +/** + * @param {number} num + * @return {number[]} + */ +var countBits = function(num) { + let ans = []; + for (let i = 0; i <= num; ++i){ + ans[i] = popcount(i); + } + return ans; +}; + +let popcount = function(num){ + let count = 0; + while(num != 0){ + num = num & (num-1); + count++; + } + return count; +} + diff --git a/Week 07/id_591/NOTE.md b/Week 07/id_591/NOTE.md index a6321d6e2..1972df5f9 100644 --- a/Week 07/id_591/NOTE.md +++ b/Week 07/id_591/NOTE.md @@ -1,4 +1,56 @@ -# NOTE +# 学习总结 +## 1、位运算 +### 1.1、判断奇偶: +x % 2 == 1 —> (x & 1) == 1 +x % 2 == 0 —> (x & 1) == 0 +### 1.2、右移1位等于除2 +即: x = x / 2; —> x = x >> 1; + > mid = (left + right) / 2; —> mid = (left + right) >> 1; + +### 1.3、清零最低位1 +X = X & (X-1) 清零最低位的 1 + +### 1.4、得到最低位1 +X & -X => 得到最低位的 1 + +### 1.5、清零 +X & ~X => 0 + +## 2、布隆过滤器 +### 2.1、定义 +一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 + +### 2.2、主要特点: +优点是空间效率和查询时间都远远超过一般的算法, +缺点是有一定的误识别率和删除困难。 + +### 2.3、应用场景 +1. 比特币网络 +2. 分布式系统(Map-Reduce) — Hadoop、search engine +3. Redis 缓存 +4. 垃圾邮件、评论等的过滤 + +## 3、排序算法 +### 3.1、比较类排序: +通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。 +> 交换排序:冒泡排序、快速排序 + +> 插入排序:简单插入排序、希尔排序 + +> 选择排序:简单选择排序、插入排序 + +> 归并排序:二路归并排序、多路归并排序 + + +### 3.2、非比较类排序: +不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时 +间下界,以线性时间运行,因此也称为线性时间非比较类排序。 +> 计数排序、桶排序、基数排序 + +## 参考资料 +- https://www.cnblogs.com/onepixel/p/7674659.html +- https://www.bilibili.com/video/av25136272 +- https://www.bilibili.com/video/av63851336 diff --git a/Week 07/id_596/LeetCode_1122_596.py b/Week 07/id_596/LeetCode_1122_596.py new file mode 100644 index 000000000..40a6f3b5e --- /dev/null +++ b/Week 07/id_596/LeetCode_1122_596.py @@ -0,0 +1,16 @@ +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + count = [0] * 1001 + answer = [] + for i in range(len(arr1)): + count[arr1[i]] += 1 + for i in range(len(arr2)): + while count[arr2[i]] > 0: + answer.append(arr2[i]) + count[arr2[i]] -= 1 + for i in range(1001): + while count[i] > 0: + answer.append(i) + count[i] -= 1 + + return answer \ No newline at end of file diff --git a/Week 07/id_596/LeetCode_190_596.py b/Week 07/id_596/LeetCode_190_596.py new file mode 100644 index 000000000..ea9d08aaf --- /dev/null +++ b/Week 07/id_596/LeetCode_190_596.py @@ -0,0 +1,8 @@ +class Solution: + def reverseBits(self, n: int) -> int: + result = 0 + for i in range(32): + result <<= 1 + result += n & 1 + n >>= 1 + return result \ No newline at end of file diff --git a/Week 07/id_596/LeetCode_191_596.py b/Week 07/id_596/LeetCode_191_596.py new file mode 100644 index 000000000..7c315024d --- /dev/null +++ b/Week 07/id_596/LeetCode_191_596.py @@ -0,0 +1,7 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n != 0: + n = n & (n-1) + count += 1 + return count \ No newline at end of file diff --git a/Week 07/id_596/NOTE.md b/Week 07/id_596/NOTE.md index a6321d6e2..1dfdf3ce1 100644 --- a/Week 07/id_596/NOTE.md +++ b/Week 07/id_596/NOTE.md @@ -1,4 +1,101 @@ -# NOTE +# 学习笔记 - +## 位运算 +### 指定位置的位运算 + +1. 将x最右边的n位清零:x & (~0 << n) +2. 获取x的第n位值(0或者1):(x >> n) & 1 +3. 获取x的第n位的幂值:x & (1<<(n-1)) +4. 仅将第n位置为1:x | (1 << n) +5. 仅将第n位置为0:x & (~(1 << n )) +6. 将 x 最高位至第n位(含)清零:x & ((1 << n) - 1) +7. 将第n位至第0位(含)清零:x & (~((1 << (n+1)) - 1)) + +### 实战位运算要点 + +#### 判断奇偶 + +x % 2 == 1 → (x & 1) == 1 + +x % 2 == 0 → (x & 1) == 0 + +#### 除2操作 + +x / 2 → x >> 1 + +即: x = x / 2; → x = x >> 1 + +mid = (left + right)/2; → (left + right) >> 1; + +#### 清零最低位的1 + +x = x & (x - 1) + +#### 得到最低位的1 + +x & -x + +#### 与自身的取反异或得0 + +x & ~x ⇒ 0 + +## 布隆过滤 + +### Bloom Filter vs Hash Table + +一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 +优点是空间效率和查询时间都远远超过一般算法,缺点是有一定的误识别率和删除困难。 + +布隆过滤判断一个元素不在则不在,如果判断在的话则不一定在,需要进一步查询确认。 +布隆过滤是作为一个外部的缓存使用的。 + +## LRU Cache + +- 两个要素:大小、替换策略 +- HashTable + Double LinkedList +- O(1)查询 + O(1)修改、更新 + +## 排序算法 + +1. 比较类排序: + 通过比较来决定元算间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 + +2. 非比较类排序: + 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 + +### 初级排序 - O(n^2) + +1. 选择排序 (Selection Sort) + + 每次找最小值,然后放到待排序数组的起始位置。 + +2. 插入排序 (Insertion Sort) + + 从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 + +3. 冒泡排序 (Bubble Sort) + + 嵌套循环,每次查看相邻的元素如果逆序,则交换。 + +### 高级排序 - O(N*LogN) + +- 快速排序 + + 数组去标杆pivot,将小元素放pivot左边,大元素放右侧,然后依次对左边和右边的子数组继续快排;以达到整个序列有序。 + +- 归并排序 (Merge Sort) - 分治排序 + 1. 把长度为n的输入序列分成两个长度为n/2的子序列; + 2. 对这两个子序列分别采用归并排序; + 3. 将两个排序好的子序列合并成一个最终的排序序列。 + +归并和快排具有相似性,但步骤相反 + +归并:先排序左右子数组,然后合并两个有序子数组 + +快排:先调配出左右子数组,然后对于左右子数组进行排序 + +- 堆排序 (Heap Sort) - 堆插入O(logN),取最大/最小值 O(1) + 1. 数组元素依次建立小顶堆 + 2. 依次取堆顶元素,并删除 \ No newline at end of file diff --git a/Week 07/id_601/LeetCode_1122_601.java b/Week 07/id_601/LeetCode_1122_601.java new file mode 100644 index 000000000..c747d2e38 --- /dev/null +++ b/Week 07/id_601/LeetCode_1122_601.java @@ -0,0 +1,36 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int c = 0; + int temp = 0; + + for (int i=0;i() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] - o2[0]; + } + }); + + // 开一个辅助结构存放结果 + List list = new ArrayList<>(); + + // 这里从1开始遍历 + for (int i = 1; i < intervals.length; i++) { + // 每次取出2个数组进行比较 + int[] one = intervals[i-1]; + int[] two = intervals[i]; + + // 如果头尾无重合,说明前一个数组与后面的数组不会产生任何重合(排序保证) + if (two[0] > one[1]) { + list.add(one); + } + // 如果存在重合,第二个数组吸收第一个数组 + else if (two[0] <= one[1]) { + two[0] = one[0]; + two[1] = Math.max(one[1], two[1]); + } + // 别忘记最后一个数组 + if (i == intervals.length - 1) { + list.add(two); + } + } + + return list.toArray(new int[0][]); + } +} diff --git "a/Week 07/id_606/1122.\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.java" "b/Week 07/id_606/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 000000000..6432c043f --- /dev/null +++ "b/Week 07/id_606/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,76 @@ +/* + * @lc app=leetcode.cn id=1122 lang=java + * + * [1122] 数组的相对排序 + * + * https://leetcode-cn.com/problems/relative-sort-array/description/ + * + * algorithms + * Easy (63.73%) + * Likes: 21 + * Dislikes: 0 + * Total Accepted: 7.3K + * Total Submissions: 11.4K + * Testcase Example: '[2,3,1,3,2,4,6,7,9,2,19]\n[2,1,4,3,9,6]' + * + * 给你两个数组,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] + * + * + * + * + * 提示: + * + * + * arr1.length, arr2.length <= 1000 + * 0 <= arr1[i], arr2[i] <= 1000 + * arr2 中的元素 arr2[i] 各不相同 + * arr2 中的每个元素 arr2[i] 都出现在 arr1 中 + * + * + */ + +// @lc code=start +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] m = new int[1001]; + + int[] ref = new int[arr1.length]; + + for (int i = 0; i < arr1.length; i++) { + m[arr1[i]]++; + } + + int cnt = 0; + for (int i = 0; i < arr2.length; i++) { + while (m[arr2[i]] > 0) { + ref[cnt++] = arr2[i]; + m[arr2[i]]--; + } + } + + for (int i = 0; i < 1001; i++) { + while (m[i] > 0) { + ref[cnt++] = i; + m[i]--; + } + } + return ref; + + } +} +// @lc code=end diff --git "a/Week 07/id_606/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.java" "b/Week 07/id_606/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.java" new file mode 100644 index 000000000..2e24b6efc --- /dev/null +++ "b/Week 07/id_606/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.java" @@ -0,0 +1,73 @@ +/* + * @lc app=leetcode.cn id=191 lang=java + * + * [191] 位1的个数 + * + * https://leetcode-cn.com/problems/number-of-1-bits/description/ + * + * algorithms + * Easy (60.18%) + * Likes: 109 + * Dislikes: 0 + * Total Accepted: 37.4K + * Total Submissions: 60.6K + * Testcase Example: '00000000000000000000000000001011' + * + * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + * + * + * + * 示例 1: + * + * 输入:00000000000000000000000000001011 + * 输出:3 + * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 + * + * + * 示例 2: + * + * 输入:00000000000000000000000010000000 + * 输出:1 + * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 + * + * + * 示例 3: + * + * 输入:11111111111111111111111111111101 + * 输出:31 + * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 + * + * + * + * 提示: + * + * + * 请注意,在某些语言(如 + * Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 + * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 + * + * + * + * + * 进阶: + * 如果多次调用这个函数,你将如何优化你的算法? + * + */ + +// @lc code=start +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + + } +} +// @lc code=end diff --git "a/Week 07/id_606/231.2-\347\232\204\345\271\202.java" "b/Week 07/id_606/231.2-\347\232\204\345\271\202.java" new file mode 100644 index 000000000..d589f587b --- /dev/null +++ "b/Week 07/id_606/231.2-\347\232\204\345\271\202.java" @@ -0,0 +1,44 @@ +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + * + * https://leetcode-cn.com/problems/power-of-two/description/ + * + * algorithms + * Easy (46.90%) + * Likes: 143 + * Dislikes: 0 + * Total Accepted: 37.5K + * Total Submissions: 79.7K + * Testcase Example: '1' + * + * 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + * + * 示例 1: + * + * 输入: 1 + * 输出: true + * 解释: 2^0 = 1 + * + * 示例 2: + * + * 输入: 16 + * 输出: true + * 解释: 2^4 = 16 + * + * 示例 3: + * + * 输入: 218 + * 输出: false + * + */ + +// @lc code=start +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} +// @lc code=end + diff --git a/Week 07/id_611/LeetCode_1122_611.java b/Week 07/id_611/LeetCode_1122_611.java new file mode 100644 index 000000000..1aa4f1e3c --- /dev/null +++ b/Week 07/id_611/LeetCode_1122_611.java @@ -0,0 +1,30 @@ +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] m = new int[1001]; + + int[] ref = new int[arr1.length]; + //记录arr1数据个数 + for(int i = 0; i < arr1.length; i++) { + m[arr1[i]]++; + } + + //重新构建新数组 + int cnt = 0; + for(int i = 0; i < arr2.length; i++) { + while(m[arr2[i]] > 0) { + ref[cnt++] = arr2[i]; + m[arr2[i]]--; + } + } + + //增加arr2中未出现到arr1的末尾 + for(int i = 0; i < 1001; i++) { + while(m[i] > 0) { + ref[cnt++] = i; + m[i]--; + } + } + return ref; + } + +} \ No newline at end of file diff --git a/Week 07/id_611/LeetCode_56_611.java b/Week 07/id_611/LeetCode_56_611.java new file mode 100644 index 000000000..f785de840 --- /dev/null +++ b/Week 07/id_611/LeetCode_56_611.java @@ -0,0 +1,33 @@ +class Solution { + + public int[][] merge(int[][] intervals) { + List res = new ArrayList<>(); + if (intervals == null || intervals.length == 0) + return res.toArray(new int[0][]); + + // Arrays.sort(intervals, (a, b) -> a[0] - b[0]);// a[0] - b[0]大于0就交换顺序 + // 根据二维数组第一个数字大小按每一行整体排序 + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + // TODO Auto-generated method stub + return o1[0] - o2[0]; + } + }); + int i = 0; + while (i < intervals.length) { + int left = intervals[i][0]; + int right = intervals[i][1]; + // i不能到最后一行,所以要小于(数组的长度 - 1) + // 判断所在行的right和下一行的left大小,对right重新进行赋最大值 + while (i < intervals.length - 1 && right >= intervals[i + 1][0]) { + i++; + right = Math.max(right, intervals[i][1]); + } + res.add(new int[] { left, right }); + i++; + } + return res.toArray(new int[0][]); + } + +} \ No newline at end of file diff --git a/Week 07/id_616/LeetCode_146_616.cpp b/Week 07/id_616/LeetCode_146_616.cpp new file mode 100644 index 000000000..eef650b08 --- /dev/null +++ b/Week 07/id_616/LeetCode_146_616.cpp @@ -0,0 +1,49 @@ +class LRUCache { +public: + LRUCache(int capacity) { + capacity_ = capacity; + } + + int get(int key) { + auto it = map_.find(key); + if(map_.end() == it) + return -1; + + pair kv = *map_[key]; + list_.erase(map_[key]); + list_.push_front(kv); + map_[key] = list_.begin(); + return kv.second; + } + + void put(int key, int value) { + auto it = map_.find(key); + if(it == map_.end()){ + if(list_.size() == capacity_){ + auto last = list_.back(); + map_.erase(last.first); + list_.pop_back(); + } + + list_.push_front(make_pair(key,value)); + map_[key] = list_.begin(); + } else { + list_.erase(map_[key]); + list_.push_front(make_pair(key,value)); + map_[key] = list_.begin(); + } + + } + +private: + int capacity_; + list> list_; + map>::iterator> map_; +}; + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache* obj = new LRUCache(capacity); + * int param_1 = obj->get(key); + * obj->put(key,value); + */ \ No newline at end of file diff --git a/Week 07/id_616/LeetCode_190_616.cpp b/Week 07/id_616/LeetCode_190_616.cpp new file mode 100644 index 000000000..d2ea841dd --- /dev/null +++ b/Week 07/id_616/LeetCode_190_616.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + uint32_t t = 0; + uint32_t mask = 1; + for(int i = 0; i < 32; i++){ + if(n & mask) { + t = (t | (1 << (31 - i))); + } + mask <<= 1; + } + return t; + } +}; \ No newline at end of file diff --git a/Week 07/id_616/LeetCode_191_616.cpp b/Week 07/id_616/LeetCode_191_616.cpp new file mode 100644 index 000000000..7235c1446 --- /dev/null +++ b/Week 07/id_616/LeetCode_191_616.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + int hammingWeight(uint32_t n) { + int cnt = 0; + while(n) { + n = n & (n - 1); + cnt++; + } + return cnt; + } +}; \ No newline at end of file diff --git a/Week 07/id_616/LeetCode_231_616.cpp b/Week 07/id_616/LeetCode_231_616.cpp new file mode 100644 index 000000000..aee7b519c --- /dev/null +++ b/Week 07/id_616/LeetCode_231_616.cpp @@ -0,0 +1,6 @@ +class Solution { +public: + bool isPowerOfTwo(int n) { + return ((n > 0) && !(n & (n - 1))); + } +}; \ No newline at end of file diff --git a/Week 07/id_616/LeetCode_56_616.cpp b/Week 07/id_616/LeetCode_56_616.cpp new file mode 100644 index 000000000..014f2c4ae --- /dev/null +++ b/Week 07/id_616/LeetCode_56_616.cpp @@ -0,0 +1,25 @@ +class Solution { +public: + vector> merge(vector>& intervals) { + vector> res; + if(intervals.size() == 0) return res; + if(intervals.size() == 1) return intervals; + + sort(intervals.begin(), intervals.end(), [](vector i,vector j) { return (i[0] 0110 +- 右移:">>":0110 => 0011 + +2.位运算符 + +- “|”:按位或,0011,1011 => 1011 +- “ & ”:按位与,0011,1011 => 0011 +- “ ~ ”:按位取反,0011 => 1100 +- “ ^ ”:按位异或(相同为零、不同为一) + +常用^ + +- x ^ 0 = x +- x ^ 1s = ~x (注意 1s = ~) +- x ^ (~x) = 1s +- x ^ x = 0 +- c = a ^ b => a ^c = b,b ^c =a(交换两个数) +- a ^ b ^ c = a ^ (b ^ c) = (a ^ b)^c //associative + +3.指定位置的位运算 + +- 将x最右边的n位清零: x & (~0 << n) +- 获取x的第n位置(0 或者 1): (x >> n) & 1 +- 获取x的第n位的幂值: x & (1 << (n - 1)) +- 仅将第n位置为1: x | (1 << n) +- 仅将第n位置为0: x & (~(1 << n)) +- 将x最高位至第n位(含)清零: x & ((1 << n) - 1) +- 将第n位至第0位(含)清零: x & (~((1 << (n + 1)) -1)) + +4.实战常用 + +判断奇偶 + +- x % 2 == 1 —> (x & 1) == 1 +- x % 2 == 0 —> (x & 1) == 0 + +除二 + +- x >> 1 —> x / 2 + +清零最低位的 1 + +- X = X & (X-1) + +得到最低位的 1 + +- X & -X + +## 布隆过滤器 + +特点 + +- 优点是空间效率和查询时间都远远超过一般的算法 +- 缺点是有一定的误识别率(不能准确判定存在)和删除困难 +- 和哈希表的区别:不保存具体的值 + +## LRU + +- 两个要素:大小(缓存的大小,超过该大小,根据替换策略执行替换)、替换策略(超出大小的替换原则) +- 数据结构:Hash Table + Double LinkedList; +- 时间复杂度:查询-->O(1);修改、更新-->O(1) + +## 排序算法 + +初级排序 复杂度O(n^2) + +- 选择排序 +- 冒泡排序 +- 插入排序 + +高级排序 复杂度O(n logn) + +- 快速排序 +- 归并排序 diff --git a/Week 07/id_631/LeetCode_146_631.go b/Week 07/id_631/LeetCode_146_631.go new file mode 100644 index 000000000..7cc89a3bd --- /dev/null +++ b/Week 07/id_631/LeetCode_146_631.go @@ -0,0 +1,82 @@ +type Node struct { + Key int + Val int + Prev *Node + Next *Node +} + +//97.58% 58.89% +type LRUCache struct { + Capacity int + Cache map[int]*Node + Head *Node + Tail *Node +} + +func Constructor(capacity int) LRUCache { + return LRUCache{ + Capacity: capacity, + Cache: make(map[int]*Node), + } +} + +func (this *LRUCache) Get(key int) int { + node, ok := this.Cache[key] + if !ok { + return -1 + } + + if this.Tail == node { + return node.Val + } else if this.Head == node { + this.Head = node.Next + } else { + node.Prev.Next = node.Next + node.Next.Prev = node.Prev + } + + // 把node放到最后 + node.Prev = this.Tail + node.Next = nil + this.Tail.Next = node + this.Tail = node + return node.Val +} + + +func (this *LRUCache) Put(key int, value int) { + if this.Capacity <= 0 { + return + } + + // Get方法回自动把存在的值移动到最后 + if this.Get(key) != -1 { + this.Tail.Val = value + return + } + + node := &Node{Key: key, Val: value} + this.Cache[key] = node + if this.Head == nil { + this.Head = node + this.Tail = node + return + } + + node.Prev = this.Tail + this.Tail.Next = node + this.Tail = node + + /*为了减少重复代码 先执行map赋值了 所以这里要 - 1*/ + if len(this.Cache) - 1 == this.Capacity { + delete(this.Cache, this.Head.Key) + this.Head = this.Head.Next + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * obj := Constructor(capacity); + * param_1 := obj.Get(key); + * obj.Put(key,value); + */ \ No newline at end of file diff --git a/Week 07/id_631/LeetCode_191_631.go b/Week 07/id_631/LeetCode_191_631.go new file mode 100644 index 000000000..8493ec271 --- /dev/null +++ b/Week 07/id_631/LeetCode_191_631.go @@ -0,0 +1,9 @@ +func hammingWeight(num uint32) int { + count := 0 + for i := 0; i < 32; i++ { + if (num >> i) & 1 == 1 { + count++ + } + } + return count +} \ No newline at end of file diff --git a/Week 07/id_631/LeetCode_231_631.go b/Week 07/id_631/LeetCode_231_631.go new file mode 100644 index 000000000..9f54bc75c --- /dev/null +++ b/Week 07/id_631/LeetCode_231_631.go @@ -0,0 +1,12 @@ +func isPowerOfTwo(n int) bool { + if n < 0 { + return false; + } + count := 0 + for i := 0; i < 32; i++ { + if (n >> i) & 1 == 1 { + count++ + } + } + return count == 1 +} \ No newline at end of file diff --git a/Week 07/id_631/LeetCode_51_631.go b/Week 07/id_631/LeetCode_51_631.go new file mode 100644 index 000000000..75cad200f --- /dev/null +++ b/Week 07/id_631/LeetCode_51_631.go @@ -0,0 +1,57 @@ +var res [][]int + +//位运算实现 +// 98.31% 100% +func solveNQueens(n int) [][]string { + if n == 0 { + return nil + } + res = make([][]int, 0) + dfs([]int{}, n, 0, 0, 0) + return generateResult() +} + +func dfs(rows []int, n, cols, pies, nas int){ + //终止条件 + if len(rows) == n { + tmp := make([]int, n) + copy(tmp, rows) + res = append(res, tmp) + return + } + + ok:= (^(cols | pies | nas)) & ((1 << uint(n)) - 1) + for ok != 0 { + p := ok & (-ok) + col := 0 + s := (1 << uint(n - 1)) + for p & s == 0 { + col++ + s >>= 1 + } + dfs(append(rows, col), n, cols ^ p, (pies ^ p) << 1, (nas ^ p) >> 1) + ok ^= p + } +} + +func generateResult() (result [][]string) { + str := "" + for _, v := range res { + var s []string + n := len(v) + for _, val := range v { + str = "" + for i := 0; i < n; i++ { + if i == val { + str += "Q" + } else { + str += "." + } + } + s = append(s, str) + } + result = append(result, s) + } + + return +} diff --git a/Week 07/id_631/NOTE.md b/Week 07/id_631/NOTE.md index a6321d6e2..61eae800b 100644 --- a/Week 07/id_631/NOTE.md +++ b/Week 07/id_631/NOTE.md @@ -1,4 +1,62 @@ -# NOTE - - - +1. 位运算 + 1. 十进制和二进制相互转换 + 2. 位运算符操作 + 1. 左移 << 数字整个左移,空出来的地方补 0,0011 => 0110 + 2. 右移 >> 数字整个左移,空出来的地方补 0,0110 => 0011 + 3. 按位或 | 两个二进制数字,有一位是 1,或结果就是 1,0011 1011 => 1011 + 4. 按位与 & 两个二进制数字,有一位是 0,或结果就是 0,0011 1011 => 0011 + 5. 按位去反 ~ 0 变成 1,1变成0 0011 => 1100 + 6. 按位异或(相同为零,不同为一) ^ 两个二进制数字,同为相异就是 1,同为相同就是 0, 0011 1011 => 1000 + 3. 位运算实战 + 1. 判断奇偶 +x %2 == 1 等价 (x & 1) == 1 +x %2 == 0 等价 (x & 1) == 0 + 2. 除二 +x = x / 2 x = x >> 1 + 3. 清零最低位的1 +x = x & (x-1) + 4. 得到最低位的1 +x & -x +1. 布隆过滤器和 LRU 缓存 + 1. 布隆过滤器 Bloom Filter +一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中,如果在表示大概率在,如果一个元素不在就一定不在 +优点:空间效率和查询时间都远远超过一般算法 +缺点:是有一定的误识别率和删除困难 + 2. LRU Least Recently Used,最近最少使用 +实现方式:HashMap + 双向链表 DoubleLinkedList +缓存替换策略: + 1. FIFO(First In First Out 先进先出) + 2. LFU(Least Frequently Used 最不经常使用) + 3. OPT(Optimal Replacement ASlgorithm 最优替换) + 4. LRU-2 [2,3] (最近两次最少使用) + 5. ARC +3. 排序算法 + 1. 比较类排序 +通过比较来决定元素间的相对次序,由于时间复杂度不能突破O(nlogn),也成为非线性时间比较类排序 + 1. 交换排序 + 2. 冒泡排序 Bubble Sort +嵌套循环,每次查看相邻的元素如果逆序,则交换 + 3. 快速排序 Quick Sort +先取标杆 pivot,将小元素放 pivot 左边,大元素放右边,然后依次对右边和右边的子数组继续快排;达到整个序列有序 +时间复杂度(平均) O(nlogn) 时间复杂度(最坏) O(n²) 时间复杂度(最好) O(nlogn) 空间复杂度 O(nlogn) 稳定性 不稳定 + 4. 插入排序 Insertion Sort +从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入 + 5. 简单插入排序 +时间复杂度(平均)O(n²) 时间复杂度(最坏)O(n²) 时间复杂度(最好)O(n) 空间复杂度 O(1) 稳定性 稳定 + 6. 希尔排序 + 7. 选择排序 Selection Sort +每次找最小值,然后放到待排序数组的起始位置 + 8. 简单选择排序 + 9. 堆排序 + 10. 归并排序 Merge Sort 分治 +把长度为 n 的输入序列分成两个长度为 n/2 的子序列2. 对这两个子序列分别采用归并排序3.​​ 将两个排序好的子序列合并成一个最终的排序序列 + 11. 归并排序 +时间复杂度(平均)O(nlogn) 时间复杂度(最坏)O(nlogn) 时间复杂度(最好)O(nlogn) 空间复杂度 O(n) 稳定性 稳定 + 2. 非比较类排序 +不通过比较来决定元素间的相对次序,可以突破基于比较排序的时间下界,以线性时间运行,因此也成为线性时间非比较类排序(通常只能用于 int 数字排序) + 1. 计数排序 +时间复杂度(平均) O(n+k) 时间复杂度(最坏) O(n+k) 时间复杂度(最好) O(n+k) 空间复杂度 O(n+k) 稳定性 · 稳定 + 2. 桶排序 +时间复杂度(平均) O(n+k) 时间复杂度(最坏) O(n²) 时间复杂度(最好) O(n) 空间复杂度 O(n+k) 稳定性 稳定 + 3. 基数排序 +时间复杂度(平均) O(n*k) 时间复杂度(最坏) O(n*k) 时间复杂度(最好) O(n*k) 空间复杂度 O(n+k)稳定性 稳定 \ No newline at end of file diff --git a/Week 07/id_641/lesson16/LeetCode_191_641.java b/Week 07/id_641/lesson16/LeetCode_191_641.java new file mode 100644 index 000000000..f0a6bb391 --- /dev/null +++ b/Week 07/id_641/lesson16/LeetCode_191_641.java @@ -0,0 +1,30 @@ +package vip.ruoyun.week7.lesson16; + +public class LeetCode_191_641 { + + + //利用 and 操作符 + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + } + + //每回都看看是否等于 0 如果不等于 0 那么就 and n-1 位 + public int hammingWeight2(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } + + +} diff --git a/Week 07/id_641/lesson16/LeetCode_231_641.java b/Week 07/id_641/lesson16/LeetCode_231_641.java new file mode 100644 index 000000000..9302c54e9 --- /dev/null +++ b/Week 07/id_641/lesson16/LeetCode_231_641.java @@ -0,0 +1,10 @@ +package vip.ruoyun.week7.lesson16; + +public class LeetCode_231_641 { + + //2的幂数的数字的二进制有且只有一个1,其余均是0 + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} + diff --git a/Week 07/id_641/lesson18/LeetCode_1122_641.java b/Week 07/id_641/lesson18/LeetCode_1122_641.java new file mode 100644 index 000000000..765eb3d9a --- /dev/null +++ b/Week 07/id_641/lesson18/LeetCode_1122_641.java @@ -0,0 +1,31 @@ +package vip.ruoyun.week7.lesson18; + +public class LeetCode_1122_641 { + + + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] nums = new int[1001]; + int[] res = new int[arr1.length]; + //遍历arr1,统计每个元素的数量 + for (int i : arr1) { + nums[i]++; + } + //遍历arr2,处理arr2中出现的元素 + int index = 0; + for (int i : arr2) { + while (nums[i] > 0) { + res[index++] = i; + nums[i]--; + } + } + //遍历nums,处理剩下arr2中未出现的元素 + for (int i = 0; i < nums.length; i++) { + while (nums[i] > 0) { + res[index++] = i; + nums[i]--; + } + } + return res; + } + +} diff --git "a/Week 07/id_646/\346\225\260\347\273\204\347\233\270\345\257\271\346\216\222\345\272\217.md" "b/Week 07/id_646/\346\225\260\347\273\204\347\233\270\345\257\271\346\216\222\345\272\217.md" new file mode 100644 index 000000000..5312ac02c --- /dev/null +++ "b/Week 07/id_646/\346\225\260\347\273\204\347\233\270\345\257\271\346\216\222\345\272\217.md" @@ -0,0 +1,17 @@ +```js +var relativeSortArray = function(arr1, arr2) { + return arr1.sort((a, b) => { + let ia = arr2.indexOf(a); + let ib = arr2.indexOf(b); + if(ia == -1 && ib == -1) { + return a - b; + } else if (ia == -1) { + return 1; + } else if (ib == -1) { + return -1; + } else { + return ia-ib; + } + }); +}; +``` \ No newline at end of file diff --git "a/Week 07/id_646/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.md" "b/Week 07/id_646/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.md" new file mode 100644 index 000000000..6b9441bf4 --- /dev/null +++ "b/Week 07/id_646/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.md" @@ -0,0 +1,20 @@ +```js +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + let aCode = 'a'.charCodeAt(); + let arrResualt = new Array(26); + for (let i = 0; i < arrResualt.length; i++) { + arrResualt[i] = 0; + } + for (let i = 0; i < s.length; i++) { + arrResualt[s[i].charCodeAt() - aCode]++; + arrResualt[t[i].charCodeAt() - aCode]--; + } + let setArray = Array.from(new Set(arrResualt)); + if (setArray.length === 1 && setArray[0] === 0) { + return true; + } else { + return false; + } +}; +``` \ No newline at end of file diff --git a/Week 07/id_651/LeetCode_146_651.py b/Week 07/id_651/LeetCode_146_651.py new file mode 100644 index 000000000..235294521 --- /dev/null +++ b/Week 07/id_651/LeetCode_146_651.py @@ -0,0 +1,60 @@ +""" +运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +进阶: +你是否可以在 O(1) 时间复杂度内完成这两种操作? +""" +class ListNode: + def __init__(self, key=None, value=None): + self.key = key + self.value = value + self.prev = None + self.next = None + +class LRUCache: + def __init__(self, capacity): + self.capcaity = capacity + self.hashmap = {} + self.head = ListNode() + self.tail = ListNode() + self.head.next = self.tail + self.tail.prev = self.head + + def move_node_to_tail(self, key): + node = self.hashmap[key] + node.prev.next = node.next + node.next.prev = node.prev + node.prev = self.tail.prev + node.next = self.tail + self.tail.prev.next = node + self.tail.prev = node + + def get(self, key): + if key in self.hashmap: + self.move_node_to_tail(key) + res = self.hashmap.get(key, -1) + if res == -1: + return res + else: + return res.value + + def put(self, key, value): + if key in self.hashmap: + self.hashmap[key].value = value + self.move_node_totail(key) + else: + if len(self.hashmap) == self.capacity: + self.hashmap.pop(self.head.next.key) + self.head.next = self.head.next.next + self.head.next.prev = self.head + new = ListNode(key, value) + self.hashmap[key] = new + new.prev = self.tail.prev + new.next = self.tail + self.tail.prev.next = new + self.tail.prev = new + + +if __name__ = '__main__': + pass \ No newline at end of file diff --git a/Week 07/id_651/LeetCode_51_651.py b/Week 07/id_651/LeetCode_51_651.py new file mode 100644 index 000000000..099911efd --- /dev/null +++ b/Week 07/id_651/LeetCode_51_651.py @@ -0,0 +1,39 @@ +""" +n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 +给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 +每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 +示例: +输入: 4 +输出: [ + [".Q..", // 解法 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // 解法 2 + "Q...", + "...Q", + ".Q.."] +] +解释: 4 皇后问题存在两个不同的解法。 +""" +class Solution: + def solveNQueens(self, n): + self.result = [] + self.n = n + self.DFS([], [], []) + return [["."*i + "Q" + "."*(n-i-1) for i in sol] for sol in self.result] + + def DFS(self, queens, xy_dif, xy_sum): + q_num = len(queens) + if q_num == self.n: + result.append(queens) + return None + for q in range(self.n): + if q not in queens and q_num-q not in xy_dif and q_num+q not in xy_sum: + self.DFS(queens+[q], xy_dif+[q_num-q], xy_sum+[q_num+q]) + +if __name__ == '__main__': + sol = Solution() + sol.solveNQueens(4) + pass \ No newline at end of file diff --git a/Week 07/id_651/LeetCode_56_651.py b/Week 07/id_651/LeetCode_56_651.py new file mode 100644 index 000000000..cdae3f9ae --- /dev/null +++ b/Week 07/id_651/LeetCode_56_651.py @@ -0,0 +1,29 @@ +""" +给出一个区间的集合,请合并所有重叠的区间。 + +示例 1: +输入: [[1,3],[2,6],[8,10],[15,18]] +输出: [[1,6],[8,10],[15,18]] +解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. + +示例 2: +输入: [[1,4],[4,5]] +输出: [[1,5]] +解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 +""" + +class Solution: + def merge(self, intervals): + intervals = sorted(intervals) + result = [] + length = len(intervals) + i = 0 + while i> 1 + x / 2^k x >> k + 清零最低位的1: + X = X&(X-1) + 得到最低位的1/0: + X&-X/ X&~X + + +2. 布隆过滤器, LRU缓存 + 布隆过滤器: + 存储:将待存储的数据按照一定规则拆分。 并在过滤器的列表中对应索引位置将表示改为1. + 查询:将待查询的数据按照一定规则拆分。 所有对应的索引位置的值是否为1。 + 如果都为1, 则该数据可能存在该位置。 + 如果存在一个非1的, 则该数据肯定不存在该位置。 + LRU缓存: + 存储:将待存储的数据生成一个双链表节点. 像队列一样, 一次插入。 改变头尾节点 + 如果缓存队列满了, 则将位于尾部的弹出。 在头部插入新数据 + 如果缓存队列满了,且待插入的数据是已存在的数据。 则将该已存在的数据弹出,在头部插入该数据 + + +3. 排序算法: + 基本排序: + 初级: 选择排序, 插入排序,冒泡排序 -> O(n^2) + + 高级: 归并排序,快速排序,堆排序 -> O(nlogn) + + 特殊排序: 主要是针对整型数据的排序 + 基数排序, 基数排序,桶排序 +""" + + + + diff --git a/Week 07/id_661/LeetCode_146_661.py b/Week 07/id_661/LeetCode_146_661.py new file mode 100644 index 000000000..e6c89698e --- /dev/null +++ b/Week 07/id_661/LeetCode_146_661.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3.7 + + +class DLinkedNode: + def __init__(self): + self.key = 0 + self.value = 0 + self.prev = None + self.next = None + + +class LRUCache: + def __init__(self, capacity: int): + self.cache = {} + self.size = 0 + self.capacity = capacity + self.head, self.tail = DLinkedNode(), DLinkedNode() + + self.head.next = self.tail + self.tail.prev = self.head + + def get(self, key: int) -> int: + node = self.cache.get(key, None) + if not node: + return -1 + + self._move_to_head(node) + + return node.value + + def put(self, key: int, value: int) -> None: + node = self.cache.get(key) + if not node: + newNode = DLinkedNode() + newNode.key = key + newNode.value = value + + self.cache[key] = newNode + self._add_node(newNode) + + self.size += 1 + + if self.size > self.capacity: + tail = self._pop_tail() + del self.cache[tail.key] + self.size -= 1 + else: + node.value = value + self._move_to_head(node) + + def _add_node(self, node): + node.prev = self.head + node.next = self.head.next + + self.head.next.prev = node + self.head.next = node + + def _remove_node(self, node): + prev = node.prev + new = node.next + + prev.next = new + new.prev = prev + + def _move_to_head(self, node): + self._remove_node(node) + self._add_node(node) + + def _pop_tail(self): + res = self.tail.prev + self._remove_node(res) + return res diff --git a/Week 07/id_661/LeetCode_190_661.py b/Week 07/id_661/LeetCode_190_661.py new file mode 100644 index 000000000..35e1c8dc9 --- /dev/null +++ b/Week 07/id_661/LeetCode_190_661.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def reverseBits(self, n): + result = 0 + for i in range(32): + result = (result << 1) + (n & 1) + n >>= 1 + + return result + + +test = 0b11000111000110101100110010010101 +print(bin(Solution().reverseBits(test))) diff --git a/Week 07/id_661/LeetCode_191_661.py b/Week 07/id_661/LeetCode_191_661.py new file mode 100644 index 000000000..c25aa1778 --- /dev/null +++ b/Week 07/id_661/LeetCode_191_661.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def hammingWeight(self, n): + count = 0 + while n > 0: + count += 1 + n &= n - 1 + return count + + +test = 0b00000000000000000000000000001011 + +print(Solution().hammingWeight(test)) diff --git a/Week 07/id_661/LeetCode_231_661.py b/Week 07/id_661/LeetCode_231_661.py new file mode 100644 index 000000000..f356a9512 --- /dev/null +++ b/Week 07/id_661/LeetCode_231_661.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def isPowerOfTwo(self, n): + return n != 0 and n & (n - 1) == 0 + + +print(Solution().isPowerOfTwo(218)) diff --git a/Week 07/id_661/LeetCode_338_661.py b/Week 07/id_661/LeetCode_338_661.py new file mode 100644 index 000000000..3b79484ab --- /dev/null +++ b/Week 07/id_661/LeetCode_338_661.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def countBits(self, num: int) -> List[int]: + iniArr = [0] + if num > 0: + while len(iniArr) < num + 1: + iniArr.extend([x + 1 for x in iniArr]) + + return iniArr[0: num + 1] diff --git a/Week 07/id_661/LeetCode_51_661.py b/Week 07/id_661/LeetCode_51_661.py new file mode 100644 index 000000000..98a3e35d9 --- /dev/null +++ b/Week 07/id_661/LeetCode_51_661.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + result = [] + self._DFS(result, [], [], [], n) + return [["." * i + "Q" + "." * (n - i - 1) for i in sol] for sol in result] + + def _DFS(self, result, queens, xy_dif, xy_sum, n): + p = len(queens) + if p == n: + result.append(queens) + return None + for q in range(n): + if q not in queens and p - q not in xy_dif and p + q not in xy_sum: + self._DFS(result, queens + + [q], xy_dif + [p - q], xy_sum + [p + q], n) diff --git a/Week 07/id_661/LeetCode_52_661.py b/Week 07/id_661/LeetCode_52_661.py new file mode 100644 index 000000000..e9d61a607 --- /dev/null +++ b/Week 07/id_661/LeetCode_52_661.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3.7 + + +class Solution: + def totalNQueens(self, n: int) -> int: + if n < 1: + return [] + self.count = 0 + self.DFS(n, 0, 0, 0, 0) + return self.count + + def DFS(self, n, row, cols, pie, na): + if row >= n: + self.count += 1 + return + bits = (~(cols | pie | na)) & ((1 << n) - 1) + while bits: + p = bits & -bits + bits = bits & (bits - 1) + self.DFS(n, row + 1, cols | p, (pie | p) << 1, (na | p) >> 1) + + +print(Solution().totalNQueens(4)) diff --git a/Week 07/id_666/LeetCode_191_666.java b/Week 07/id_666/LeetCode_191_666.java new file mode 100644 index 000000000..a809b95c5 --- /dev/null +++ b/Week 07/id_666/LeetCode_191_666.java @@ -0,0 +1,13 @@ +public class Solution { + public int hammingWeight(int n) { + int count = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + count++; + } + mask <<= 1; + } + return count; + } +} \ No newline at end of file diff --git a/Week 07/id_666/LeetCode_231_666.java b/Week 07/id_666/LeetCode_231_666.java new file mode 100644 index 000000000..2fcb37ba4 --- /dev/null +++ b/Week 07/id_666/LeetCode_231_666.java @@ -0,0 +1,13 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + if (n < 1) { + return false; + } + + if ((n & (n -1)) == 0) { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Week 07/id_681/LeetCode_191_681.java b/Week 07/id_681/LeetCode_191_681.java new file mode 100644 index 000000000..6478109aa --- /dev/null +++ b/Week 07/id_681/LeetCode_191_681.java @@ -0,0 +1,13 @@ +public class Solution { + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + } +} \ No newline at end of file diff --git a/Week 07/id_681/LeetCode_338_681.java b/Week 07/id_681/LeetCode_338_681.java new file mode 100644 index 000000000..f3302a365 --- /dev/null +++ b/Week 07/id_681/LeetCode_338_681.java @@ -0,0 +1,15 @@ +public class Solution { + public int[] countBits(int num) { + int[] ans = new int[num + 1]; + for (int i = 0; i <= num; ++i) + ans[i] = popcount(i); + return ans; + } + + private int popcount(int x) { + int count; + for (count = 0; x != 0; ++count) + x &= x - 1; + return count; + } +} diff --git a/Week 07/id_686/LeetCode_1122_686.py b/Week 07/id_686/LeetCode_1122_686.py new file mode 100644 index 000000000..3196aabf6 --- /dev/null +++ b/Week 07/id_686/LeetCode_1122_686.py @@ -0,0 +1,31 @@ +# +# @lc app=leetcode.cn id=1122 lang=python3 +# +# [1122] 数组的相对排序 +# + +# @lc code=start +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + cnt = [0 for _ in range(1001)] + + for a in arr1: + cnt[a] += 1 + + i = 0 + for a in arr2: + while cnt[a] > 0: + arr1[i] = a + i += 1 + cnt[a] -= 1 + + for j in range(1001): + while cnt[j] > 0: + arr1[i] = j + i += 1 + cnt[j] -= 1 + + return arr1 + +# @lc code=end + diff --git a/Week 07/id_686/LeetCode_146_686.java b/Week 07/id_686/LeetCode_146_686.java new file mode 100644 index 000000000..49da04e82 --- /dev/null +++ b/Week 07/id_686/LeetCode_146_686.java @@ -0,0 +1,86 @@ +//运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +// +// 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +//写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 +// +// 进阶: +// +// 你是否可以在 O(1) 时间复杂度内完成这两种操作? +// +// 示例: +// +// LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +// +//cache.put(1, 1); +//cache.put(2, 2); +//cache.get(1); // 返回 1 +//cache.put(3, 3); // 该操作会使得密钥 2 作废 +//cache.get(2); // 返回 -1 (未找到) +//cache.put(4, 4); // 该操作会使得密钥 1 作废 +//cache.get(1); // 返回 -1 (未找到) +//cache.get(3); // 返回 3 +//cache.get(4); // 返回 4 +// +// Related Topics 设计 + + + +//leetcode submit region begin(Prohibit modification and deletion) +public class LRUCache{ + class Pair{ + int key; + int value; + } + private Map cache = new HashMap<>(); + private int size; + private int capacity; + Deque dq = new LinkedList<>(); + + public LRUCache(int capacity) { + this.size = 0; + this.capacity = capacity; + } + + public int get(int key) { + Pair node = cache.get(key); + if(node == null) return -1; + + dq.remove(node); + dq.addFirst(node); + + return node.value; + } + + public void put(int key, int value) { + Pair node = cache.get(key); + + if(node == null){ + Pair newNode = new Pair(); + newNode.key = key; + newNode.value = value; + + cache.put(key, newNode); + dq.addFirst(newNode); + + ++size; + + if(size > capacity){ + Pair tail = dq.pollLast(); + cache.remove(tail.key); + --size; + } + }else { + node.value = value; + dq.remove(node); + dq.addFirst(node); + } + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 07/id_686/LeetCode_146_686.py b/Week 07/id_686/LeetCode_146_686.py new file mode 100644 index 000000000..bae2ef2cb --- /dev/null +++ b/Week 07/id_686/LeetCode_146_686.py @@ -0,0 +1,85 @@ +# +# @lc app=leetcode.cn id=146 lang=python3 +# +# [146] LRU缓存机制 +# + +# @lc code=start +class Double_LL_Node: + def __init__(self, val): + self.val = val + self.prev = None + self.next = None + +class LRUCache: + + def __init__(self, capacity: int): + self.capacity = capacity + self.curr_length = 0 + self.hashmap = {} + + self.head = Double_LL_Node(0) + self.tail = Double_LL_Node(0) + + self.head.next = self.tail + self.tail.prev = self.head + + def move_to_front_in_LL(self, node): + temp = self.head.next + + self.head.next = node + node.prev = self.head + + node.next = temp + temp.prev = node + + def remove_from_LL(self, node): + temp_next = node.next + temp_before = node.prev + + temp_before.next = temp_next + temp_next.prev = temp_before + + return node + + def get(self, key: int) -> int: + if key in self.hashmap: + node = self.remove_from_LL(self.hashmap[key][1]) + self.move_to_front_in_LL(node) + return self.hashmap[key][0] + else: + return -1 + + def put(self, key: int, value: int) -> None: + if key in self.hashmap: + node = self.remove_from_LL(self.hashmap[key][1]) + self.move_to_front_in_LL(node) + + self.hashmap[key][0] = value + + else: + if self.curr_length> 1; + } + return n == 1; + } +} diff --git a/Week 07/id_696/LeetCode_242_696.java b/Week 07/id_696/LeetCode_242_696.java new file mode 100644 index 000000000..a5ec7f140 --- /dev/null +++ b/Week 07/id_696/LeetCode_242_696.java @@ -0,0 +1,16 @@ +package week07; + +import java.util.Arrays; + +class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] sArray = s.toCharArray(); + char[] tArray = t.toCharArray(); + Arrays.sort(sArray); + Arrays.sort(tArray); + return Arrays.equals(sArray, tArray); + } +} diff --git a/Week 07/id_701/LeetCode_146_701.py b/Week 07/id_701/LeetCode_146_701.py new file mode 100644 index 000000000..cd9cdaac9 --- /dev/null +++ b/Week 07/id_701/LeetCode_146_701.py @@ -0,0 +1,24 @@ +from collections import OrderedDict + + +class LRUCache: + def __init__(self, capacity: int): + self.dic = OrderedDict() + self.capacity = capacity + + def get(self, key: int) -> int: + if key not in self.dic: + return -1 + val = self.dic.pop(key) + self.dic[key] = val + return val + + def put(self, key: int, value: int) -> None: + if key in self.dic: + self.dic.pop(key) + else: + if self.capacity > 0: + self.capacity -= 1 + else: + self.dic.popitem(last=False) + self.dic[key] = value diff --git a/Week 07/id_701/LeetCode_190_701.py b/Week 07/id_701/LeetCode_190_701.py new file mode 100644 index 000000000..b2fd42225 --- /dev/null +++ b/Week 07/id_701/LeetCode_190_701.py @@ -0,0 +1,7 @@ +class Solution: + def reverseBits(self, n: int) -> int: + ans = 0 + for i in range(32): + ans = (ans << 1) + (n & 1) + n >>= 1 + return ans diff --git a/Week 07/id_701/LeetCode_191_701.py b/Week 07/id_701/LeetCode_191_701.py new file mode 100644 index 000000000..28935bff4 --- /dev/null +++ b/Week 07/id_701/LeetCode_191_701.py @@ -0,0 +1,11 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + return bin(n).count('1') + + def hammingWeight(self, n: int) -> int: + count = 0 + for i in range(0, 32): + if(n & 1 == 1): + count += 1 + n >>= 1 + return count diff --git a/Week 07/id_701/LeetCode_231_701.py b/Week 07/id_701/LeetCode_231_701.py new file mode 100644 index 000000000..f04e71820 --- /dev/null +++ b/Week 07/id_701/LeetCode_231_701.py @@ -0,0 +1,3 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and not (n & n-1) diff --git a/Week 07/id_701/NOTE.md b/Week 07/id_701/NOTE.md index a6321d6e2..f38aec06c 100644 --- a/Week 07/id_701/NOTE.md +++ b/Week 07/id_701/NOTE.md @@ -1,4 +1,171 @@ -# NOTE - +# 【701-week7】第七周学习总结 +## 位运算 + +XOR 异或:相同为 0,不同为 1。也可用 **不进位加** 来理解。 + +操作特点: + +- x ^ 0 = x +- x ^ 1s = ~x // 注意 1s = ~0 +- x ^ (~x) = 1s +- x ^ x = 0 +- c = a ^ b => a ^ c = b, b ^ c = a // 交换两个数 +- a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative + +指定位置的位运算: + +- 将 x 最右边的 n 位清零:x & (~0 << n) +- 获取 x 的第 n 位值(0 或者 1): (x >> n) & 1 +- 获取 x 的第 n 位的幂值:x & (1 << (n -1)) +- 仅将第 n 位置为 1:x | (1 << n) +- 仅将第 n 位置为 0:x & (~ (1 << n)) +- 将 x 最高位至第 n 位(含)清零:x & ((1 << n) - 1) +- 将第 n 位至第 0 位(含)清零:x & (~ ((1 << (n + 1)) - 1)) + +实战位运算要: + +- 判断奇偶:x % 2 == 1 —> (x & 1) == 1 x % 2 == 0 —> (x & 1) == 0 +- 取中间值: x >> 1 —> x / 2 + - 即:x = x / 2; —> x = x >> 1; + - mid = (left + right) / 2; —> mid = (left + right) >> 1; +- 清零最低位的 1:X = X & (X-1) +- 得到最低位的 1:X & -X +- X & ~X => 0 + +## 布隆过滤器 + +> 一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索 一个元素是否在一个集合中。 + +- 优点是空间效率和查询时间都远远超过一般的算法; +- 缺点是有一定的误识别率和删除困难; + +常见使用案例: + +- 比特币网络 +- 分布式系统 (Map-Reduce) — Hadoop、search engine +- Redis 缓存 +- 垃圾邮箱、评论等的过滤 + +示例代码 + +```python +from bitarray import bitarray +import mmh3 + +class BloomFilter: + def __init__(self, size, hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray(size) + self.bit_array.setall(0) + + def add(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + self.bit_array[result] = 1 + + def lookup(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + if self.bit_array[result] == 0: + return "Nope" return "Probably" + +bf = BloomFilter(500000, 7) +bf.add("dantezhao") +print(bf.lookup("dantezhao")) +print(bf.lookup("yyj")) +``` + +## Cache 缓存 + +LRU Cache + +两个要素: + +- 大小 +- 替换策略: + - LFU - least frequently used + - LRU - least recently used +- Hash Table + Double LinkedList +- O(1) 查询,O(1) 修改、更新 + +示例代码 + +```python +class LRUCache(object): + def __init__(self, capacity): + self.dic = collections.OrderedDict() + self.remain = capacity + + def get(self, key): + if key not in self.dic: + return -1 + v = self.dic.pop(key) + self.dic[key] = v # key as the newest one + return v + + def put(self, key, value): + if key in self.dic: + self.dic.pop(key) + else: + if self.remain > 0: + self.remain -= 1 + else: # self.dic is full + self.dic.popitem(last=False) + self.dic[key] = value +``` + +## 排序算法 + +比较类排序 + +> 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。 + +非比较类排序 + +> 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时 间下界,以线性时间运行,因此也称为线性时间非比较类排序。 + + +### 初级排序 O(n*n) + +- 选择排序(Selection Sort) + +> 每次找最小值,然后放到待排序数组的起始位置。 + +- 插入排序(Insertion Sort) + +> 从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后 向前扫描,找到相应位置并插入。 + +- 冒泡排序(Bubble Sort) + +> 嵌套循环,每次查看相邻的元素如果逆序,则交换。 + +### 高级排序 (n * logN) + +- 快速排序(Quick Sort) + +> 数组取标杆 pivot,将小元素放 pivot左边,大元素放右侧,然后依次 对右边和右边的子数组继续快排;以达到整个序列有序。 + +归并 和 快排 具有相似性,但步骤顺序相反 + +- 归并:先排序左右子数组,然后合并两个有序子数组 +- 快排:先调配出左右子数组,然后对于左右子数组进行排序 + +- 堆排序(Heap Sort) — 堆插入 O(logN),取最大/小值 O(1) + +> 数组元素依次建立小顶堆;依次取堆顶元素,并删除; + +### 特殊排序 + +- 计数排序(Counting Sort) + +> 计数排序要求输入的数据必须是有确定范围的整数。将输入的数据值转化为键存 储在额外开辟的数组空间中;然后依次把计数大于 1 的填充回原数组 + +- 桶排序(Bucket Sort) + +> 桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有 限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式 继续使用桶排序进行排)。 + +- 基数排序(Radix Sort) +> 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类 推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按 高优先级排序。 \ No newline at end of file diff --git a/Week 07/id_716/LeetCode_146_716.java b/Week 07/id_716/LeetCode_146_716.java new file mode 100644 index 000000000..e4f08a967 --- /dev/null +++ b/Week 07/id_716/LeetCode_146_716.java @@ -0,0 +1,17 @@ + +public class LeetCode_146_716 { + class LRUCache { + + public LRUCache(int capacity) { + + } + + public int get(int key) { + return 0; + } + + public void put(int key, int value) { + + } + } +} \ No newline at end of file diff --git a/Week 07/id_716/LeetCode_190_716.java b/Week 07/id_716/LeetCode_190_716.java new file mode 100644 index 000000000..e269a3a84 --- /dev/null +++ b/Week 07/id_716/LeetCode_190_716.java @@ -0,0 +1,25 @@ + +public class LeetCode_190_716 { + // you need treat n as an unsigned value + public int reverseBits1(int n) { + int res = 0; + // 32 bit, loop 32 times + for (int i = 0; i < 32; i++) { + // n & 1: 取二进制最后一位 + // res << 1: res 左移1位,如 0 << 1 -> 00 + res = (res << 1) + (n & 1); + // n 右移1位,删除掉最低位 + n = n >> 1; + } + return res; + } + + public int reverseBits(int n) { + int res = 0; + for (int i = 0; i < 32; i++) { + res = (res << 1) | (n & 1); // 和 (res << 1) + (n & 1) 等价 + n >>= 1; + } + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_716/LeetCode_191_716.java b/Week 07/id_716/LeetCode_191_716.java new file mode 100644 index 000000000..edb7929b4 --- /dev/null +++ b/Week 07/id_716/LeetCode_191_716.java @@ -0,0 +1,34 @@ + +public class LeetCode_191_716 { + // 1. bit manipulation + public int hammingWeight1(int n) { + int res = 0; + while (n != 0) { + n = n & (n - 1); + res++; + } + return res; + } + + // 2. loop & mask + public int hammingWeight2(int n) { + int res = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) res++; + mask <<= 1; + } + return res; + } + + // 3. % 2, then / 2 + public int hammingWeight3(int n) { + int res = 0; + for (int i = 0; i < 32; i++) { + if ((n & 1) == 1) res++; + n = n >> 1; + } + + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_716/LeetCode_231_716.java b/Week 07/id_716/LeetCode_231_716.java new file mode 100644 index 000000000..545c25476 --- /dev/null +++ b/Week 07/id_716/LeetCode_231_716.java @@ -0,0 +1,6 @@ + +public class LeetCode_231_716 { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_716/LeetCode_338_716.java b/Week 07/id_716/LeetCode_338_716.java new file mode 100644 index 000000000..1fd20f223 --- /dev/null +++ b/Week 07/id_716/LeetCode_338_716.java @@ -0,0 +1,38 @@ + +public class LeetCode_338_716 { + // 1. loop every item + public int[] countBits1(int num) { + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + res[i] = countBitsOfANumber(i); + } + return res; + } + + private int countBitsOfANumber(int i) { + int cnt = 0; + while (i != 0) { + i = i & (i - 1); + cnt++; + } + return cnt; + } + + // 2. dp + public int[] countBits2(int num) { + int[] res = new int[num + 1]; + for (int i = 0; i <= num; i++) { + res[i] = res[i >> 1] + (i & 1); + } + return res; + } + + // 3. dp + public int[] countBits3(int num) { + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i & (i - 1)] + 1; + } + return res; + } +} \ No newline at end of file diff --git a/Week 07/id_716/NOTE.md b/Week 07/id_716/NOTE.md index a6321d6e2..4ed76c3f4 100644 --- a/Week 07/id_716/NOTE.md +++ b/Week 07/id_716/NOTE.md @@ -1,4 +1,93 @@ # NOTE - +## 题目 +- +- +- +- +- +- +- +- +- +- +- + +## 总结:各大经典排序算法分析及实现 + +本周是训练营的第 7 周,主要对排序算法做些总结,理清楚排序算法的分析、代码实现和工业级排序算法需要考虑的指标,甚至于可以分析一下 java(或者 golang)中排序算法是如何实现的。 + +排序在日常开发中经常用到,而往往我们都是使用库函数中的排序函数,大部分人可能不知道它的具体实现是如何的,它的效率怎么样,什么数据量的情况下它会有好的表现,什么数据量下它会变的更糟,它会占用多大的额外空间,比较或者移动数据的次数是多少等等。 + +### 如何分析一个排序算法 + +想要知道一个排序算法是否适合应用场景,就需要知道如何分析和评价一个排序算法。可以从以下几点进行考察: + +- 复杂度分析(包括时间和空间) + +需要同时考虑时间复杂度和空间复杂度,对与时间复杂度要从至少三个维度进行分析:最好、最坏和平均复杂度分析,以及各自情况下对应的数据特点是怎么样的。因为不同有序度的数据,对排序算法的性能表现是有影响的。比如冒泡排序,在接近有序的数据下,可能会提前结束循环,复杂度可能会接近 O(n) + +- 考虑在特定数据规模下的细粒度分析,把复杂度的常数项、系数、阶数也做分析 + +实际的软件开发中,我们排序的可能是 10 个、100 个、1000 个这样规模很小的数据,所以,在对同一阶时间复杂度的排序算法性能对比的时候,我们就要把系数、常数、低阶也考虑进来 + +- 是否是原地排序算法(原地排序说明是否会使用很多的额外空间) +- 是否是稳定的排序算法(稳定排序说明如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变) +- 排序过程中比较、交换/移动数据的次数 + +### 常见的排序算法 + +常见的排序算法有: + +1. 初级:冒泡排序、选择排序、插入排序、希尔排序 +2. 高级:快速排序、归并排序、堆排序 +3. 特殊:计数排序、桶排序、基数排序 + +- 冒泡排序 Bubble Sort + +```java +public class BubbleSort implements Sort { + @Override + public void sort(int[] arr) { + if (arr.length <= 1) return; + + for (int i = 0; i < arr.length; i++) { + boolean flag = false; // 标识概论次的标中是否有数据交换 + for (int j = 0; j < arr.length - i - 1; j++) { // 边界 arr.length - i - 1 + if (arr[j] > arr[j + 1]) { // 大数往后移动 + int temp = arr[j]; + arr[j] = arr[j - 1]; + arr[j - 1] = temp; + flag = true; + } + } + // flag 还是 false 的话,说明没有数据交换,表明已经有序,就退出 + if (!flag) break; + } + } +} +``` + +冒泡排序的核心思想是每一轮的比较,找到一个最大的值放在数组的后面,总共需要进行 `arr.length` 的轮次。重点有两个: + +1. 冒泡排序有可能是可以提前终止的,在每次比较时后一个数较小的话,就会做一次交换,如果在轮次没结束之前,且没有进行数据交换,那么就说明数组已经完全有序,就可以直接退出了 +2. 比较的条件和范围,条件是 `arr[j]` 大于 `arr[j + 1]`, j 的范围是从 `0` 到 `arr.length - i - 1`, 因为最后的 `i + 1` 个数已经有序了 + +以上两点是写冒泡排序需要注意的。 + +分析:最好情况时间复杂度是 O(n), 最坏是 O(n^2), 平均是 O(n^2), 是原地排序算法,空间复杂度 O(1), 是稳定的排序算法。 + +- 插入排序 + +```java +``` + +- 希尔排序 +- 选择排序 +- 快速排序 +- 归并排序 +- 堆排序 + +Java 中的排序函数 +Golang 中的排序函数 diff --git a/Week 07/id_721/LeetCode_191_721.java b/Week 07/id_721/LeetCode_191_721.java new file mode 100644 index 000000000..1cca9bc1e --- /dev/null +++ b/Week 07/id_721/LeetCode_191_721.java @@ -0,0 +1,49 @@ +package bit; + +/** + * @author alis + * @date 2019/12/1 8:12 AM + * @description + */ +public class LeetCode_191_721 { + /** + * 题意 + * 计算输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(汉明重量) + * 思路: + * 1. for loop ,遍历计算法 (32) + * 2. %2 /2 取出最后一个,判断是否为1 (32) + * 3. n & 1 看最低位是0 还是1, 每次 x = x >> 1向右移一位,进行下一次判断 (32) + * 4. x = x & (x-1) 清0最低位的1(将最后一个1变为0) 判断x是否位0; while (x != 0) {count++; x = x & (x -1);} + */ + public int hammingWeightRemoveLastOne(int n) { + int count = 0; + while (n != 0) { + count++; + n = n & (n - 1); //将最后一个1位移除,计算移除了多少个1位,就可以得到结果 + } + return count; + } + + /** + * 移除最后一位,判断最后一位是否是1,再进行统计 + */ + public int hammingWeightRemoveLastIndex(int n) { + int count = 0; + while (n != 0) { // 退出条件,移除最后一位,直至这个整数的所有数位都已经被移除 --> 0 + int last = n & 1; + if (last == 1) count++; + n = n >> 1; // 右移动一位,取出最后一位 + } + return count; + } + + public int hammingWeightMod(int n) { + int count = 0; + while (n != 0) { + int cur = n % 2; + if (cur == 1) count++; + n = n / 2; + } + return count; + } +} diff --git a/Week 07/id_721/LeetCode_192_721.java b/Week 07/id_721/LeetCode_192_721.java new file mode 100644 index 000000000..6d619fbfe --- /dev/null +++ b/Week 07/id_721/LeetCode_192_721.java @@ -0,0 +1,28 @@ +package bit; + +/** + * @author alis + * @date 2019/12/1 5:16 PM + * @description + */ +public class LeetCode_192_721 { + /** + * 颠倒二进制位 + * 1. 将给定的二进制数,由低位到高位逐个取出 + * 2. 然后通过位运算,将其放置到反转到二进制位 + * 3. 将上述结果,再次通过位运算合并在一起 + */ + public int reverseBits(int n) { + int res = 0; + for (int i = 0; i <= 32; i++) { + // 给定的二进制数,从低位到高位逐个取出 + int temp = n >> i; // 右移i位 + temp = temp & 1; // 取最后一位 + // 然后通过位运算,将其放置到反转后的位置 + temp = temp << (31 - i); + res |= temp; + + } + return res; + } +} diff --git a/Week 07/id_721/LeetCode_231_721.java b/Week 07/id_721/LeetCode_231_721.java new file mode 100644 index 000000000..aa3351fa2 --- /dev/null +++ b/Week 07/id_721/LeetCode_231_721.java @@ -0,0 +1,16 @@ +package bit; + +/** + * @author alis + * @date 2019/12/1 10:41 AM + * @description + */ +public class LeetCode_231_721 { + /** + * 题意:判断一个数字是否为2的次幂数 + * + * */ + public boolean isPowerOfTwo(int n) { + return (n != 0) && (n & (n - 1)) == 0; + } +} diff --git a/Week 07/id_721/LeetCode_338_721.java b/Week 07/id_721/LeetCode_338_721.java new file mode 100644 index 000000000..dd5e9016c --- /dev/null +++ b/Week 07/id_721/LeetCode_338_721.java @@ -0,0 +1,67 @@ +package bit; + +/** + * @author alis + * @date 2019/12/1 5:33 PM + * @description + */ +public class LeetCode_338_721 { + /** + * 题意: 判断一个正整数,在0 foreach 判断每个数字的二进制格式包含多少个1 -> 位运算 x & (x-1) 取出二进制位的最后一个1,并统计其次数 + */ + public int[] countBits(int n) { + int[] res = new int[n + 1]; + for (int i = 0; i <= n; ++i) { + res[i] = countBit(i); + } + return res; + } + + private int countBit(int x) { + int count = 0; + while (x != 0) { + count++; + x &= (x - 1); + } + return count; + } + + /** + * 动态规划 + 最高有效位 + *

    + * DP解法 + * 从观察规律 0(0), 1(1), 2(10), 3(11) 看 + * 2的二进制比 0 多一个1 + * 3的二进制比 1 多一个1 + * 根据状态转移,得出dp方程 + * p(x+b) = p(x) + 1, b = 2^m + */ + public int[] countBitsDP1(int n) { + int[] ans = new int[n + 1]; + int i = 0, b = 1; + while (b <= n) { + // 求每一层子问题: 比如 求 2,3整数的统计, 可以由0,1得到 ; 而b可以理解为 b=3-1=2-0这个规律 + while (i < b && i + b <= n) { + ans[i + b] = ans[i] + 1; + ++i; + } + i = 0; + b <<= 1; // b=2b 也就是求b在每一层子问题的上限 + } + return ans; + } + + /** + * dp方程 + * P(x)=P(x/2)+(xmod2) + */ + public int[] countBitsDP2(int n) { + int[] ans = new int[n + 1]; + for (int i = 1; i <= n; i++) { + ans[i] = ans[i >> 1] + (i & 1); + } + return ans; + } +} diff --git a/Week 07/id_731/LeetCode_231_731.txt b/Week 07/id_731/LeetCode_231_731.txt new file mode 100644 index 000000000..3de7884e9 --- /dev/null +++ b/Week 07/id_731/LeetCode_231_731.txt @@ -0,0 +1,13 @@ +class Solution { +public: + bool isPowerOfTwo(int n) { + if (n <= 0) { + return false; + } + + if ((n&(n-1)) == 0) { + return true; + } + return false; + } +}; \ No newline at end of file diff --git a/Week 07/id_731/LeetCode_56_731.txt b/Week 07/id_731/LeetCode_56_731.txt new file mode 100644 index 000000000..886882e7d --- /dev/null +++ b/Week 07/id_731/LeetCode_56_731.txt @@ -0,0 +1,22 @@ +class Solution { +public: + vector> merge(vector>& intervals) { + if(intervals.empty()) + return {}; + vector>res; + sort(intervals.begin(),intervals.end()); + int i=1; + for(;i=intervals[i-1][0]&&intervals[i][0]<=intervals[i-1][1]) + { + intervals[i][0]=intervals[i-1][0]; + intervals[i][1]=max(intervals[i-1][1],intervals[i][1]); + } + else + res.push_back(intervals[i-1]); + } + res.push_back(intervals[i-1]); //һԪطŽvector + return res; + } +}; \ No newline at end of file diff --git "a/Week 07/id_756/[191]]\344\275\2151\347\232\204\344\270\252\346\225\260.java" "b/Week 07/id_756/[191]]\344\275\2151\347\232\204\344\270\252\346\225\260.java" new file mode 100644 index 000000000..ec4b9edbe --- /dev/null +++ "b/Week 07/id_756/[191]]\344\275\2151\347\232\204\344\270\252\346\225\260.java" @@ -0,0 +1,8 @@ +public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; +} \ No newline at end of file diff --git "a/Week 07/id_756/[231]2\347\232\204\345\271\202.java" "b/Week 07/id_756/[231]2\347\232\204\345\271\202.java" new file mode 100644 index 000000000..aeaac1421 --- /dev/null +++ "b/Week 07/id_756/[231]2\347\232\204\345\271\202.java" @@ -0,0 +1,5 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week 07/id_766/LeetCode_191_766.java b/Week 07/id_766/LeetCode_191_766.java new file mode 100644 index 000000000..fa4cb9cbd --- /dev/null +++ b/Week 07/id_766/LeetCode_191_766.java @@ -0,0 +1,20 @@ +/* + * @lc app=leetcode.cn id=191 lang=java + * + * [191] 位1的个数 + */ + +// @lc code=start +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int c = 0; + while (n != 0) { + c += (n & 1); + n >>>=1; + } + return c; + } +} +// @lc code=end + diff --git a/Week 07/id_766/LeetCode_231_766.java b/Week 07/id_766/LeetCode_231_766.java new file mode 100644 index 000000000..6a27312ea --- /dev/null +++ b/Week 07/id_766/LeetCode_231_766.java @@ -0,0 +1,18 @@ +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + */ + +// @lc code=start +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + + + + + } +} +// @lc code=end + diff --git a/Week 07/id_766/LeetCode_242_766.py b/Week 07/id_766/LeetCode_242_766.py new file mode 100644 index 000000000..ee8119242 --- /dev/null +++ b/Week 07/id_766/LeetCode_242_766.py @@ -0,0 +1,23 @@ +# +# @lc app=leetcode.cn id=242 lang=python3 +# +# [242] 有效的字母异位词 +# + +# @lc code=start +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + if len(s) == len(t): + for char in set(s): + if s.count(char) != t.count(char): + return False + return True + + else: + return False + + + + +# @lc code=end + diff --git a/Week 07/id_766/LeetCode_338_766.java b/Week 07/id_766/LeetCode_338_766.java new file mode 100644 index 000000000..fa50aeefa --- /dev/null +++ b/Week 07/id_766/LeetCode_338_766.java @@ -0,0 +1,18 @@ +/* + * @lc app=leetcode.cn id=338 lang=java + * + * [338] 比特位计数 + */ + +// @lc code=start +class Solution { + public int[] countBits(int num) { + int[] + f = new int[num + 1]; + for (int i = 1; i <= num; i++) f[i] = f[i >> 1] + ( i & 1); + return f; + + } +} +// @lc code=end + diff --git a/Week 07/id_766/LeetCode_493_766.java b/Week 07/id_766/LeetCode_493_766.java new file mode 100644 index 000000000..d063a7999 --- /dev/null +++ b/Week 07/id_766/LeetCode_493_766.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=493 lang=java + * + * [493] 翻转对 + */ + +// @lc code=start +class Solution { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length-1); + + + } + private int mergeSort(int[] nums, int s, int e) { + if (s >= e) return 0; + int mid = s + (e -s) / 2; + int cnt = mergeSort(nums, s, mid) + mergeSort(nums, mid + 1, e); + for (int i = s, j = mid + 1; i <=mid; i++) { + while(j <=e && nums[i]/2.0 > nums[j]) j++; + cnt += j-(mid+1); + } + Arrays.sort(nums, s, e+1); + return cnt; + } +} +// @lc code=end + diff --git a/Week 08/.DS_Store b/Week 08/.DS_Store new file mode 100644 index 000000000..406fc34e1 Binary files /dev/null and b/Week 08/.DS_Store differ diff --git a/Week 03/id_131/NOTE.md b/Week 08/id_001/NOTE.md old mode 100644 new mode 100755 similarity index 100% rename from Week 03/id_131/NOTE.md rename to Week 08/id_001/NOTE.md diff --git a/Week 08/id_006/LeetCode_300_006.java b/Week 08/id_006/LeetCode_300_006.java new file mode 100644 index 000000000..1c4a993e9 --- /dev/null +++ b/Week 08/id_006/LeetCode_300_006.java @@ -0,0 +1,21 @@ +class Solution { + public int lengthOfLIS(int[] nums) { + // [10,9,2,5,3,7,101,18] + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + + 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], 1 + dp[j]); + } + } + } + + int res = 0; + for (int i = 0; i < nums.length; i++) { + res = Math.max(res, dp[i]); + } + return res; + } +} diff --git a/Week 08/id_006/LeetCode_387_006.java b/Week 08/id_006/LeetCode_387_006.java new file mode 100644 index 000000000..18da5830d --- /dev/null +++ b/Week 08/id_006/LeetCode_387_006.java @@ -0,0 +1,15 @@ +public class Solution { + public int firstUniqChar(String s) { + int[] cache = new int[256]; + + for (int i = 0; i < s.length(); i++) { + cache[s.charAt(i) - 'a']++; + } + for (int i = 0; i < s.length(); i++) { + if (cache[s.charAt(i) - 'a'] == 1) { + return i; + } + } + return -1; + } +} diff --git a/Week 07/id_131/NOTE.md b/Week 08/id_006/NOTE.md old mode 100644 new mode 100755 similarity index 100% rename from Week 07/id_131/NOTE.md rename to Week 08/id_006/NOTE.md diff --git a/Week 07/id_576/NOTE.md b/Week 08/id_011/NOTE.md old mode 100644 new mode 100755 similarity index 100% rename from Week 07/id_576/NOTE.md rename to Week 08/id_011/NOTE.md diff --git a/Week 08/id_011/decode-ways.go b/Week 08/id_011/decode-ways.go new file mode 100644 index 000000000..375519efe --- /dev/null +++ b/Week 08/id_011/decode-ways.go @@ -0,0 +1,20 @@ +package algorithm00401 + +func numDecodings(s string) int { + if len(s) == 0 || s[:1] == "0" { + return 0 + } + a, b := 1, 1 + for i := 1; i < len(s); i++ { + if s[i:i+1] == "0" { + a = 0 + } + if s[i-1:i] == "1" || (s[i-1:i] == "2" && s[i:i+1] <= "6") { + a = a + b + b = a - b + } else { + b = a + } + } + return a +} diff --git a/Week 08/id_011/first-unique-character-in-a-string.go b/Week 08/id_011/first-unique-character-in-a-string.go new file mode 100644 index 000000000..1b46f1911 --- /dev/null +++ b/Week 08/id_011/first-unique-character-in-a-string.go @@ -0,0 +1,14 @@ +package algorithm00401 + +func firstUniqChar(s string) int { + var memo [26]int + for _, c := range s { + memo[c-'a']++ + } + for i, c := range s { + if memo[c-'a'] == 1 { + return i + } + } + return -1 +} diff --git a/Week 08/id_011/isomorphic-strings.go b/Week 08/id_011/isomorphic-strings.go new file mode 100644 index 000000000..e7a704e8e --- /dev/null +++ b/Week 08/id_011/isomorphic-strings.go @@ -0,0 +1,17 @@ +package algorithm00401 + +func isIsomorphic(s string, t string) bool { + m1 := make([]int, 256) + m2 := make([]int, 256) + + for i := 0; i < len(s); i++ { + if m1[s[i]-'a'] != m2[t[i]-'a'] { + return false + } + + m1[s[i]-'a'] = i + 1 + m2[t[i]-'a'] = i + 1 + } + + return true +} diff --git a/Week 08/id_011/reverse-only-letters.go b/Week 08/id_011/reverse-only-letters.go new file mode 100644 index 000000000..37a3d91e8 --- /dev/null +++ b/Week 08/id_011/reverse-only-letters.go @@ -0,0 +1,23 @@ +package algorithm00401 + +func reverseOnlyLetters(S string) string { + b := []byte(S) + + for l, r := 0, len(b)-1; l < r; { + for l < r && !isBetter(b[l]) { + l++ + } + for l < r && !isBetter(b[r]) { + r-- + } + b[l], b[r] = b[r], b[l] + l++ + r-- + } + + return string(b) +} + +func isBetter(b byte) bool { + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') +} diff --git a/Week 08/id_011/reverse-string-ii.go b/Week 08/id_011/reverse-string-ii.go new file mode 100644 index 000000000..8087ea1e7 --- /dev/null +++ b/Week 08/id_011/reverse-string-ii.go @@ -0,0 +1,26 @@ +package algorithm00401 + +func reverseStr(s string, k int) string { + b := []byte(s) + for i := 0; i < len(s); i++ { + j := minInt(i+k, len(s)) + reverse(b[i:j]) + } + return string(b) +} + +func minInt(i, j int) int { + if i < j { + return i + } + return j +} + +func reverse(b []byte) { + i, j := 0, len(b)-1 + for i < j { + b[i], b[j] = b[j], b[i] + i++ + j-- + } +} diff --git a/Week 08/id_016/LeetCode_15_016.js b/Week 08/id_016/LeetCode_15_016.js new file mode 100644 index 000000000..69f322810 --- /dev/null +++ b/Week 08/id_016/LeetCode_15_016.js @@ -0,0 +1,63 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-19 10:09:38 + * @LastEditTime: 2019-10-19 15:40:33 +1.暴力破解 3层循环 O(n^3) -- 存在执行时间过长的问题 +2.模拟两数之和-双指针进行求解O(n^2) -- 代码过于冗余 +3.参考网上代码进行修复O(n^2) -- 修复了数组重复的问题,优化代码18行 + */ +/* + * @lc app=leetcode id=15 lang=javascript + * + * [15] 3Sum + */ +// @lc code=start +/** + * @param {number[]} nums + * @return {number[][]} + */ +// var threeSum = function(nums) { +// let length = nums.length; +// let arr = []; +// let map = new Map(); +// for (let i = 0; i < length - 2; i++) { +// for (let j = i + 1; j < length - 1; j++) { +// for (let k = j + 1; k < length; k++) { +// if (nums[i] + nums[j] + nums[k] === 0) { +// arr.push([nums[i], nums[j], nums[k]]); +// } +// } +// } +// } +// arr.forEach(item => { +// item.sort((a, b) => a - b); +// map.set(item.join(), item); +// }); +// return Array.from(map.values()); +// }; +var threeSum = function(nums) { + nums.sort((a, b) => a - b); + let arr = []; + for (let i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + for (let l = i + 1, r = nums.length - 1; l < r; ) { + let sum = nums[i] + nums[l] + nums[r]; + if (sum === 0) { + arr.push([nums[i], nums[l++], nums[r--]]); + while (l < r && nums[l] === nums[l - 1]) l++; + while (l < r && nums[r] === nums[r + 1]) r--; + } else if (sum < 0) { + l++; + } else if (sum > 0) { + r--; + } + } + } + return arr; +}; +// @lc code=end +// console.log(threeSum([0, 0, 0, 0])); +console.log(threeSum([-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6])); +// console.log(threeSum([-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6])); diff --git a/Week 08/id_016/LeetCode_58_016.js b/Week 08/id_016/LeetCode_58_016.js new file mode 100644 index 000000000..e0d5c05e9 --- /dev/null +++ b/Week 08/id_016/LeetCode_58_016.js @@ -0,0 +1,57 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-12-08 22:17:13 + * @LastEditTime: 2019-12-08 22:17:19 + */ +/* + * @lc app=leetcode id=58 lang=javascript + * + * [58] Length of Last Word + * + * https://leetcode.com/problems/length-of-last-word/description/ + * + * algorithms + * Easy (32.32%) + * Likes: 476 + * Dislikes: 1959 + * Total Accepted: 316.3K + * Total Submissions: 977.5K + * Testcase Example: '"Hello World"' + * + * Given a string s consists of upper/lower-case alphabets and empty space + * characters ' ', return the length of last word in the string. + * + * If the last word does not exist, return 0. + * + * Note: A word is defined as a character sequence consists of non-space + * characters only. + * + * Example: + * + * + * Input: "Hello World" + * Output: 5 + * + * + * + * + */ + +// @lc code=start +/** + * @param {string} s + * @return {number} + */ +var lengthOfLastWord = function(s) { + let res = 0; + s = s.replace(/\s+$/g, ""); + for (let i = s.length - 1; i >= 0; i--) { + if (s[i] === " ") break; + res++; + } + return res; +}; +// @lc code=end + diff --git a/Week 08/id_016/LeetCode_709_016.js b/Week 08/id_016/LeetCode_709_016.js new file mode 100644 index 000000000..9663f5359 --- /dev/null +++ b/Week 08/id_016/LeetCode_709_016.js @@ -0,0 +1,88 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-12-08 21:21:08 + * @LastEditTime: 2019-12-08 21:21:24 + */ +/* + * @lc app=leetcode id=709 lang=javascript + * + * [709] To Lower Case + * + * https://leetcode.com/problems/to-lower-case/description/ + * + * algorithms + * Easy (77.72%) + * Likes: 360 + * Dislikes: 1250 + * Total Accepted: 165.5K + * Total Submissions: 211.9K + * Testcase Example: '"Hello"' + * + * Implement function ToLowerCase() that has a string parameter str, and + * returns the same string in lowercase. + * + * + * + * + * Example 1: + * + * + * Input: "Hello" + * Output: "hello" + * + * + * + * Example 2: + * + * + * Input: "here" + * Output: "here" + * + * + * + * Example 3: + * + * + * Input: "LOVELY" + * Output: "lovely" + * + * + * + * + */ + +// @lc code=start +/** + * @param {string} str + * @return {string} + */ +// [a,z] = [97,122] +// [A,Z] = [65,90] +// var toLowerCase = function(str) { +// let res = ""; +// let code; +// for(let i = 0; i < str.length; i++){ +// code = str.charCodeAt(i); +// if(code>=65 && code <= 90){ +// res += String.fromCharCode(code+32); +// continue; +// } +// res += str[i]; +// } +// return res; +// }; + +// 大写变小写、小写变大写 : ASCII码 ^= 32 +// 大写变小写、小写变小写 : ASCII码 |= 32 +// 小写变大写、大写变大写 : ASCII码 &= -33 +var toLowerCase = function(str) { + let res = ""; + for(let i = 0; i < str.length; i++){ + res += String.fromCharCode(str.charCodeAt(i) | 32); + } + return res; +}; +// @lc code=end + diff --git a/Week 07/id_651/NOTE.md b/Week 08/id_016/NOTE.md old mode 100644 new mode 100755 similarity index 100% rename from Week 07/id_651/NOTE.md rename to Week 08/id_016/NOTE.md diff --git a/Week 08/id_021/NOTE.md b/Week 08/id_021/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_021/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_021/algorithm.zip b/Week 08/id_021/algorithm.zip new file mode 100644 index 000000000..ce0f0e0e7 Binary files /dev/null and b/Week 08/id_021/algorithm.zip differ diff --git a/Week 08/id_026/NOTE.md b/Week 08/id_026/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_026/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_031/NOTE.md b/Week 08/id_031/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_031/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_036/NOTE.md b/Week 08/id_036/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_036/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_041/NOTE.md b/Week 08/id_041/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_041/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_046/LeetCode_151_046.java b/Week 08/id_046/LeetCode_151_046.java new file mode 100644 index 000000000..c20aebc01 --- /dev/null +++ b/Week 08/id_046/LeetCode_151_046.java @@ -0,0 +1,19 @@ +class Solution { + public String reverseWords(String s) { + String emptyStr=" "; + final String[] words = s.trim().split(emptyStr); + StringBuilder sb=new StringBuilder(); + for (int i = words.length - 1; i >= 0; i--) { + String str=words[i]; + while (str.contains(emptyStr)){ + str=str.replaceAll(emptyStr,""); + } + if ("".equals(str)){ + continue; + } + sb.append(str).append(emptyStr); + } + return sb.toString().trim(); + + } +} \ No newline at end of file diff --git a/Week 08/id_046/LeetCode_300_046.java b/Week 08/id_046/LeetCode_300_046.java new file mode 100644 index 000000000..01131d440 --- /dev/null +++ b/Week 08/id_046/LeetCode_300_046.java @@ -0,0 +1,21 @@ +public class Solution { + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int res = 1; + for (int i = 1; i < dp.length; i++) { + int maxval = 0; + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + maxval = Math.max(maxval, dp[j]); + } + } + dp[i] = maxval +1; + res = Math.max(res, dp[i]); + } + return res; + } +} diff --git a/Week 08/id_046/LeetCode_387_046.java b/Week 08/id_046/LeetCode_387_046.java new file mode 100644 index 000000000..e80d36d6f --- /dev/null +++ b/Week 08/id_046/LeetCode_387_046.java @@ -0,0 +1,13 @@ +class Solution { + public int firstUniqChar(String s) { + Map count = new HashMap<>(); + for(int i =0;i < s.length();i++){ + char c = s.charAt(i); + count.put(c, count.getOrDefault(c, 0) + 1); + } + for(int i =0;i < s.length();i++){ + if(count.get(s.charAt(i)) == 1) return i; + } + return -1; + } +} \ No newline at end of file diff --git a/Week 08/id_046/NOTE.md b/Week 08/id_046/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_046/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_051/NOTE.md b/Week 08/id_051/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_051/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_056/NOTE.md b/Week 08/id_056/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_056/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_061/LeetCode_151_601.java b/Week 08/id_061/LeetCode_151_601.java new file mode 100644 index 000000000..b5f676865 --- /dev/null +++ b/Week 08/id_061/LeetCode_151_601.java @@ -0,0 +1,12 @@ +class Solution { + public String reverseWords(String s) { + String[] arr = s.split(" "); + StringBuffer b = new StringBuffer(); + for (int i=arr.length-1;i>=0;i--){ + if(!arr[i].equals("")) { + b.append(arr[i]).append(" "); + } + } + return b.toString().trim(); + } +} diff --git a/Week 08/id_061/LeetCode_387_601.java b/Week 08/id_061/LeetCode_387_601.java new file mode 100644 index 000000000..0dd7fcd22 --- /dev/null +++ b/Week 08/id_061/LeetCode_387_601.java @@ -0,0 +1,11 @@ +class Solution { + public int firstUniqChar(String s) { + int[] l = new int[26]; + for (char c:s.toCharArray()) + l[c - 'a']++; + for (int i = 0; i math.MaxInt32 { + return math.MaxInt32 + }else if result*sign < -math.MaxInt32 - 1 { + return -math.MaxInt32 - 1 + } + }else{ + break + } + } + return result*sign +} \ No newline at end of file diff --git a/Week 08/id_071/LeetCode_091_071.go b/Week 08/id_071/LeetCode_091_071.go new file mode 100644 index 000000000..dc527e277 --- /dev/null +++ b/Week 08/id_071/LeetCode_091_071.go @@ -0,0 +1,32 @@ +package week08 + +import "strconv" + +//1.2 https://leetcode-cn.com/problems/decode-ways/ +func numDecodings(s string) int { + + if s == "0" { + return 0 + } + + if len(s) <= 1 { + return 1 + } + + dp := make([]int, len(s)+1) + dp[0], dp[1] = 1, 1 + if s[0] == '0' { + dp[1] = 0 + } + for i := 2; i <= len(s); i++ { + if signle, _ := strconv.Atoi(s[i-1: i]); signle > 0 { + dp[i] = dp[i-1] + } + + if double, _ := strconv.Atoi(s[i-2: i]);double >= 10 && double <= 26 { + dp[i] += dp[i-2] + } + } + + return dp[len(s)] +} \ No newline at end of file diff --git a/Week 08/id_071/LeetCode_300_071.go b/Week 08/id_071/LeetCode_300_071.go new file mode 100644 index 000000000..11225f10e --- /dev/null +++ b/Week 08/id_071/LeetCode_300_071.go @@ -0,0 +1,37 @@ +package week08 + +//1.1 https://leetcode-cn.com/problems/longest-increasing-subsequence/ +func lengthOfLIS(nums []int) int { + + if len(nums) == 1 { + return 1 + } + + if len(nums) == 0 { + return 0 + } + + dp := make([]int, len(nums)) + + for i := 0; i < len(nums); i++ { + dp[i] = 1 + } + + max := 1 + for i := 1; i < len(nums); i++ { + for j := 0; j < i; j++ { + curProblem := dp[i] + if nums[i] > nums[j] { + if dp[j]+1 > curProblem { + dp[i]++ + curProblem := dp[i] + if max < curProblem { + max = curProblem + } + } + } + } + } + + return max +} diff --git a/Week 08/id_071/LeetCode_387_071.go b/Week 08/id_071/LeetCode_387_071.go new file mode 100644 index 000000000..34c1e213c --- /dev/null +++ b/Week 08/id_071/LeetCode_387_071.go @@ -0,0 +1,19 @@ +package week08 + +//2.1 https://leetcode-cn.com/problems/first-unique-character-in-a-string/ +func firstUniqChar(s string) int { + if len(s) < 1 { + return 0 + } + var m = make(map[string]int) + for i := 0; i < len(s); i++ { + m[string(s[i])] ++ + } + + for j := 0; j < len(s); j++ { + if m[string(s[j])] == 1 { + return j + } + } + return -1 +} \ No newline at end of file diff --git a/Week 08/id_071/LeetCode_541_071.go b/Week 08/id_071/LeetCode_541_071.go new file mode 100644 index 000000000..dde7786ed --- /dev/null +++ b/Week 08/id_071/LeetCode_541_071.go @@ -0,0 +1,23 @@ +package week08 + +// 2.3 https://leetcode-cn.com/problems/reverse-string-ii/ +func reverseStr(s string, k int) string { + + res := []byte(s) + for i := 0; i < len(s); i = i + 2*k { + if i + k < len(res){ + reverse(res[i : i+k]) + }else{ + reverse(res[i:]) + } + } + return string(res) +} + +func reverse(b []byte){ + l, r := 0, len(b) - 1 + for l < r { + b[l], b[r] = b[r], b[l] + l, r = l+1, r+1 + } +} \ No newline at end of file diff --git a/Week 08/id_071/NOTE.md b/Week 08/id_071/NOTE.md new file mode 100755 index 000000000..412780418 --- /dev/null +++ b/Week 08/id_071/NOTE.md @@ -0,0 +1,86 @@ +# NOTE + +> 高级动态规划 + +##### 基础概念 + + 找到重复子问题 + + 递归 + + 分治 + + 动态规划(动态递推) = 分治 + 最优子结构 + + dp状态定义 dp := map[string]int + dp状态转移方程 func + +##### 实战题目 + + 70 爬楼梯 f(n) = f(n-1) + f(n-2) + + 换硬币 + + 62 不同路径 f(x, y) = f(x-1, y) + f(x, y-1) + + 198 打家劫舍 + dp[i] = max(dp[i- 2] + nums[i], dp[i- 1]) + + dp[i][0] = max(dp[i-1][0], dp[i- 1][1]) //没偷 i + dp[i][1] = dp[i- 1][0] + nums[i] //偷了 i + + 64 最小路径和 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + A[i][j] + + 121 股票买卖 + 今天没有持有股票 + dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + price[i]) + + 今天持有股票 + dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]) + +##### 高级DP + + 复杂度: + 1 状态拥有更多为维度 + 2 状态方程更加复杂 + + + 爬楼梯 + + 746 使用最小花费爬楼梯 + + 编辑距离 + dp[i][j] word1.substr(0,i) 到 word2.substr(0,j)的距离 + + w1 ....x i + w2 ...y j + if w1[i] == w2[j] { + edit_dist(i, j) = edit_dist(i-1, j-1) + 1 + } else { + edit_dist(i, j) = Min(edit_dist(i-1, j-1) + 1, edit_dist(i-1, j) + 1, edit_dist(i, j-1) + 1) + } + +**** + +> 字符串算法 + +##### 基础知识 golang + + 声明 var s := "string" //immutable 线程安全 + 遍历 for + 比较 equal + + 异位词 + 回文词 + +##### 最长子串(无间隔)、子序列(有间隔) + + longest common sequence + + longest common substring + + edit distance + + longest palindromic substring + + P(i,j) = ( P(i+1, j-1) && s[i] == s[j] ) \ No newline at end of file diff --git a/Week 08/id_076/NOTE.md b/Week 08/id_076/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_076/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_081/LongestIncreasingSubsequence.java b/Week 08/id_081/LongestIncreasingSubsequence.java new file mode 100644 index 000000000..bbed04a8d --- /dev/null +++ b/Week 08/id_081/LongestIncreasingSubsequence.java @@ -0,0 +1,15 @@ +class LongestIncreasingSubsequence { + public int lengthOfLIS(int[] nums) { + if(nums.length == 0) return 0; + int[] dp = new int[nums.length]; + int res = 0; + Arrays.fill(dp, 1); + for(int i = 0; i < nums.length; i++) { + for(int j = 0; j < i; j++) { + if(nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1); + } + res = Math.max(res, dp[i]); + } + return res; + } +} diff --git a/Week 08/id_081/MaximalRectangle.java b/Week 08/id_081/MaximalRectangle.java new file mode 100644 index 000000000..30c3f399b --- /dev/null +++ b/Week 08/id_081/MaximalRectangle.java @@ -0,0 +1,62 @@ +class MaximalRectangle { + public int maximalRectangle(char[][] matrix) { + if(matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0; + + int row = matrix.length; + int col = matrix[0].length; + + int[][] diagram = new int[row][col]; + for (int i = 0; i < row; ++i) + for (int j = 0; j < col; ++j) { + if (i == 0) { + diagram[i][j] = matrix[i][j] == '1' ? 1 : 0; + } else { + diagram[i][j] = matrix[i][j] == '1' ? diagram[i - 1][j] + 1: 0; + } + } + + int maxArea = 0; + for(int i = 0; i < row; ++i) { + int partMax = largestRectangleArea(diagram[i]); + maxArea = Math.max(partMax, maxArea); + } + + return maxArea; + } + + + public int largestRectangleArea(int[] height) { + if (height == null || height.length == 0) + return 0; + + int[] lessFromLeft = new int[height.length]; + int[] lessFromRight = new int[height.length]; + lessFromRight[height.length - 1] = height.length; + lessFromLeft[0] = -1; + + for (int i = 1; i < height.length; i++) { + int p = i - 1; + + while (p >= 0 && height[p] >= height[i]) { + p = lessFromLeft[p]; + } + lessFromLeft[i] = p; + } + + for (int i = height.length - 2; i >= 0; i--) { + int p = i + 1; + + while (p < height.length && height[p] >= height[i]) { + p = lessFromRight[p]; + } + lessFromRight[i] = p; + } + + int maxArea = 0; + for (int i = 0; i < height.length; i++) { + maxArea = Math.max(maxArea, height[i] * (lessFromRight[i] - lessFromLeft[i] - 1)); + } + + return maxArea; + } +} diff --git a/Week 08/id_081/NOTE.md b/Week 08/id_081/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_081/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_086/LeetCode_205_086.java b/Week 08/id_086/LeetCode_205_086.java new file mode 100644 index 000000000..5248a5e90 --- /dev/null +++ b/Week 08/id_086/LeetCode_205_086.java @@ -0,0 +1,16 @@ +/** + * 205. 同构字符串 + */ + class Solution { + public boolean isIsomorphic(String s, String t) { + if(s.length() != t.length()) return false; + char[] schars = s.toCharArray(); + char[] tchars = t.toCharArray(); + for (int i = 0; i < s.length(); i++) { + if (s.indexOf(schars[i]) != t.indexOf(tchars[i])) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week 08/id_086/LeetCode_387_086.java b/Week 08/id_086/LeetCode_387_086.java new file mode 100644 index 000000000..9a4a986c6 --- /dev/null +++ b/Week 08/id_086/LeetCode_387_086.java @@ -0,0 +1,16 @@ +/** + * 387. 字符串中的第一个唯一字符 + */ +class Solution { + public int firstUniqChar(String s) { + int[] letters = new int[26]; + for (char c:s.toCharArray()) { + letters[c-'a']++; + } + for (int i=0;i letters = new Stack<>(); + for (char c : S.toCharArray()) { + if (Character.isLetter(c)) { + letters.push(c); + } + } + StringBuilder ans = new StringBuilder(); + for (char c : S.toCharArray()) { + if (Character.isLetter(c)) { + ans.append(letters.pop()); + } else { + ans.append(c); + } + } + return ans.toString(); + } +} \ No newline at end of file diff --git a/Week 08/id_086/NOTE.md b/Week 08/id_086/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_086/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_091/LeetCode_151_091.py b/Week 08/id_091/LeetCode_151_091.py new file mode 100644 index 000000000..a1399bff6 --- /dev/null +++ b/Week 08/id_091/LeetCode_151_091.py @@ -0,0 +1,18 @@ +class Solution: + def reverseWords(self, s: str) -> str: + s = s.strip() + res = "" + i, j = len(s) - 1, len(s) + while i > 0: + if s[i] == ' ': + res += s[i + 1: j] + ' ' + while s[i] == ' ': i -= 1 + j = i + 1 + i -= 1 + return res + s[:j] + + +if __name__ == "__main__": + solution = Solution() + res = solution.reverseWords(" hello world ") + print(res) diff --git a/Week 08/id_091/LeetCode_300_091.py b/Week 08/id_091/LeetCode_300_091.py new file mode 100644 index 000000000..2f198cea5 --- /dev/null +++ b/Week 08/id_091/LeetCode_300_091.py @@ -0,0 +1,18 @@ +from typing import List + + +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + if not nums: return 0 + dp = [1] * len(nums) + for i in range(len(nums)): + for j in range(i): + if nums[j] < nums[i]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) + + +if __name__ == "__main__": + solution = Solution() + res = solution.lengthOfLIS([4, 5, 5, 4, 20, 19, 30, 21, 20]) + print(res) diff --git a/Week 08/id_091/LeetCode_557_091.py b/Week 08/id_091/LeetCode_557_091.py new file mode 100644 index 000000000..7e4888bfb --- /dev/null +++ b/Week 08/id_091/LeetCode_557_091.py @@ -0,0 +1,9 @@ +class Solution: + def reverseWords(self, s: str) -> str: + return ' '.join(s.split(' ')[::-1])[::-1] + + +if __name__ == "__main__": + solution = Solution() + res = solution.reverseWords("hello world, it's me") + print(res) diff --git a/Week 08/id_091/LeetCode_8_091.py b/Week 08/id_091/LeetCode_8_091.py new file mode 100644 index 000000000..1d89c16b1 --- /dev/null +++ b/Week 08/id_091/LeetCode_8_091.py @@ -0,0 +1,13 @@ +import re +from typing import List + + +class Solution: + def myAtoi(self, str: str) -> int: + return min(max(int(*re.findall('^[\+\-]?\d+', str.strip())), -2 ** 31), 2 ** 31 - 1) + + +if __name__ == "__main__": + solution = Solution() + res = solution.myAtoi(' 420') + print(res) diff --git a/Week 08/id_091/NOTE.md b/Week 08/id_091/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_091/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_096/NOTE.md b/Week 08/id_096/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_096/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_101/NOTE.md b/Week 08/id_101/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_101/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_106/LeetCode_10_106.java b/Week 08/id_106/LeetCode_10_106.java new file mode 100644 index 000000000..76aec2f12 --- /dev/null +++ b/Week 08/id_106/LeetCode_10_106.java @@ -0,0 +1,148 @@ +/* + * @lc app=leetcode id=10 lang=java + * + * [10] Regular Expression Matching + * + * https://leetcode.com/problems/regular-expression-matching/description/ + * + * algorithms + * Hard (25.81%) + * Likes: 3331 + * Dislikes: 611 + * Total Accepted: 364.7K + * Total Submissions: 1.4M + * Testcase Example: '"aa"\n"a"' + * + * Given an input string (s) and a pattern (p), implement regular expression + * matching with support for '.' and '*'. + * + * + * '.' Matches any single character. + * '*' Matches zero or more of the preceding element. + * + * + * The matching should cover the entire input string (not partial). + * + * Note: + * + * + * s could be empty and contains only lowercase letters a-z. + * p could be empty and contains only lowercase letters a-z, and characters + * like . or *. + * + * + * Example 1: + * + * + * Input: + * s = "aa" + * p = "a" + * Output: false + * Explanation: "a" does not match the entire string "aa". + * + * + * Example 2: + * + * + * Input: + * s = "aa" + * p = "a*" + * Output: true + * Explanation: '*' means zero or more of the preceding element, 'a'. + * Therefore, by repeating 'a' once, it becomes "aa". + * + * + * Example 3: + * + * + * Input: + * s = "ab" + * p = ".*" + * Output: true + * Explanation: ".*" means "zero or more (*) of any character (.)". + * + * + * Example 4: + * + * + * Input: + * s = "aab" + * p = "c*a*b" + * Output: true + * Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, + * it matches "aab". + * + * + * Example 5: + * + * + * Input: + * s = "mississippi" + * p = "mis*is*p*." + * Output: false + * + * + */ + +// @lc code=start +class Solution { + public boolean isMatch(String s, String p) { + boolean[][] dp = new boolean[s.length()+1][p.length()+1]; + dp[0][0]=true; + for(int i = 1; i <= s.length(); i++){//不必要,boolean默认都是false + dp[i][0]=false; + } + for(int j = 1; j <= p.length(); j++){ + dp[0][j]=false; + if(p.charAt(j-1) == '*'){ + dp[0][j] = dp[0][j-2]; + } + } + for(int i=1;i<=s.length();i++){ + for(int j=1;j<=p.length();j++){ + if(p.charAt(j-1)==s.charAt(i-1)||p.charAt(j-1)=='.'){ + dp[i][j] = dp[i-1][j-1]; + }else if(p.charAt(j-1)=='*'){ + dp[i][j] = dp[i][j-2]; + if(p.charAt(j-2)==s.charAt(i-1)||p.charAt(j-2) == '.'){ + dp[i][j] = dp[i][j] | dp[i-1][j]; + } + }else{ + dp[i][j]=false; + } + } + } + return dp[s.length()][p.length()]; + } +} +// @lc code=end +/** + * .代表匹配任意单个字符 + * *代表匹配0-n个前面的那一个元素 + * 即b* 可以是0 也可以是[1..n)个b + * 用dp[i][j]表示s p两个字符串每个位置匹配的状态 + * 1 p与s当前位置字符相同 p.charAt(j)==s.charAt(i) 则dp[i][j] = dp[i-1][j-1] + * 2 p 当前位置是. p.charAt(j)=='.' 无论s是什么字符一定匹配 dp[i][j] = dp[i-1][j-1]; + * 3 p 当前位置是* p.charAt(j)=='*' + * 3.1 根据*的定义 p.charAt(j-1)* == 0时(出现0次) 可以直接抹掉只需要考虑p.charAt(j-2) 则dp[i][j] = dp[i][j-2] + * 3.2 p.charAt(j-1)* == [1..n) (出现1-n次) + * 此时当p.charAt(j-1)==s.charAt(i) 或者 p.charAt(j-1) == '.'说明s.charAt(i)属于p.charAt(j-1)*的一部分,可以抹掉只考虑s.charAt(i-1) 则dp[i][j] = dp[i-1][j] + * 这里要注意的部分是s.charAt(i)属于p.charAt(j-1)*的一部分,是否抹掉对值不影响,dp[i][j] = dp[i][j] | dp[i-1][j] + * 4 p.charAt(j)!=s.charAt(i) dp[i][j]=false + * + * + * 总结以上状态转移方程有3种 + * dp[i][j] = dp[i-1][j-1] + * dp[i][j] = dp[i-1][j] + * dp[i][j] = dp[i][j-2] + * 或者false + * + '' x a * b . c +'' T F F F F F F +x F T F T F F F +a F F T T F F F +a F F F T F F F +b F F F F T F F +y F F F F F T F +c F F F F F F T + */ diff --git a/Week 08/id_106/LeetCode_1143_106.java b/Week 08/id_106/LeetCode_1143_106.java new file mode 100644 index 000000000..1d0f1bc74 --- /dev/null +++ b/Week 08/id_106/LeetCode_1143_106.java @@ -0,0 +1,92 @@ +/* + * @lc app=leetcode id=1143 lang=java + * + * [1143] Longest Common Subsequence + * + * https://leetcode.com/problems/longest-common-subsequence/description/ + * + * algorithms + * Medium (57.21%) + * Likes: 335 + * Dislikes: 8 + * Total Accepted: 19.8K + * Total Submissions: 34.6K + * Testcase Example: '"abcde"\n"ace"' + * + * Given two strings text1 and text2, return the length of their longest common + * subsequence. + * + * A subsequence of a string is a new string generated from the original string + * with some characters(can be none) deleted without changing the relative + * order of the remaining characters. (eg, "ace" is a subsequence of "abcde" + * while "aec" is not). A common subsequence of two strings is a subsequence + * that is common to both strings. + * + * + * + * If there is no common subsequence, return 0. + * + * + * Example 1: + * + * + * Input: text1 = "abcde", text2 = "ace" + * Output: 3 + * Explanation: The longest common subsequence is "ace" and its length is 3. + * + * + * Example 2: + * + * + * Input: text1 = "abc", text2 = "abc" + * Output: 3 + * Explanation: The longest common subsequence is "abc" and its length is 3. + * + * + * Example 3: + * + * + * Input: text1 = "abc", text2 = "def" + * Output: 0 + * Explanation: There is no such common subsequence, so the result is 0. + * + * + * + * Constraints: + * + * + * 1 <= text1.length <= 1000 + * 1 <= text2.length <= 1000 + * The input strings consist of lowercase English characters only. + * + * + */ + +// @lc code=start +class Solution { + public int longestCommonSubsequence(String text1, String text2) { + int[][] dp = new int[text1.length()+1][text2.length()+1]; + for(int i = 0;i < text1.length(); i++){ + for(int j = 0; j< text2.length(); j++){ + // System.out.println("i: "+i+", j: "+j); + if(text1.charAt(i) == text2.charAt(j)) dp[i+1][j+1] = dp[i][j] + 1; + else dp[i+1][j+1] = Math.max(dp[i+1][j],dp[i][j+1]); + } + } + return dp[text1.length()][text2.length()]; + } +} +// @lc code=end +/* + M K O I R +M 0 +O 1 2 +R 2 2 +E 2 2 + +a[i][j] +if char equals +f[i+1][j+1] = f[i][j] + 1; +else +f[i+1][j+1] = Math.Max(f[i+1][j],f[i][j+1]) + */ diff --git a/Week 08/id_106/LeetCode_64_106.java b/Week 08/id_106/LeetCode_64_106.java new file mode 100644 index 000000000..3217510a0 --- /dev/null +++ b/Week 08/id_106/LeetCode_64_106.java @@ -0,0 +1,65 @@ +/* + * @lc app=leetcode id=64 lang=java + * + * [64] Minimum Path Sum + * + * https://leetcode.com/problems/minimum-path-sum/description/ + * + * algorithms + * Medium (49.00%) + * Likes: 1762 + * Dislikes: 45 + * Total Accepted: 276.9K + * Total Submissions: 560.6K + * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' + * + * Given a m x n grid filled with non-negative numbers, find a path from top + * left to bottom right which minimizes the sum of all numbers along its path. + * + * Note: You can only move either down or right at any point in time. + * + * Example: + * + * + * Input: + * [ + * [1,3,1], + * ⁠ [1,5,1], + * ⁠ [4,2,1] + * ] + * Output: 7 + * Explanation: Because the path 1→3→1→1→1 minimizes the sum. + * + * + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + int[][] dp = grid.clone(); + for(int i=1;i rorse (replace 'h' with 'r') + * rorse -> rose (remove 'r') + * rose -> ros (remove 'e') + * + * + * Example 2: + * + * + * Input: word1 = "intention", word2 = "execution" + * Output: 5 + * Explanation: + * intention -> inention (remove 't') + * inention -> enention (replace 'i' with 'e') + * enention -> exention (replace 'n' with 'x') + * exention -> exection (replace 'n' with 'c') + * exection -> execution (insert 'u') + * + * + */ + +// @lc code=start +class Solution { + public int minDistance(String word1, String word2) { + int s1 = word1.length(); + int s2 = word2.length(); + int[][] dp = new int[s1+1][s2+1]; + for (int i=1;i<=s1;i++){ + dp[i][0] = i; + } + for(int j=1;j<=s2;j++){ + dp[0][j] = j; + } + for (int i=1;i<=s1;i++){ + for(int j=1;j<=s2;j++){ + if(word1.charAt(i-1)==word2.charAt(j-1)){ + dp[i][j] = dp[i-1][j-1]; + }else{ + dp[i][j] = Math.min(Math.min(dp[i-1][j-1], dp[i-1][j]),dp[i][j-1])+1; + } + } + } + return dp[s1][s2]; + } +} +// @lc code=end + +/** + * 使用数学归纳法和DP + * 要将word1[0..i) 转化为 word2[0..j) 假设这个编辑的最小步数是dp[i][j] + * 1 当word1或者word2的长度为0时,从一个单词向其转化需要的步数就是这个单词的长度dp[i][0]=i dp[0][j]=j + * 2 假设已经知道word1[0..i-1)到word2[0..j-1)的最短路径 dp[i-1][j-1] + * 此时如果word1[i-1]=word2[j-1]那么不会再有变化的操作,则dp[i][j] = dp[i-1][j-1] + * 此时如果word1[i-1]!=word2[j-1]那么根据三种可选操作有以下情况 + * 2.1 replace 用word2[j-1]替换word1[i-1] 使得word1[i-1]=word2[j-1] ==>dp[i][j] = dp[i-1][j-1]+1 + * 2.2 delete 如果word1[0..i-1) 和 word2[0..j)相同,那么就将word1[i-1]删掉 ==>dp[i][j] = dp[i-1][j]+1 + * 2.3 insert 如果word1[0..i-1)+word[j-1] 和 word2[0..j)相同,那么就将word1[0..i)后加上word2[j-1] ==>dp[i][j] = dp[i][j-1]+1 + * 在上述三种情况中选取最小的情况 + */ diff --git a/Week 08/id_106/NOTE.md b/Week 08/id_106/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_106/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_111/NOTE.md b/Week 08/id_111/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_111/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_116/NOTE.md b/Week 08/id_116/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_116/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_121/NOTE.md b/Week 08/id_121/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_121/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_126/NOTE.md b/Week 08/id_126/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_126/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_131/LeetCode_300_131.java b/Week 08/id_131/LeetCode_300_131.java new file mode 100644 index 000000000..d6eb0aa05 --- /dev/null +++ b/Week 08/id_131/LeetCode_300_131.java @@ -0,0 +1,30 @@ +package com.lzhlyle.leetcode.recite.no300; + +import java.util.Arrays; + +public class LongestIncreasingSubsequence_2 { + // dp O(n^2) + public int lengthOfLIS(int[] nums) { + // base condition + if (nums == null) return 0; + if (nums.length < 2) return nums.length; + + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int max = 1; + for (int i = 1; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1); + } + max = Math.max(max, dp[i]); + } + + return max; + } + + public static void main(String[] args) { + int[] nums = {10, 9, 2, 5, 3, 4}; + int res = new LongestIncreasingSubsequence_2().lengthOfLIS(nums); + System.out.println(res); + } +} diff --git a/Week 08/id_131/LeetCode_387_131.java b/Week 08/id_131/LeetCode_387_131.java new file mode 100644 index 000000000..fbefc327d --- /dev/null +++ b/Week 08/id_131/LeetCode_387_131.java @@ -0,0 +1,21 @@ +package com.lzhlyle.leetcode.recite.no387; + +public class FirstUniqueCharacterInAString_2 { + public int firstUniqChar(String s) { + // base condition + if (s == null || s.length() < 1) return -1; + + int[] counts = new int[26]; + + char[] chars = s.toCharArray(); + for (int i = 0; i < chars.length; i++) { + counts[chars[i] - 'a'] += 1; + } + + for (int i = 0; i < chars.length; i++) { + if (counts[chars[i] - 'a'] == 1) return i; + } + + return -1; + } +} diff --git a/Week 08/id_131/NOTE.md b/Week 08/id_131/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_131/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_136/NOTE.md b/Week 08/id_136/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_136/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_141/LeetCode_300_141.swift b/Week 08/id_141/LeetCode_300_141.swift new file mode 100644 index 000000000..1d0ca0b41 --- /dev/null +++ b/Week 08/id_141/LeetCode_300_141.swift @@ -0,0 +1,41 @@ +// +// DecodeWays.swift +// algorithm +// +// Created by pingan on 2019/12/5. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation + +class DecodeWays { + func numDecodings(_ s: String) -> Int { + if s.count == 0 { + return 0; + } + let len = s.count; + var dp = Array(repeating: 0, count: len + 1); + dp[len] = 1; + let arr = Array(s); + if arr[len - 1] == "0" { + dp[len - 1] = 0; + } else { + dp[len - 1] = 1; + } + if len < 2 { + return arr.first == "0" ? 0 : 1; + } + for i in (0...len-2).reversed() { + if arr[i] == "0" { + dp[i] = 0; + continue; + } + if Int(String(arr[i]))! * 10 + Int(String(arr[i + 1]))! <= 26 { + dp[i] = dp[i + 1] + dp[i + 2]; + } else { + dp[i] = dp[i + 1]; + } + } + return dp[0]; + } +} diff --git a/Week 08/id_141/LeetCode_91_141.swift b/Week 08/id_141/LeetCode_91_141.swift new file mode 100644 index 000000000..56d85b085 --- /dev/null +++ b/Week 08/id_141/LeetCode_91_141.swift @@ -0,0 +1,29 @@ +// +// LengthOfLIS.swift +// algorithm +// +// Created by pingan on 2019/12/5. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation + +class LengthOfLIS { + func lengthOfLIS(_ nums: [Int]) -> Int { + if nums.count == 0 { + return 0; + } + var dp: [Int] = Array(repeating: 1, count: nums.count); + var res = 0; + + for i in 0..> dp(t.size() + 1, vector(s.size() + 1, 0)); + for (int i = 0; i < s.size(); ++i) { + dp[0][i] = 1; + } + + for (int i = 0; i < t.size(); ++i) { + for (int j = 0; j < s.size(); ++j) { + if (t[i] == s[j]) { + dp[i + 1][j + 1] = dp[i][j] + dp[i + 1][j]; + } else { + dp[i + 1][j + 1] = dp[i + 1][j]; + } + } + } + + return dp[t.size()][s.size()]; + } +}; diff --git a/Week 08/id_151/LeetCode_300_151.cpp b/Week 08/id_151/LeetCode_300_151.cpp new file mode 100644 index 000000000..b78bab62a --- /dev/null +++ b/Week 08/id_151/LeetCode_300_151.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int lengthOfLIS(vector& nums) { + if (nums.empty()) + return 0; + + vector dp(nums.size(), 1); + int res = 1; + + for (int i = 1; i < nums.size(); ++i) { + int m = 0; + for (int j = 0; j < i; ++j) { + if (nums[i] > nums[j]) + m = max(m, dp[j]); + } + + dp[i] = m + 1; + res = max(res, dp[i]); + } + + return res; + } +}; diff --git a/Week 08/id_151/LeetCode_32_151.cpp b/Week 08/id_151/LeetCode_32_151.cpp new file mode 100644 index 000000000..e6ba34a1f --- /dev/null +++ b/Week 08/id_151/LeetCode_32_151.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int longestValidParentheses(string s) { + vector dp(s.size(), 0); + int res = 0; + for (int i = 0; i < s.size(); ++i) { + if (s[i] == ')') { + if (i - 1 >= 0 && s[i-1] == '(') { + dp[i] = (i - 2 >= 0 ? dp[i-2] : 0) + 2; + } else if (i - 1 >= 0 && s[i-1] == ')') { + int idx = i - dp[i-1] - 2; + if (idx + 1>= 0 && s[idx+1] == '(') { + dp[i] = dp[i-1] + (idx >= 0 ? dp[idx] : 0) + 2; + } + } + + res = max(res, dp[i]); + } + } + + return res; + } +}; diff --git a/Week 08/id_151/LeetCode_387_151.cpp b/Week 08/id_151/LeetCode_387_151.cpp new file mode 100644 index 000000000..f377cfcd3 --- /dev/null +++ b/Week 08/id_151/LeetCode_387_151.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + int firstUniqChar(string s) { + int a[26] = {0}; + + for (const auto& ch : s) + a[ch - 'a']++; + + for (int i = 0; i < s.size(); ++i) + if (a[s[i] - 'a'] == 1) + return i; + return -1; + } +}; diff --git a/Week 08/id_151/LeetCode_438_151.cpp b/Week 08/id_151/LeetCode_438_151.cpp new file mode 100644 index 000000000..c1a7badce --- /dev/null +++ b/Week 08/id_151/LeetCode_438_151.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + vector findAnagrams(string s, string p) { + vector ret; + if (p.size() > s.size()) + return ret; + + int ap[26] = {0}; + for (const auto& ch : p) ap[ch - 'a']++; + + int as[26] = {0}; + for (int i = 0; i < s.size(); ++i) { + as[s[i] - 'a']++; + if (i >= p.size()) + as[s[i - p.size()] - 'a']--; + + if (memcmp(ap, as, sizeof(ap)) == 0) + ret.push_back(i - p.size() + 1); + } + return ret; + } +}; diff --git a/Week 08/id_151/LeetCode_91_151.cpp b/Week 08/id_151/LeetCode_91_151.cpp new file mode 100644 index 000000000..238f289f7 --- /dev/null +++ b/Week 08/id_151/LeetCode_91_151.cpp @@ -0,0 +1,31 @@ +class Solution { +public: + int numDecodings(string s) { + if (s.empty() || s[0] == '0') + return 0; + + vector dp(s.size(), 1); + for (int i = 0; i < s.size(); ++i) { + if (i - 1 >= 0) { + string tmp(s, i-1, 2); + if (tmp == "00") + return 0; + if (s[i] == '0') { + dp[i-1] = 0; + } + //cout << "tmp=" << tmp << endl; + if (atoi(tmp.c_str()) <= 26) { + if (i - 2 >= 0) { + dp[i] = dp[i-1] + dp[i-2]; + } else { + dp[i] = dp[i-1] + 1; + } + } else { + dp[i] = dp[i-1]; + } + } + } + + return dp[s.size()-1]; + } +}; diff --git a/Week 08/id_151/NOTE.md b/Week 08/id_151/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_151/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_156/NOTE.md b/Week 08/id_156/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_156/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_161/NOTE.md b/Week 08/id_161/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_161/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_166/NOTE.md b/Week 08/id_166/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_166/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_171/NOTE.md b/Week 08/id_171/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_171/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_176/NOTE.md b/Week 08/id_176/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_176/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_181/NOTE.md b/Week 08/id_181/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_181/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_186/NOTE.md b/Week 08/id_186/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_186/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_191/NOTE.md b/Week 08/id_191/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_191/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_196/NOTE.md b/Week 08/id_196/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_196/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_201/LeetCode_115_numDistinct b/Week 08/id_201/LeetCode_115_numDistinct new file mode 100644 index 000000000..3a671332e --- /dev/null +++ b/Week 08/id_201/LeetCode_115_numDistinct @@ -0,0 +1,20 @@ +public class LeetCode_115_numDistinct { + + + public int numDistinct(String s, String t) { + int[][] dp = new int[t.length() + 1][s.length() + 1]; + for (int j = 0; j < s.length() + 1; j++) + dp[0][j] = 1; + for (int i = 1; i < t.length() + 1; i++) { + for (int j = 1; j < s.length() + 1; j++) { + if (t.charAt(i - 1) == s.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]; + } else { + dp[i][j] = dp[i][j - 1]; + } + } + } + return dp[t.length()][s.length()]; + } + +} \ No newline at end of file diff --git a/Week 08/id_201/LeetCode_300_lengthOfLIS b/Week 08/id_201/LeetCode_300_lengthOfLIS new file mode 100644 index 000000000..8c5984115 --- /dev/null +++ b/Week 08/id_201/LeetCode_300_lengthOfLIS @@ -0,0 +1,20 @@ +public class LeetCode_300_lengthOfLIS { + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int res = 1, maxVal; + for (int i = 1; i < dp.length; i++) { + maxval = 0; + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + maxval = Math.max(maxval, dp[j]); + } + } + dp[i] = maxval +1; + res = Math.max(res, dp[i]); + } + return res; +} \ No newline at end of file diff --git a/Week 08/id_201/LeetCode_387_firstUniqueChar b/Week 08/id_201/LeetCode_387_firstUniqueChar new file mode 100644 index 000000000..f163c8f4b --- /dev/null +++ b/Week 08/id_201/LeetCode_387_firstUniqueChar @@ -0,0 +1,17 @@ +public class LeetCode_387_firstUniqueChar { + + public int firstUniqChar(String s) { + int[] letter=new int[26]; + for (char c:s.toCharArray()){ + letter[c-'a']++; + } + for (int i = 0; i temp = new HashMap(); + int n = s.length(); + for (int i = 0; i < n; i++) { + String str = String.valueOf(s.charAt(i)); + temp.put(str, temp.getOrDefault(str, 0) + 1); + } + + // find the index + for (int i = 0; i < n; i++) { + if (temp.get(String.valueOf(s.charAt(i))) == 1) + return i; + } + return -1; + } + + //151 + public String reverseWords(String s) { + String[] sArray = s.trim().split(" +"); + int len = sArray.length - 1; + StringBuffer ss = new StringBuffer(""); + while (len >= 0) { + ss.append(sArray[len]); + if (len > 0) { + ss.append(" "); + } + len--; + } + return ss.toString(); + } + + + private String killBlank(String str) { + if (" ".equals(str)) { + return ""; + } else { + return str; + } + } + +} diff --git a/Week 08/id_221/NOTE.md b/Week 08/id_221/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_221/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_226/NOTE.md b/Week 08/id_226/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_226/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_231/NOTE.md b/Week 08/id_231/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_231/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_236/NOTE.md b/Week 08/id_236/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_236/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_241/LeetCode_10_241.java b/Week 08/id_241/LeetCode_10_241.java new file mode 100644 index 000000000..d09913873 --- /dev/null +++ b/Week 08/id_241/LeetCode_10_241.java @@ -0,0 +1,32 @@ +import java.util.*; +/** + * 正则表达式匹配 + */ +class Solution { + private Boolean[][] dp; + + public boolean isMatch(String s, String p) { + dp = new Boolean[s.length()][p.length()]; + return isMatchHelper(0, 0, s, p); + } + + private boolean isMatchHelper(int i, int j, String s, String p) { + if (j == p.length()) return i == s.length(); //如果正则匹配结束后,字符串也应该匹配完毕 + if (i < s.length() && dp[i][j] != null) return dp[i][j]; //使用数组缓存已经算过的点 + boolean ans; + //这里需要先算第一个字符是否匹配的,而不能放到判断子句中,否则会影响结果 + //也就是,后面的判断,只要传递 i + 1,就要判断当前的 first + boolean first = i < s.length() && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); + //如果字符的第二个是*号 + if (p.length() - j >= 2 && p.charAt(j + 1) == '*') + //两种情况,一个是匹配0 个,则忽略正则的*号和之前一个字符。一个是匹配多个,则不断的移动 s + //这里需要将匹配 0 个情况放在判断的开头,这样当 i 溢出时,会通过 j+2的行为,让第一行判断终止递归。否则 i 将无限循环. + ans = isMatchHelper(i, j + 2, s, p) || (first && isMatchHelper(i + 1, j, s, p)); + else + //这里就是没有*号,则都往后移动一位。这里需要用 first,如果为 false,就不会判断后面了。 + ans = first && isMatchHelper(i + 1, j + 1, s, p); + //由于 i 会有溢出的可能,所以每次二维数组操作,需要判断 i 的界限 + if (i < s.length()) dp[i][j] = ans; + return ans; + } +} \ No newline at end of file diff --git a/Week 08/id_241/LeetCode_72_241.java b/Week 08/id_241/LeetCode_72_241.java new file mode 100644 index 000000000..acc6984af --- /dev/null +++ b/Week 08/id_241/LeetCode_72_241.java @@ -0,0 +1,25 @@ +import java.util.*; +/** + * 编辑距离 + */ +class Solution { + public int minDistance(String word1, String word2) { + int len1 = word1.length(); + int len2 = word2.length(); + int[][] dp = new int[len1 + 1][len2 + 1]; + for (int i = 0; i <= len1; i++) + dp[i][0] = i; + for (int i = 0; i <= len2; i++) + dp[0][i] = i; + for (int i = 1; i <= len1; i++) { + for (int j = 1; j <= len2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) + dp[i][j] = dp[i - 1][j - 1]; + else { + dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1; + } + } + } + return dp[len1][len2]; + } +} \ No newline at end of file diff --git a/Week 08/id_241/NOTE.md b/Week 08/id_241/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_241/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_246/LeetCode_115_246.py b/Week 08/id_246/LeetCode_115_246.py new file mode 100644 index 000000000..c05003f5a --- /dev/null +++ b/Week 08/id_246/LeetCode_115_246.py @@ -0,0 +1,53 @@ +''' +distinct-subsequences_115 + +给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。 + +一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是) + +示例 1: +输入: S = "rabbbit", T = "rabbit" +输出: 3 +解释: +如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。 +(上箭头符号 ^ 表示选取的字母) +rabbbit +^^^^ ^^ +rabbbit +^^ ^^^^ +rabbbit +^^^ ^^^ + +示例 2: +输入: S = "babgbag", T = "bag" +输出: 5 +解释: +如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。 +(上箭头符号 ^ 表示选取的字母) + +babgbag +^^ ^ +babgbag +^^ ^ +babgbag +^ ^^ +babgbag + ^ ^^ +babgbag + ^^^ +''' + +def numDistinct(s, t): + n1 = len(s) + n2 = len(t) + dp = [[0]*(n1+1) for _ in range(n2+1)] + for j in range(n1+1): + dp[0][j] = 1 + for i in range(1, n2+1): + for j in range(1, n1+1): + if t[i-1] == s[j-1]: + dp[i][j] = dp[i-1][j-1] + dp[i][j-1] + else: + dp[i][j] = dp[i][j-1] + print(dp) + return dp[-1][-1] \ No newline at end of file diff --git a/Week 08/id_246/LeetCode_205_246.py b/Week 08/id_246/LeetCode_205_246.py new file mode 100644 index 000000000..c0e6a976d --- /dev/null +++ b/Week 08/id_246/LeetCode_205_246.py @@ -0,0 +1,34 @@ +''' +isomorphic-strings_205 + +给定两个字符串 s 和 t,判断它们是否是同构的。 + +如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。 + +所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。 + +示例 1: + +输入: s = "egg", t = "add" +输出: true +''' + +def isIsomorphic_1(s, t): + return [*map(s.index, s)] == [*map(t.index, t)] + +def isIsomorphic_2(s, t): + d1, d2 = {}, {} + for i, val in enumerate(s): + d1[val] = d1.get(val, []) + [i] + for i, val in enumerate(t): + d2[val] = d2.get(val, []) + [i] + return sorted(d1.values()) == sorted(d2.values()) + +def isIsomorphic_3(s, t): + return len(set(zip(s, t))) == len(set(s)) == len(set(t)) + +def isIsomorphic_4(s, t): + return [s.find(i) for i in s] == [t.find(j) for j in t] + +def isIsomorphic_5( s, t): + return map(s.find, s) == map(t.find, t) \ No newline at end of file diff --git a/Week 08/id_246/LeetCode_300_246.py b/Week 08/id_246/LeetCode_300_246.py new file mode 100644 index 000000000..b2b45ee48 --- /dev/null +++ b/Week 08/id_246/LeetCode_300_246.py @@ -0,0 +1,48 @@ +''' +longest-increasing-subsequence_300 + +给定一个无序的整数数组,找到其中最长上升子序列的长度。 + +示例: +输入: [10,9,2,5,3,7,101,18] +输出: 4 +解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 +''' + +# 动态规划 +def length0fLIS_1(nums): + if not nums: return 0 + dp = [1] * len(nums) + for i in range(len(nums)): + for j in range(i): + if nums[j] < nums[i]: + dp[i] = max(dp[i], dp[j]+1) + return max(dp) + + +# 动态规划 + 二分查找 +def length0fLIS_2(nums): + tails, res = [0] * len(nums), 0 + for num in nums: + i, j = 0, res + while i < j: + m = (i + j)//2 + if tails[m] < num: + i = m + 1 + else: + j = m + tails[i] = num + if j == res: + res += 1 + return res + + +# 动态规划 + 二分查找 +def lengthOfLIS_3(nums): + q = [-float('inf')] + for i in nums: + if i > q[-1]: + q += [i] + else: + q[bisect.bisect_left(q, i)] = i + return len(q) - 1 \ No newline at end of file diff --git a/Week 08/id_246/LeetCode_32_246.py b/Week 08/id_246/LeetCode_32_246.py new file mode 100644 index 000000000..c0ad35c67 --- /dev/null +++ b/Week 08/id_246/LeetCode_32_246.py @@ -0,0 +1,30 @@ +''' +longest-valid-parentheses_32 + +给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + +示例 1: +输入: "(()" +输出: 2 +解释: 最长有效括号子串为 "()" +示例 2: + +输入: ")()())" +输出: 4 +解释: 最长有效括号子串为 "()()" +''' + +def longestValidParentheses(s): + if (not s): + return 0 + res = 0 + n = len(s) + dp = [0] * n + for i in range(1, n): + if (s[i] == '('): + if (s[i-1] == '('): + dp[i] = dp[i-2] + 2 + if (s[i-1] == ')' and i-dp[i-1]-1 >= 0 and s[i-dp[i-1]-1] == '('): + dp[i] = dp[i-1]+dp[i-dp[i-1]-2]+2 + res = max(res, dp[i]) + return res \ No newline at end of file diff --git a/Week 08/id_246/LeetCode_44_246.py b/Week 08/id_246/LeetCode_44_246.py new file mode 100644 index 000000000..48c9d3d52 --- /dev/null +++ b/Week 08/id_246/LeetCode_44_246.py @@ -0,0 +1,67 @@ +''' +wildcard-matching_44 + +给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。 + +'?' 可以匹配任何单个字符。 +'*' 可以匹配任意字符串(包括空字符串)。 +两个字符串完全匹配才算匹配成功。 + +说明: + +s 可能为空,且只包含从 a-z 的小写字母。 +p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。 +示例 1: + +输入: +s = "aa" +p = "a" +输出: false +解释: "a" 无法匹配 "aa" 整个字符串。 + +''' + +#指针 +def isMatch_1(s, p): + i = 0 + j = 0 + start = -1 + match = 0 + while i < len(s): + # 一对一匹配,匹配成功一起移 + if j < len(p) and (s[i] == p[j] or p[j] == "?"): + i += 1 + j += 1 + # 记录p的"*"的位置,还有s的位置 + elif j < len(p) and p[j] == "*": + start = j + match = i + j += 1 + # j 回到 记录的下一个位置 + # match 更新下一个位置 + # 这不代表用*匹配一个字符 + elif start != -1: + j = start + 1 + match += 1 + i = match + else: + return False + # 将多余的 * 直接匹配空串 + return all(x == "*" for x in p[j:]) + + +#dp +def isMatch_2(s, p): + sn, pn = len(s), len(p) + dp = [[False]*(pn+1) for _ in range(sn+1)] + dp[0][0] = True + for j in range(1, pn+1): + if p[j-1] == '*': + dp[0][j] = dp[0][j-1] + for i in range(1, sn+1): + for j in range(1, pn+1): + if (s[i-1] == p[i-1] or p[i-1] == '?'): + dp[i][j] = dp[i-1][j-1] + elif p[j-1] == '*': + dp[i][j] = dp[i-1][j] or dp[i][j-1] + return dp[-1][-1] \ No newline at end of file diff --git a/Week 08/id_246/LeetCode_818_246.py b/Week 08/id_246/LeetCode_818_246.py new file mode 100644 index 000000000..57803fc27 --- /dev/null +++ b/Week 08/id_246/LeetCode_818_246.py @@ -0,0 +1,43 @@ +''' +race-car_818 + +你的赛车起始停留在位置 0,速度为 +1,正行驶在一个无限长的数轴上。(车也可以向负数方向行驶。) +你的车会根据一系列由 A(加速)和 R(倒车)组成的指令进行自动驾驶 。 +当车得到指令 "A" 时, 将会做出以下操作: position += speed, speed *= 2。 +当车得到指令 "R" 时, 将会做出以下操作:如果当前速度是正数,则将车速调整为 speed = -1 ;否则将车速调整为 speed = 1。  (当前所处位置不变。) +例如,当得到一系列指令 "AAR" 后, 你的车将会走过位置 0->1->3->3,并且速度变化为 1->2->4->-1。 +现在给定一个目标位置,请给出能够到达目标位置的最短指令列表的长度。 + +示例 1: +输入: +target = 3 +输出: 2 +解释: +最短指令列表为 "AA" +位置变化为 0->1->3 + +示例 2: +输入: +target = 6 +输出: 5 +解释: +最短指令列表为 "AAARA" +位置变化为 0->1->3->7->7->6 + +说明: +1 <= target(目标位置) <= 10000。 +''' + + +def racecar(target): + dp = [0, 1, 4]+[float('inf')]*target + for t in range(3, target+1): + k = t.bit_length() + if t == 2**k-1: + dp[t] = k + continue + for j in range(k-1): + dp[t] = min(dp[t], dp[t-2**(k-1)+2**j]+k-1+j+2) + if 2**k-1-t 1 +'B' -> 2 +... +'Z' -> 26 +给定一个只包含数字的非空字符串,请计算解码方法的总数。 + +示例 1: +输入: "12" +输出: 2 +解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + +示例 2: +输入: "226" +输出: 3 +解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +''' + + +# dp_1 +def numDecodings_1(s): + n = len(s) + if (not s or s[0]=='0'): + return 0 + dp = [0]*(n+1) + dp[0] = dp[1] = 1 + for i in range(1, n): + if (s[i]=='0'): + if (s[i-1]=='1' or s[i-1]=='2'): + dp[i+1] = dp[i-1] + else: + return 0 + else: + if (s[i-1] =='1' or + (s[i-1] == '2' and '1'<=s[i]<='6')): + dp[i+1] = dp[i] + dp[i-1] + else: + dp[i+1] = dp[i] + return dp[-1] + + +# dp_2 +def numDecodings_12(s): + n = len(s) + if (not s or s[0]=='0'): + return 0 + pre = cur = 1 + for i in range(1, n): + if (s[i] == '0'): + if (s[i-1] == '1') or (s[i-1]=="2"): + cur = pre + else: return 0 + else: + if (s[i-1] =='1' or (s[i-1] == '2' and '1'<=s[i]<='6')): + tmp = cur + cur += pre + pre = tmp + else: + pre = cur + cur = cur + return cur \ No newline at end of file diff --git a/Week 08/id_246/NOTE.md b/Week 08/id_246/NOTE.md new file mode 100755 index 000000000..71d7debcf --- /dev/null +++ b/Week 08/id_246/NOTE.md @@ -0,0 +1,18 @@ +# NOTE + +【字符串】 + +1. 字符串操作问题 + +2. 异位词问题 + +3. 回文串问题 + +4. 字符串+DP问题 + +5. 字符串匹配算法 +【1】 暴力法(brute force) +【2】 Rabin-Karp 算法 +【3】 KMP 算法 +【4】 Boyer-Moore 算法 +【5】 Sunday 算法 \ No newline at end of file diff --git a/Week 08/id_251/LeetCode_387_251.py b/Week 08/id_251/LeetCode_387_251.py new file mode 100644 index 000000000..b72b03e95 --- /dev/null +++ b/Week 08/id_251/LeetCode_387_251.py @@ -0,0 +1,43 @@ +# 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 +# +# 案例: +# +# +# s = "leetcode" +# 返回 0. +# +# s = "loveleetcode", +# 返回 2. +# +# +# +# +# 注意事项:您可以假定该字符串只包含小写字母。 +# Related Topics 哈希表 字符串 + +""" +1 字典 +2 字母表 +""" +import collections + + +class Solution(object): + def firstUniqChar(self, s): + """ + :type s: str + :rtype: int + """ + dic = collections.Counter(s) + + for i, c in enumerate(s): + if dic[c] == 1: + return i + return -1 + + +class Solution2: + def firstUniqChar(self, s): + letters = 'abcdefghijklmnopqrstuvwxyz' + index = [s.index(l) for l in letters if s.count(l) == 1] + return min(index) if len(index) > 0 else -1 diff --git a/Week 08/id_251/LeetCode_63_251.py b/Week 08/id_251/LeetCode_63_251.py new file mode 100644 index 000000000..2fe4d243b --- /dev/null +++ b/Week 08/id_251/LeetCode_63_251.py @@ -0,0 +1,80 @@ +# 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 +# +# 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 +# +# 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? +# +# +# +# 网格中的障碍物和空位置分别用 1 和 0 来表示。 +# +# 说明:m 和 n 的值均不超过 100。 +# +# 示例 1: +# +# 输入: +# [ +#   [0,0,0], +#   [0,1,0], +#   [0,0,0] +# ] +# 输出: 2 +# 解释: +# 3x3 网格的正中间有一个障碍物。 +# 从左上角到右下角一共有 2 条不同的路径: +# 1. 向右 -> 向右 -> 向下 -> 向下 +# 2. 向下 -> 向下 -> 向右 -> 向右 +# +# Related Topics 数组 动态规划 + +""" +1 递归 超时 +2 dp +https://leetcode.com/problems/unique-paths-ii/discuss/23410/Python-different-solutions-(O(m*n)-O(n)-in-place). +""" + + +class Solution(object): + def uniquePathsWithObstacles(self, obstacleGrid): + """ + :type obstacleGrid: List[List[int]] + :rtype: int + """ + m, n = len(obstacleGrid) - 1, len(obstacleGrid[0]) - 1 + return self.DFS(obstacleGrid, m, n) + + def DFS(self, obstacleGrid, m, n): + if m == 0 and n == 0: + return 1 - obstacleGrid[0][0] + # * 和 and 效果一样 + if m == 0: + return self.DFS(obstacleGrid, m, n - 1) * (1 - obstacleGrid[0][n]) + if n == 0: + return self.DFS(obstacleGrid, m - 1, n) and 1 - obstacleGrid[m][0] + + return (self.DFS(obstacleGrid, m - 1, n) + self.DFS(obstacleGrid, m, n - 1)) * (1 - obstacleGrid[m][n]) + + +class Solution2(object): + def uniquePathsWithObstacles(self, obstacleGrid): + """ + :type obstacleGrid: List[List[int]] + :rtype: int + """ + if not obstacleGrid: + return 0 + m, n = len(obstacleGrid), len(obstacleGrid[0]) + dp = [[0 for _ in range(n)] for _ in range(m)] + # dp = [[0] * n for _ in range(m)] + dp[0][0] = 1 - obstacleGrid[0][0] + + for i in range(1, m): + dp[i][0] = dp[i - 1][0] * (1 - obstacleGrid[i][0]) + for j in range(1, n): + dp[0][j] = dp[0][j - 1] * (1 - obstacleGrid[0][j]) + + for i in range(1, m): + for j in range(1, n): + dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) * (1 - obstacleGrid[i][j]) + + return dp[-1][-1] diff --git a/Week 08/id_251/LeetCode_72_251.py b/Week 08/id_251/LeetCode_72_251.py new file mode 100644 index 000000000..7bc9ced20 --- /dev/null +++ b/Week 08/id_251/LeetCode_72_251.py @@ -0,0 +1,110 @@ +# 给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 +# +# 你可以对一个单词进行如下三种操作: +# +# +# 插入一个字符 +# 删除一个字符 +# 替换一个字符 +# +# +# 示例 1: +# +# 输入: word1 = "horse", word2 = "ros" +# 输出: 3 +# 解释: +# horse -> rorse (将 'h' 替换为 'r') +# rorse -> rose (删除 'r') +# rose -> ros (删除 'e') +# +# +# 示例 2: +# +# 输入: word1 = "intention", word2 = "execution" +# 输出: 5 +# 解释: +# intention -> inention (删除 't') +# inention -> enention (将 'i' 替换为 'e') +# enention -> exention (将 'n' 替换为 'x') +# exention -> exection (将 'n' 替换为 'c') +# exection -> execution (插入 'u') +# +# Related Topics 字符串 动态规划 + +""" +1 深度递归 超时 +2 递归+记忆化 +3 DP +""" + + +class Solution(object): + def minDistance(self, word1, word2): + """ + :type word1: str + :type word2: str + :rtype: int + """ + """ + if not word1 and not word2: + return 0 + if not word1: + return len(word2) + if not word2: + return len(word1) + """ + if not word1 or not word2: + return len(word1) or len(word2) + + if word1[0] == word2[0]: + return self.minDistance(word1[1:], word2[1:]) + insert = 1 + self.minDistance(word1, word2[1:]) + delete = 1 + self.minDistance(word1[1:], word2) + replace = 1 + self.minDistance(word1[1:], word2[1:]) + return min(insert, delete, replace) + + +class Solution2(object): + def minDistance(self, word1, word2, cache={}): + """ + :type word1: str + :type word2: str + :rtype: int + """ + if not word1 or not word2: + return len(word1) or len(word2) + + if word1[0] == word2[0]: + return self.minDistance(word1[1:], word2[1:]) + + if (word1, word2) not in cache: + inserted = 1 + self.minDistance(word1, word2[1:]) + deleted = 1 + self.minDistance(word1[1:], word2) + replaced = 1 + self.minDistance(word1[1:], word2[1:]) + cache[(word1, word2)] = min(inserted, deleted, replaced) + + return cache[(word1, word2)] + + +class Solution3(object): + def minDistance(self, word1, word2): + """ + :type word1: str + :type word2: str + :rtype: int + """ + m, n = len(word1), len(word2) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(m + 1): + dp[i][0] = i + for j in range(n + 1): + dp[0][j] = j + + for i in range(1, m + 1): + for j in range(1, n + 1): + if word1[i - 1] == word2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + else: + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + return dp[m][n] diff --git a/Week 08/id_251/NOTE.md b/Week 08/id_251/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_251/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_256/LeetCode_51_256.js b/Week 08/id_256/LeetCode_51_256.js new file mode 100644 index 000000000..360edca1c --- /dev/null +++ b/Week 08/id_256/LeetCode_51_256.js @@ -0,0 +1,45 @@ +/* + * @lc app=leetcode.cn id=51 lang=javascript + * + * [51] N皇后 + */ + +// @lc code=start +/** + * @param {number} n + * @return {string[][]} + */ +var solveNQueens = function(n) { + //方法一 回溯 + let col = new Array(n).fill(false); + let left = new Array(n * 2).fill(false); + let right = new Array(n + 2).fill(false); + let board = Array.from({ length: n }, () => + Array.from({ length: n }, () => ".") + ); + let res = []; + var backtrack = function(i) { + if (i === n) { + res.push(board.map(row => row.join(""))); + return res; + } + for (let j = 0; j < n; j++) { + let l = i + j; + let r = j - i + n - 1; + if (!col[j] && !left[l] && !right[r]) { + board[i][j] = "Q"; + col[j] = true; + left[l] = true; + right[r] = true; + backtrack(i + 1); + board[i][j] = "."; + col[j] = false; + left[l] = false; + right[r] = false; + } + } + }; + backtrack(0); + return res; +}; +// @lc code=end diff --git a/Week 08/id_256/LeetCode_58_256.js b/Week 08/id_256/LeetCode_58_256.js new file mode 100644 index 000000000..7137de314 --- /dev/null +++ b/Week 08/id_256/LeetCode_58_256.js @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=58 lang=javascript + * + * [58] 最后一个单词的长度 + */ + +// @lc code=start +/** + * @param {string} s + * @return {number} + */ +var lengthOfLastWord = function(s) { + let letters = s.split(' '); + if(letters.length == 0) return 0; + while(letters.length > 0 && letters[letters.length-1] == "") { + letters.pop(); + } + if(letters.length == 0) return 0; + return letters[letters.length-1].length; +}; +// @lc code=end + diff --git a/Week 08/id_256/LeetCode_746_256.js b/Week 08/id_256/LeetCode_746_256.js new file mode 100644 index 000000000..cd200135d --- /dev/null +++ b/Week 08/id_256/LeetCode_746_256.js @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=746 lang=javascript + * + * [746] 使用最小花费爬楼梯 + */ + +// @lc code=start +/** + * @param {number[]} cost + * @return {number} + */ +var minCostClimbingStairs = function(cost) { + //DP + if(cost.length <= 1) return 0; + if(cost.length == 2) { + return Math.min(cost[0], cost[1]); + } + for(let i = 2; i < cost.length; i++) { + cost[i] += Math.min(cost[i-2], cost[i-1]); + } + return Math.min(cost[cost.length-2], cost[cost.length-1]); +}; +// @lc code=end + diff --git a/Week 08/id_256/LeetCode_771_256.js b/Week 08/id_256/LeetCode_771_256.js new file mode 100644 index 000000000..a953bc4d2 --- /dev/null +++ b/Week 08/id_256/LeetCode_771_256.js @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=771 lang=javascript + * + * [771] 宝石与石头 + */ + +// @lc code=start +/** + * @param {string} J + * @param {string} S + * @return {number} + */ +var numJewelsInStones = function(J, S) { + let J_arr = [...J]; + let S_arr = [...S]; + let count = 0; + S_arr.forEach(key => { + if(J_arr.indexOf(key) >= 0) { + count ++; + } + }) + return count; +}; +// @lc code=end + diff --git a/Week 08/id_256/LeetCode_773_256.js b/Week 08/id_256/LeetCode_773_256.js new file mode 100644 index 000000000..dbf02c9d2 --- /dev/null +++ b/Week 08/id_256/LeetCode_773_256.js @@ -0,0 +1,68 @@ +/* + * @lc app=leetcode.cn id=773 lang=javascript + * + * [773] 滑动谜题 + */ + +// @lc code=start +/** + * @param {number[][]} board + * @return {number} + */ +var slidingPuzzle = function(board) { + // BFS + let R = board.length; + if(R == 0) return 0; + let C = board[0].length; + if(C == 0) return 0; + let sr = 0; + let sc = 0; + search: + for(sr = 0; sr < board.length; sr++) { + for(sc = 0; sc < board[sr].length; sc++) { + if(board[sr][sc] == 0) { + break search; + } + } + } + let queue = []; + let strQueue = []; + let start = new Node(board, sr, sc, 0); + queue.push(start); + strQueue.push(start.boardStr); + let direction = [[-1,0],[1,0],[0,-1],[0,1]]; + let target = "1,2,3,4,5,0"; + while(queue.length > 0) { + let tempNode = queue.shift(); + if(tempNode.boardStr == target) { + return tempNode.depth; + } + for(let i = 0; i < direction.length; i++) { + let nei_r = direction[i][0] + tempNode.nei_r; + let nei_c = direction[i][1] + tempNode.nei_c; + if((Math.abs(nei_r - tempNode.nei_r) + Math.abs(nei_c - tempNode.nei_c) != 1) || nei_r < 0 || nei_c < 0 || nei_r >= R || nei_c >= C) continue; + //创建新board + let newBoard = JSON.parse(JSON.stringify(tempNode.board)); + newBoard[tempNode.nei_r][tempNode.nei_c] = newBoard[nei_r][nei_c]; + newBoard[nei_r][nei_c] = 0; + let newNode = new Node(newBoard, nei_r, nei_c, tempNode.depth + 1); + if(strQueue.indexOf(newNode.boardStr) >= 0) continue; + strQueue.push(newNode.boardStr); + queue.push(newNode); + } + } + return -1; +}; +class Node { + //board [][] + //nei_r nei_c 0所以索引 + //depth 深度 + constructor(board, nei_r, nei_c, depth) { + this.board = board; + this.nei_r = nei_r; + this.nei_c = nei_c; + this.depth = depth; + this.boardStr = board.toString(); + } +} + diff --git a/Week 08/id_256/LeetCode_91_256.js b/Week 08/id_256/LeetCode_91_256.js new file mode 100644 index 000000000..cac6cfa37 --- /dev/null +++ b/Week 08/id_256/LeetCode_91_256.js @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=91 lang=javascript + * + * [91] 解码方法 + */ + +// @lc code=start +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function(s) { + //DP + if(s[0] == 0)return 0; + let len = s.length; + let dp = new Array(len + 1).fill(0); + dp[0] = dp[1] = 1; + for(let i = 2; i <=len; i++) { + if(s[i-1] != 0) { + dp[i] += dp[i - 1]; + } + if(s[i-2] == 1 || s[i-2] == 2 && s[i-1] <= 6) { + dp[i] += dp[i - 2]; + } + } + return dp[len]; + +}; +// @lc code=end + diff --git a/Week 08/id_256/NOTE.md b/Week 08/id_256/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_256/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_261/NOTE.md b/Week 08/id_261/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_261/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_261/leetcode_300_261.go b/Week 08/id_261/leetcode_300_261.go new file mode 100644 index 000000000..a1319f00d --- /dev/null +++ b/Week 08/id_261/leetcode_300_261.go @@ -0,0 +1,26 @@ +// leetcode : https://leetcode-cn.com/problems/longest-increasing-subsequence + +func lengthOfLIS(nums []int) int { + n := len(nums) + if n <= 1 { + return n + } + a := make([]int, n) + a[0] = 1 + maxDP := 1 + for i := 1; i < n; i++ { + max := 1 + for j:=i-1; j >=0; j-- { + if nums[i] > nums[j] { + if max < a[j] + 1 { + max = a[j] + 1 + } + } + } + a[i] = max + if max > maxDP { + maxDP = max + } + } + return maxDP +} \ No newline at end of file diff --git a/Week 08/id_261/leetcode_91_261.go b/Week 08/id_261/leetcode_91_261.go new file mode 100644 index 000000000..74846c074 --- /dev/null +++ b/Week 08/id_261/leetcode_91_261.go @@ -0,0 +1,36 @@ +// leetcode : https://leetcode-cn.com/problems/decode-ways/ + +func numDecodings(s string) int { + n := len(s) + a := make([][]int, n) + a[0] = []int{1, 0} + if s[0] >= '1' && s[0] <= '2' { + a[0][1] = 1 + } + if s[0] == '0' { + return 0 + } + for i := 1; i < n; i++ { + if s[i] == '0' { + if s[i-1] == '0' || s[i-1] > '2' { + return 0 + } + if a[i-1][1] >= 0 { + a[i] = []int{a[i-1][1], 0} + } else { + a[i] = []int{a[i-1][0], 0} + } + continue + } + num := 0 + if s[i] >= '1' && s[i] <= '2' { + num = a[i-1][0] + } + if s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6') { + a[i] = []int{a[i-1][0] + a[i-1][1], num} + } else { + a[i] = []int{a[i-1][0], num} + } + } + return a[n-1][0] +} \ No newline at end of file diff --git a/Week 08/id_266/266-Week 08 b/Week 08/id_266/266-Week 08 new file mode 100644 index 000000000..1a18fdc16 --- /dev/null +++ b/Week 08/id_266/266-Week 08 @@ -0,0 +1,79 @@ +// 1.最长上升子序列(longest-increasing-subsequence) +// idea: +// explanation: e.g = [10, 9, 2, 5, 3, 7, 101, 8] +// initial condition: dp = [1] * len(nums), 初始值都为1, dp[i]的意思是以nums[i]结尾的最长上升子序列的长度 +// 开始一个一个看: +// 10: dp[0] = 1 +// 9(<10): dp[1] = 1 +// 2(<10 || < 9): dp[2] = 1 +// 5(>2): dp[3] = max(dp[2] + 1) = 2 +// 3(>2): dp[4] = max(dp[2] + 1) = 2 +// 7(>2 || >5 || >3): dp[5] = max(dp[2]+1,dp[3]+1,dp[4]+1) = 3 +// 101(>10 || >9 || >2 || >5 || >3 || >7): dp[6] = max(dp[0]+1, dp[1]+1, dp[2]+1, dp[3]+1, dp[4]+1, dp[5]+1)=4 +// 18(>10 || >9 || >2 || >5 || >3 || >7): dp[7] = max(dp[0]+1, dp[1]+1, dp[2]+1, dp[3]+1, dp[4]+1, dp[5]+1) = 4 + +import java.util.Arrays; + +class Solution { + public int lengthOfLIS(int[] nums) { + int len = nums.length; + if (len == 0) { + return 0; + } + + // define the dp and initialize with all 1 elements + int[] dp = new int[len]; + Arrays.fill(dp, 1); + + for (int i = 1; i < len; i++) { + int curVal = nums[i]; // the current value + // for those elements ahead of curVal + for (int j = 0; j < i; j++) { + if (curVal > nums[j]) { + dp[i] = Math.max(dp[j] + 1, dp[i]); // notice that the initial value is 1(dp[i]=1) + } + } + } + + // print the max value in dp + int res = dp[0]; + for (int i = 0; i < len; i++) { + res = Integer.max(res, dp[i]); + } + return res; + } +} + +// 2.最长有效括号(longest-valid-parentheses) + +public class Solution { + public int longestValidParentheses(String s) { + int left = 0, right = 0, maxlength = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * right); + } else if (right >= left) { + left = right = 0; + } + } + left = right = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * left); + } else if (left >= right) { + left = right = 0; + } + } + return maxlength; + } +} diff --git a/Week 08/id_266/NOTE.md b/Week 08/id_266/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_266/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_271/NOTE.md b/Week 08/id_271/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_271/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_276/LeetCode_242.java b/Week 08/id_276/LeetCode_242.java new file mode 100644 index 000000000..801592986 --- /dev/null +++ b/Week 08/id_276/LeetCode_242.java @@ -0,0 +1,9 @@ +//LeetCode 242 +//Чλ +public boolean isAnagram(String s, String t) { + int[] cnt = new int[255]; + for(char c : s.toCharArray()) cnt[c - 'a'] ++; + for (char c : t.toCharArray()) cnt[c - 'a'] --; + for (int n : cnt) if (n != 0) return false; + return true; + } \ No newline at end of file diff --git a/Week 08/id_276/LeetCode_387.java b/Week 08/id_276/LeetCode_387.java new file mode 100644 index 000000000..fbf68b62a --- /dev/null +++ b/Week 08/id_276/LeetCode_387.java @@ -0,0 +1,20 @@ +//һظַ hashmap +public int firstUniqChar(String s) { + Map map = new HashMap<>(); + for (int i = 0; i < s.length(); ++ i) { + if (map.containsKey(s.charAt(i))) map.put(s.charAt(i), -1); + else map.put(s.charAt(i), i); + } + for (char c : s.toCharArray()) { + if (map.get(c) >= 0) return map.get(c); + } + return -1; + } +//int[] +public int firstUniqChar(String s) { + int[] freq = new int[26]; + for (int i = 0; i < s.length(); ++ i) freq[s.charAt(i) - 'a'] ++; + for (int i = 0; i < s.length(); ++ i) { + if (freq[s.charAt(i) - 'a'] == 1) return i; + } +} diff --git a/Week 08/id_276/NOTE.md b/Week 08/id_276/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_276/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_281/NOTE.md b/Week 08/id_281/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_281/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_286/NOTE.md b/Week 08/id_286/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_286/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_291/NOTE.md b/Week 08/id_291/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_291/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_296/LeetCode_115_296.java b/Week 08/id_296/LeetCode_115_296.java new file mode 100644 index 000000000..e335a1b29 --- /dev/null +++ b/Week 08/id_296/LeetCode_115_296.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=115 lang=java + * + * [115] 不同的子序列 + */ + +// @lc code=start +class Solution { + public int numDistinct(String s, String t) { + int[][] dp = new int[t.length() + 1][s.length() + 1]; + for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1; + for (int i = 1; i < t.length() + 1; i++) { + for (int j = 1; j < s.length() + 1; j++) { + if (t.charAt(i - 1) == s.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]; + else dp[i][j] = dp[i][j - 1]; + } + } + return dp[t.length()][s.length()]; + } +} +// @lc code=end + diff --git a/Week 08/id_296/LeetCode_44_296.java b/Week 08/id_296/LeetCode_44_296.java new file mode 100644 index 000000000..b117bf334 --- /dev/null +++ b/Week 08/id_296/LeetCode_44_296.java @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=44 lang=java + * + * [44] 通配符匹配 + */ + +// @lc code=start +class Solution { + public boolean isMatch(String s, String p) { + int m = s.length(), n = p.length(); + boolean[][] f = new boolean[m + 1][n + 1]; + + f[0][0] = true; + for (int i = 1; i <= n; i++) { + f[0][i] = f[0][i - 1] && p.charAt(i - 1) == '*'; + } + + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') { + f[i][j] = f[i - 1][j - 1]; + } + if (p.charAt(j - 1) == '*') { + f[i][j] = f[i][j - 1] || f[i - 1][j]; + } + } + } + return f[m][n]; + } +} +// @lc code=end + diff --git a/Week 08/id_296/NOTE.md b/Week 08/id_296/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_296/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_301/NOTE.md b/Week 08/id_301/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_301/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_306/DecodeWays.java b/Week 08/id_306/DecodeWays.java new file mode 100644 index 000000000..cce7d724c --- /dev/null +++ b/Week 08/id_306/DecodeWays.java @@ -0,0 +1,36 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/6. + * 力扣题目地址:https://leetcode-cn.com/problems/decode-ways + */ +public class DecodeWays { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + //help用来存储res以前的值 + help = res-help; + } else { + help = res; + } + + } + return res; + } +} diff --git a/Week 08/id_306/DistinctSubsequences.java b/Week 08/id_306/DistinctSubsequences.java new file mode 100644 index 000000000..901e8e611 --- /dev/null +++ b/Week 08/id_306/DistinctSubsequences.java @@ -0,0 +1,56 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/distinct-subsequences + */ +public class DistinctSubsequences { + /** + * 还行 没太懂 + * 出处:https://leetcode-cn.com/problems/distinct-subsequences/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-27 + * @param s + * @param t + * @return + */ + public int numDistinct(String s, String t) { + int s_len = s.length(); + int t_len = t.length(); + int[] dp = new int[s_len + 1]; + for (int i = 0; i <= s_len; i++) { + dp[i] = 1; + } + for (int t_i = 1; t_i <= t_len; t_i++) { + int pre = dp[0]; + dp[0] = 0; + for (int s_i = 1; s_i <= s_len; s_i++) { + int temp = dp[s_i]; + if (t.charAt(t_i - 1) == s.charAt(s_i - 1)) { + dp[s_i] = dp[s_i - 1] + pre; + } else { + dp[s_i] = dp[s_i - 1]; + } + pre = temp; + } + } + return dp[s_len]; + } + + /** + * 没看懂 需要细品 + * 出处:https://leetcode-cn.com/problems/distinct-subsequences/solution/dong-tai-gui-hua-by-powcai-5 + * @param s + * @param t + * @return + */ + public int numDistinct1(String s, String t) { + int[][] dp = new int[t.length() + 1][s.length() + 1]; + for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1; + for (int i = 1; i < t.length() + 1; i++) { + for (int j = 1; j < s.length() + 1; j++) { + if (t.charAt(i - 1) == s.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]; + else dp[i][j] = dp[i][j - 1]; + } + } + return dp[t.length()][s.length()]; + } +} diff --git a/Week 08/id_306/FindAllAnagramsInAString.java b/Week 08/id_306/FindAllAnagramsInAString.java new file mode 100644 index 000000000..9517287e8 --- /dev/null +++ b/Week 08/id_306/FindAllAnagramsInAString.java @@ -0,0 +1,87 @@ +package sf.week8; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LynnSun on 2019/12/8. + * 力扣题目地址:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string + */ +public class FindAllAnagramsInAString { + /** + * 双指针 + * @param s + * @param p + * @return + */ + public List findAnagrams(String s, String p){ + int[] count = new int[26]; + int[] window = new int[26]; + for (char c : p.toCharArray()) { + count[c - 'a']++; + } + int left = 0, right = 0; + List list = new ArrayList<>(); + while (right < s.length()) { + int idx = s.charAt(right++) - 'a'; + window[idx]++; + while (count[idx] < window[idx]) { + window[s.charAt(left++) - 'a']--; + } + if (right - left == p.length()) { + list.add(left); + } + } + return list; + } + + /** + * 依次判断法&类KMP算法 + * https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/solution/java-liang-fang-fa-yi-ci-pan-duan-fa-lei-kmpsuan-f/ + * @param s + * @param p + * @return + */ + public List findAnagrams1(String s, String p) { + int slength = s.length(); + int plength = p.length(); + int conter = 0; + StringBuilder sb = new StringBuilder(p); + + List result = new ArrayList(); + + for(int i=0; i> groupAnagrams(String[] strs) { + HashMap> hash = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + char[] s_arr = strs[i].toCharArray(); + //排序 + Arrays.sort(s_arr); + //映射到 key + String key = String.valueOf(s_arr); + //添加到对应的类中 + if (hash.containsKey(key)) { + hash.get(key).add(strs[i]); + } else { + List temp = new ArrayList(); + temp.add(strs[i]); + hash.put(key, temp); + } + + } + return new ArrayList>(hash.values()); + } + + /** + * 利用质数相乘 + * https://leetcode-cn.com/problems/group-anagrams/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--16 + * @param strs + * @return + */ + public List> groupAnagrams3(String[] strs) { + HashMap> hash = new HashMap<>(); + //每个字母对应一个质数 + int[] prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103 }; + for (int i = 0; i < strs.length; i++) { + int key = 1; + //累乘得到 key + for (int j = 0; j < strs[i].length(); j++) { + key *= prime[strs[i].charAt(j) - 'a']; + } + if (hash.containsKey(key)) { + hash.get(key).add(strs[i]); + } else { + List temp = new ArrayList(); + temp.add(strs[i]); + hash.put(key, temp); + } + + } + return new ArrayList>(hash.values()); + } +} diff --git a/Week 08/id_306/Isomorphic.java b/Week 08/id_306/Isomorphic.java new file mode 100644 index 000000000..78d1dbe3c --- /dev/null +++ b/Week 08/id_306/Isomorphic.java @@ -0,0 +1,59 @@ +package sf.week8; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by LynnSun on 2019/12/8. + * 力扣题目地址:https://leetcode-cn.com/problems/isomorphic-strings + */ +public class Isomorphic { + /** + * 简单解法 + * + * 字符串中,同一个位置的字符在本串中第一次出现的位置相同。我简单解释一下,本题判定为false有这些个情况,我们假设拿s串和t串作对比 + * 1.s串中相同的字符,对应的t串中的字符并不相等 + * 2.s串中不同的字符,对应的t串中的字符却是相等的 + * 所以判断的关键点就是相同的字符要对应相同的字符,那么相同字符处于后位置的字符的第一次出现的位置就应该相同。 + * 所以我们在判断时,只需要判断两个字符串同位置的字符是否相同即可。 + * + * @param s + * @param t + * @return + */ + public boolean isIsomorphic(String s, String t) { + char[] ch1 = s.toCharArray(); + char[] ch2 = t.toCharArray(); + int len = s.length(); + for (int i = 0; i < len; i++) { + if(s.indexOf(ch1[i]) != t.indexOf(ch2[i])){ + return false; + } + } + return true; + } + + /** + * Hash 方法 + * @param s + * @param t + * @return + */ + public boolean isIsomorphicHash(String s, String t) { + Map map = new HashMap<>(); + if(s.length()!=t.length())return false; + + for(int i = 0;i Jset = new HashSet(); + for (char j: J.toCharArray()) + Jset.add(j); + + int ans = 0; + for (char s: S.toCharArray()) + if (Jset.contains(s)) + ans++; + return ans; + } +} diff --git a/Week 08/id_306/LengthOfLastWord.java b/Week 08/id_306/LengthOfLastWord.java new file mode 100644 index 000000000..ec244c93a --- /dev/null +++ b/Week 08/id_306/LengthOfLastWord.java @@ -0,0 +1,23 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/length-of-last-word + */ +public class LengthOfLastWord { + // 常规解法 + public int lengthOfLastWord(String s) { + s = s.trim(); + int start = s.lastIndexOf(" ") + 1; + return s.substring(start).length(); + } + // 另一种解法 + public int lengthOfLastWordOther(String s) { + int end = s.length() - 1; + while(end >= 0 && s.charAt(end) == ' ') end--; + if(end < 0) return 0; + int start = end; + while(start >= 0 && s.charAt(start) != ' ') start--; + return end - start; + } +} diff --git a/Week 08/id_306/LongestIncreasingSubsequence.java b/Week 08/id_306/LongestIncreasingSubsequence.java new file mode 100644 index 000000000..743803831 --- /dev/null +++ b/Week 08/id_306/LongestIncreasingSubsequence.java @@ -0,0 +1,24 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/longest-increasing-subsequence + */ +public class LongestIncreasingSubsequence { + // dp + 二分查找 + public int lengthOfLIS(int[] nums) { + int[] tails = new int[nums.length]; + int res = 0; + for(int num : nums) { + int i = 0, j = res; + while(i < j) { + int m = (i + j) / 2; + if(tails[m] < num) i = m + 1; + else j = m; + } + tails[i] = num; + if(res == j) res++; + } + return res; + } +} diff --git a/Week 08/id_306/LongestPalindromicSubstring.java b/Week 08/id_306/LongestPalindromicSubstring.java new file mode 100644 index 000000000..5f601b791 --- /dev/null +++ b/Week 08/id_306/LongestPalindromicSubstring.java @@ -0,0 +1,36 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/8. + */ +public class LongestPalindromicSubstring { + /** + * 扩展中心 + * 多钟解法查看 https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-bao-gu/ + * @param s + * @return + */ + public String longestPalindrome(String s) { + if (s == null || s.length() < 1) return ""; + int start = 0, end = 0; + for (int i = 0; i < s.length(); i++) { + int len1 = expandAroundCenter(s, i, i); + int len2 = expandAroundCenter(s, i, i + 1); + int len = Math.max(len1, len2); + if (len > end - start) { + start = i - (len - 1) / 2; + end = i + len / 2; + } + } + return s.substring(start, end + 1); + } + + private int expandAroundCenter(String s, int left, int right) { + int L = left, R = right; + while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) { + L--; + R++; + } + return R - L - 1; + } +} diff --git a/Week 08/id_306/LongestValidParentheses.java b/Week 08/id_306/LongestValidParentheses.java new file mode 100644 index 000000000..5bb08704c --- /dev/null +++ b/Week 08/id_306/LongestValidParentheses.java @@ -0,0 +1,67 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/6. + * 力扣题目地址:https://leetcode-cn.com/problems/edit-distance/ + */ +public class LongestValidParentheses { + + /** + * 动态规划 一维数组 + * @param s + * @return + */ + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + // 右括号前边是左括号 + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + // 右括号前边是右括号,并且除去前边的合法序列的前边是左括号 + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } + + /** + * 神奇的解法 看题解看到的 很有意思 + * https://leetcode-cn.com/problems/longest-valid-parentheses/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-7/ + * @param s + * @return + */ + public int longestValidParentheses2(String s) { + int left = 0, right = 0, maxlength = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * right); + } else if (right >= left) { + left = right = 0; + } + } + left = right = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * left); + } else if (left >= right) { + left = right = 0; + } + } + return maxlength; + } +} diff --git a/Week 08/id_306/MaximalRectangle.java b/Week 08/id_306/MaximalRectangle.java new file mode 100644 index 000000000..d6d1a5092 --- /dev/null +++ b/Week 08/id_306/MaximalRectangle.java @@ -0,0 +1,118 @@ +package sf.week8; + +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/maximal-rectangle + */ +public class MaximalRectangle { + /** + * 官方题解 + * @param matrix + * @return + */ + public int maximalRectangle(char[][] matrix) { + if (matrix.length == 0) return 0; + int m = matrix.length; + int n = matrix[0].length; + + int[] left = new int[n]; // initialize left as the leftmost boundary possible + int[] right = new int[n]; + int[] height = new int[n]; + + Arrays.fill(right, n); // initialize right as the rightmost boundary possible + + int maxarea = 0; + for (int i = 0; i < m; i++) { + int cur_left = 0, cur_right = n; + // update height + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') height[j]++; + else height[j] = 0; + } + // update left + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') left[j] = Math.max(left[j], cur_left); + else { + left[j] = 0; + cur_left = j + 1; + } + } + // update right + for (int j = n - 1; j >= 0; j--) { + if (matrix[i][j] == '1') right[j] = Math.min(right[j], cur_right); + else { + right[j] = n; + cur_right = j; + } + } + // update area + for (int j = 0; j < n; j++) { + maxarea = Math.max(maxarea, (right[j] - left[j]) * height[j]); + } + } + return maxarea; + } + + /** + * 容易懂的 注释详细 + * 出处:https://leetcode-cn.com/problems/maximal-rectangle/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-1-8 + * @param matrix + * @return + */ + public int maximalRectangle4(char[][] matrix) { + if (matrix.length == 0) { + return 0; + } + int maxArea = 0; + int cols = matrix[0].length; + int[] leftLessMin = new int[cols]; + int[] rightLessMin = new int[cols]; + Arrays.fill(leftLessMin, -1); //初始化为 -1,也就是最左边 + Arrays.fill(rightLessMin, cols); //初始化为 cols,也就是最右边 + int[] heights = new int[cols]; + for (int row = 0; row < matrix.length; row++) { + //更新所有高度 + for (int col = 0; col < cols; col++) { + if (matrix[row][col] == '1') { + heights[col] += 1; + } else { + heights[col] = 0; + } + } + //更新所有leftLessMin + int boundary = -1; //记录上次出现 0 的位置 + for (int col = 0; col < cols; col++) { + if (matrix[row][col] == '1') { + //和上次出现 0 的位置比较 + leftLessMin[col] = Math.max(leftLessMin[col], boundary); + } else { + //当前是 0 代表当前高度是 0,所以初始化为 -1,防止对下次循环的影响 + leftLessMin[col] = -1; + //更新 0 的位置 + boundary = col; + } + } + //右边同理 + boundary = cols; + for (int col = cols - 1; col >= 0; col--) { + if (matrix[row][col] == '1') { + rightLessMin[col] = Math.min(rightLessMin[col], boundary); + } else { + rightLessMin[col] = cols; + boundary = col; + } + } + + //更新所有面积 + for (int col = cols - 1; col >= 0; col--) { + int area = (rightLessMin[col] - leftLessMin[col] - 1) * heights[col]; + maxArea = Math.max(area, maxArea); + } + + } + return maxArea; + + } +} diff --git a/Week 08/id_306/NOTE.md b/Week 08/id_306/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_306/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_306/RaceCar.java b/Week 08/id_306/RaceCar.java new file mode 100644 index 000000000..52a56453a --- /dev/null +++ b/Week 08/id_306/RaceCar.java @@ -0,0 +1,29 @@ +package sf.week8; + +import java.util.Arrays; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/race-car + */ +public class RaceCar { + public int racecar(int target) { + int[] dp = new int[target + 3]; + Arrays.fill(dp, Integer.MAX_VALUE); + dp[0] = 0; dp[1] = 1; dp[2] = 4; + + for (int t = 3; t <= target; ++t) { + int k = 32 - Integer.numberOfLeadingZeros(t); + if (t == (1< 'Z' && chars[i] < 'a') || chars[i] > 'z')) i++; + while (i < j && (chars[j] < 'A' || (chars[j] > 'Z' && chars[j] < 'a') || chars[j] > 'z')) j--; + if(i < j) { + chars[i] ^= chars[j]; + chars[j] ^= chars[i]; + chars[i++] ^= chars[j--]; + } + } + return String.valueOf(chars); + } + + // 反转指针 + public String reverseOnlyLetters1(String S) { + StringBuilder ans = new StringBuilder(); + int j = S.length() - 1; + for (int i = 0; i < S.length(); ++i) { + if (Character.isLetter(S.charAt(i))) { + while (!Character.isLetter(S.charAt(j))) + j--; + ans.append(S.charAt(j--)); + } else { + ans.append(S.charAt(i)); + } + } + + return ans.toString(); + } +} diff --git a/Week 08/id_306/ReverseString.java b/Week 08/id_306/ReverseString.java new file mode 100644 index 000000000..0ef8c2957 --- /dev/null +++ b/Week 08/id_306/ReverseString.java @@ -0,0 +1,23 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/reverse-string + */ +public class ReverseString { + // 双指针 + public void reverseString(char[] s) { + if (s == null || s.length < 2) { + return; + } + int left = -1; + int right = s.length; + while (++left < --right) { + char c = s[left]; + s[left] = s[right]; + s[right] = c; + } + + return; + } +} diff --git a/Week 08/id_306/ReverseWords.java b/Week 08/id_306/ReverseWords.java new file mode 100644 index 000000000..3543518a9 --- /dev/null +++ b/Week 08/id_306/ReverseWords.java @@ -0,0 +1,36 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/reverse-words-in-a-string + */ +public class ReverseWords { + // O(1)空间复杂度 用char数组完成 + public String reverseWords(String s) { + if (null == s || s.length() == 0) + return ""; + final char[] c = s.toCharArray(); + final int len = c.length; + int i = len - 1; + + while (i >= 0 && c[i] == ' ') i--; + + int left = i + 1; + int right = i + 1; + StringBuffer sb = new StringBuffer(i + 1); + + + for (; i >= 0; i--) { + if (c[i] == ' ') { + if (right != left) sb.append(c, left, right - left).append(" "); + left = i; + right = i; + continue; + } + left = i; + } + if (right != left) + return sb.append(c, left, right - left).toString(); + return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : ""; + } +} diff --git a/Week 08/id_306/ReverseWordsIII.java b/Week 08/id_306/ReverseWordsIII.java new file mode 100644 index 000000000..18cce3a20 --- /dev/null +++ b/Week 08/id_306/ReverseWordsIII.java @@ -0,0 +1,36 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/8. + * 力扣题目地址:https://leetcode-cn.com/problems/reverse-words-in-a-string-iii + */ +public class ReverseWordsIII { + + public String reverseWords(String s) { + String words[] = s.split(" "); + StringBuilder res=new StringBuilder(); + for (String word: words) + res.append(new StringBuffer(word).reverse().toString() + " "); + return res.toString().trim(); + } + /** + * 官方题解 + * @param input + * @return + */ + public String reverseWords1(String input) { + final StringBuilder result = new StringBuilder(); + final StringBuilder word = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + if (input.charAt(i) != ' ') { + word.append(input.charAt(i)); + } else { + result.append(word.reverse()); + result.append(" "); + word.setLength(0); + } + } + result.append(word.reverse()); + return result.toString(); + } +} diff --git a/Week 08/id_306/SellStockFour.java b/Week 08/id_306/SellStockFour.java new file mode 100644 index 000000000..431cd9aff --- /dev/null +++ b/Week 08/id_306/SellStockFour.java @@ -0,0 +1,45 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/6. + * 力扣题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv + */ +public class SellStockFour { + public int maxProfit(int k, int[] prices) { + if (prices == null || prices.length < 1 || k < 1) { + return 0; + } + if (k > prices.length >> 1) { + return maxProfit(prices); + } + // 初始化 dp 数组,第 i 天,第 k 笔 交易,是否持有股票,1 持有,0 不持有 + int[][][] mp = new int[prices.length][k + 1][2]; + // 初始化第一天数据,买入股票 + for (int i = 1; i < k+1; i++) { + mp[0][i][1] = -prices[0]; + } + // 依次递归最大收益 + for (int i = 1; i < prices.length; i++) { + for (int j = 1; j <= k; j++) { + // 第 i 天,第 j 笔 交易,不持有股票的最大值= + // 前一天持有股票今天卖出 / 前一天不持有股票,保持不变 + mp[i][j][0] = Math.max(mp[i - 1][j][0], mp[i - 1][j][1] + prices[i]); + // 第 i 天,第 j 笔 交易,持有股票的最大值= + // 前一天不持有股票今天买入 / 前一天持有股票,保持不变 + mp[i][j][1] = Math.max(mp[i - 1][j][1], mp[i - 1][j - 1][0] - prices[i]); + } + } + return mp[prices.length - 1][k][0]; // 最大利润 + } + // 不限制交易次数 + public int maxProfit(int[] prices) { + int profit = 0; + // 贪婪算法,存在利润就卖出 + for (int i = 0; i < prices.length-1; i++) { + if (prices[i] < prices[i + 1]) { + profit += prices[i + 1] - prices[i]; + } + } + return profit; + } +} diff --git a/Week 08/id_306/StringToIntegerAtoi.java b/Week 08/id_306/StringToIntegerAtoi.java new file mode 100644 index 000000000..d33b994b3 --- /dev/null +++ b/Week 08/id_306/StringToIntegerAtoi.java @@ -0,0 +1,42 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/string-to-integer-atoi + */ +public class StringToIntegerAtoi { + //最好的解法 还加了溢出判断 + public int myAtoi(String str) { + if (str == null) return 0; + str = str.trim(); + if (str.length() == 0) return 0; + int i = 0; + //2.判断数字的符号 + int flag = 1; + char ch = str.charAt(i); + if (ch == '+') { + i++; + } else if (ch == '-') { + flag = -1; + i++; + } + //3.找出数字部分 + int res = 0; + for (; i < str.length(); i++) { + ch = str.charAt(i); + if (ch < '0' || ch > '9') + break; + //溢出判断 + if (flag > 0 && res > Integer.MAX_VALUE / 10) + return Integer.MAX_VALUE; + if (flag > 0 && res == Integer.MAX_VALUE / 10 && ch - '0' > Integer.MAX_VALUE % 10) + return Integer.MAX_VALUE; + if (flag < 0 && -res < Integer.MIN_VALUE / 10) + return Integer.MIN_VALUE; + if (flag < 0 && -res == Integer.MIN_VALUE / 10 && -(ch - '0') < Integer.MIN_VALUE % 10) + return Integer.MIN_VALUE; + res = res * 10 + ch - '0'; + } + return res * flag; + } +} diff --git a/Week 08/id_306/ToLowerCase.java b/Week 08/id_306/ToLowerCase.java new file mode 100644 index 000000000..3e3df917c --- /dev/null +++ b/Week 08/id_306/ToLowerCase.java @@ -0,0 +1,21 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/7. + * 力扣题目地址:https://leetcode-cn.com/problems/to-lower-case + */ +public class ToLowerCase { + // Java 最好的解法 + public String toLowerCase(String str) { + char[] st = new char[str.length()]; + char c; + for (int i = 0; i < str.length(); i++) { + c = str.charAt(i); + if (c >= 65 && c <= 90) { + c = (char) (c + 32); + } + st[i] = c; + } + return new String(st); + } +} diff --git a/Week 08/id_306/UniquePathsTwo.java b/Week 08/id_306/UniquePathsTwo.java new file mode 100644 index 000000000..3176429f3 --- /dev/null +++ b/Week 08/id_306/UniquePathsTwo.java @@ -0,0 +1,34 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/6. + * 力扣题目地址:https://leetcode-cn.com/problems/unique-paths-ii + */ +public class UniquePathsTwo { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid == null) return 0; + int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length]; + // 第一个数 + dp[0][0] = obstacleGrid[0][0] == 0 ? 1 : 0; + if (dp[0][0] == 0) return 0; + // 第一行 + for (int j = 1; j < obstacleGrid[0].length; j++) { + if (obstacleGrid[0][j] != 1) { + dp[0][j] = dp[0][j - 1]; + } + } + // 第一列 + for (int i = 1; i < obstacleGrid.length; i++) { + if (obstacleGrid[i][0] != 1) { + dp[i][0] = dp[i - 1][0]; + } + } + + for (int i = 1; i < obstacleGrid.length; i++) { + for (int j = 1; j < obstacleGrid[0].length; j++) { + if (obstacleGrid[i][j] != 1) dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[obstacleGrid.length - 1][obstacleGrid[0].length - 1]; + } +} diff --git a/Week 08/id_306/ValidPalindromeII.java b/Week 08/id_306/ValidPalindromeII.java new file mode 100644 index 000000000..df442a30f --- /dev/null +++ b/Week 08/id_306/ValidPalindromeII.java @@ -0,0 +1,29 @@ +package sf.week8; + +/** + * Created by LynnSun on 2019/12/8. + * 力扣题目地址:https://leetcode-cn.com/problems/valid-palindrome-ii + */ +public class ValidPalindromeII { + public boolean validPalindrome(String s) { + char[] chars = s.toCharArray(); + int left=0, right=chars.length-1,deleteIndex=-1; + while (left= 0; i--) { + for (int j = pattern.length(); j >= 0; j--) { + // dp[text.length()][pattern.length()] 已经进行了初始化 + if (i == text.length() && j == pattern.length()) + continue; + //相比之前增加了判断是否等于 * + boolean first_match = (i < text.length() && j < pattern.length() && (pattern.charAt(j) == text.charAt(i) || pattern.charAt(j) == '?' || pattern.charAt(j) == '*')); + if (j < pattern.length() && pattern.charAt(j) == '*') { + //将 * 跳过 和将字符匹配一个并且 pattern 不变两种情况 + dp[i][j] = dp[i][j + 1] || first_match && dp[i + 1][j]; + } else { + dp[i][j] = first_match && dp[i + 1][j + 1]; + } + } + } + return dp[0][0]; + } + + /** + * 优化空间复杂度 + * https://leetcode-cn.com/problems/wildcard-matching/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-9/ + * @param text + * @param pattern + * @return + */ + public boolean isMatch1(String text, String pattern) { + // 多一维的空间,因为求 dp[len - 1][j] 的时候需要知道 dp[len][j] 的情况, + // 多一维的话,就可以把 对 dp[len - 1][j] 也写进循环了 + boolean[][] dp = new boolean[2][pattern.length() + 1]; + dp[text.length() % 2][pattern.length()] = true; + + // 从 len 开始减少 + for (int i = text.length(); i >= 0; i--) { + for (int j = pattern.length(); j >= 0; j--) { + if (i == text.length() && j == pattern.length()) + continue; + boolean first_match = (i < text.length() && j < pattern.length() && (pattern.charAt(j) == text.charAt(i) + || pattern.charAt(j) == '?' || pattern.charAt(j) == '*')); + if (j < pattern.length() && pattern.charAt(j) == '*') { + dp[i % 2][j] = dp[i % 2][j + 1] || first_match && dp[(i + 1) % 2][j]; + } else { + dp[i % 2][j] = first_match && dp[(i + 1) % 2][j + 1]; + } + } + } + return dp[0][0]; + } +} diff --git a/Week 08/id_311/LeetCode_300_Solution.java b/Week 08/id_311/LeetCode_300_Solution.java new file mode 100644 index 000000000..796d9ac07 --- /dev/null +++ b/Week 08/id_311/LeetCode_300_Solution.java @@ -0,0 +1,17 @@ +public class Solution { + public int lengthOfLIS(int[] nums) { + int[] dp = new int[nums.length]; + int len = 0; + for (int num : nums) { + int i = Arrays.binarySearch(dp, 0, len, num); + if (i < 0) { + i = -(i + 1); + } + dp[i] = num; + if (i == len) { + len++; + } + } + return len; + } +} diff --git a/Week 08/id_311/LeetCode_58_Solution.java b/Week 08/id_311/LeetCode_58_Solution.java new file mode 100644 index 000000000..964660ceb --- /dev/null +++ b/Week 08/id_311/LeetCode_58_Solution.java @@ -0,0 +1,10 @@ +class Solution { + public int lengthOfLastWord(String s) { + int end = s.length() - 1; + while(end >= 0 && s.charAt(end) == ' ') end--; + if(end < 0) return 0; + int start = end; + while(start >= 0 && s.charAt(start) != ' ') start--; + return end - start; + } +} \ No newline at end of file diff --git a/Week 08/id_311/NOTE.md b/Week 08/id_311/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_311/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_316/NOTE.md b/Week 08/id_316/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_316/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_321/NOTE.md b/Week 08/id_321/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_321/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_326/NOTE.md b/Week 08/id_326/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_326/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_331/NOTE.md b/Week 08/id_331/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_331/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_336/LeetCode_336_300.js b/Week 08/id_336/LeetCode_336_300.js new file mode 100644 index 000000000..f6dcf70bf --- /dev/null +++ b/Week 08/id_336/LeetCode_336_300.js @@ -0,0 +1,22 @@ +// #### 解法:动态规划 +/** + * @param {number[]} nums + * @return {number} + */ +var lengthOfLIS = function(nums) { + let n = nums.length; + if(n == 0){ + return 0; + } + let dp = new Array(n).fill(1); + let max = 0; + for(let i = 0;i < n;i++){ + for(let j = 0;j < i;j++){ + if(nums[j] < nums[i]){ + dp[i] = Math.max(dp[i],dp[j]+1); + } + } + max = Math.max(max,dp[i]); + } + return max; +}; \ No newline at end of file diff --git a/Week 08/id_336/LeetCode_336_387.js b/Week 08/id_336/LeetCode_336_387.js new file mode 100644 index 000000000..903ec6cb2 --- /dev/null +++ b/Week 08/id_336/LeetCode_336_387.js @@ -0,0 +1,35 @@ +// #### 解法一:哈希 + 遍历 +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + let hash = {}; + let result = []; + for(let i = 0;i < s.length;i++){ + if(!hash[s[i]]){ + hash[s[i]] = 1; + }else{ + hash[s[i]]++; + } + } + for(let j = 0;j < s.length;j++){ + if(hash[s[j]] == 1){ + return j; + } + } + return -1; +}; +// #### 解法二:库函数 +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + for(let i = 0;i < s.length;i++){ + if(s.indexOf(s[i]) == s.lastIndexOf(s[i])){ + return i; + } + } + return -1; +}; \ No newline at end of file diff --git a/Week 08/id_336/LeetCode_336_91.js b/Week 08/id_336/LeetCode_336_91.js new file mode 100644 index 000000000..42ae4b961 --- /dev/null +++ b/Week 08/id_336/LeetCode_336_91.js @@ -0,0 +1,22 @@ +// #### 解法:动态规划 +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function(s) { + if(s[0] == 0){ + return 0; + } + let n = s.length; + let dp = new Array(n+1).fill(0); + dp[0] = dp[1] = 1; + for(let i = 2;i <= n;i++){ + if(s[i-1] != 0){ + dp[i] += dp[i-1]; + } + if((s[i-2] == 1) || (s[i-2] == 2 && s[i-1] <= 6)){ + dp[i] += dp[i-2]; + } + } + return dp[n]; +} \ No newline at end of file diff --git a/Week 08/id_336/NOTE.md b/Week 08/id_336/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_336/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_341/NOTE.md b/Week 08/id_341/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_341/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_346/LeetCode_387_346.java b/Week 08/id_346/LeetCode_387_346.java new file mode 100644 index 000000000..b6169540d --- /dev/null +++ b/Week 08/id_346/LeetCode_387_346.java @@ -0,0 +1,27 @@ +package suanfa; + +import java.util.HashMap; + +/** + * @auther: TKQ + * @Title: LeetCode_387_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-12-08 17:41 + */ +public class LeetCode_387_346 { + + public int firstUniqChar(String s) { + HashMap hm = new HashMap(); + for (int i = 0; i < s.length(); i++) { + hm.put(s.charAt(i), hm.getOrDefault(s.charAt(i), 0) + 1); + } + for (int i = 0; i < s.length(); i++) { + if (hm.get(s.charAt(i)) == 1) { + return i; + } + } + return -1; + } +} diff --git a/Week 08/id_346/LeetCode_91_346.java b/Week 08/id_346/LeetCode_91_346.java new file mode 100644 index 000000000..03a18c7c1 --- /dev/null +++ b/Week 08/id_346/LeetCode_91_346.java @@ -0,0 +1,40 @@ +package suanfa; + +/** + * @auther: TKQ + * @Title: LeetCode_91_346 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-12-08 18:00 + */ +public class LeetCode_91_346 { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + //help用来存储res以前的值 + help = res-help; + } else { + help = res; + } + + } + return res; + } +} diff --git a/Week 08/id_346/NOTE.md b/Week 08/id_346/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_346/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_351/NOTE.md b/Week 08/id_351/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_351/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_356/NOTE.md b/Week 08/id_356/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_356/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_361/NOTE.md b/Week 08/id_361/NOTE.md new file mode 100755 index 000000000..41ad3c242 --- /dev/null +++ b/Week 08/id_361/NOTE.md @@ -0,0 +1,32 @@ +## 高级DP +复杂度来源 +1.状态拥有更多的维度(二维、三维、或者更多、甚至需要压缩) +2.状态方程更加复杂 + +本质:内功、逻辑思维、数学 + +爬楼梯问题改进 +前后不能走相同的步数 + +编辑距离 + +## 字符串算法 +### 字符串基础 +- 字符串操作 +- 异位词问题 +- 回文串问题 +### 高级字符串算法 +- 最长子串、子序列问题 +- 字符串 +DP 问题 + +1.暴力递归 +2.动态规划 +dp[i][j] 代表T前i字符串可以由s前j字符串组成最多个数 +所以动态方程 +当S[j]==T[i],dp[i][j]=dp[i-1][j-1]+dp[i][j-1] +当S[j]!=T[i],dp[i][j]=dp[i][j-1] + +### 字符串匹配算法 +1.暴力法(brute force)O(mn) +2.Rabin-karp 算法 +3.KMP算法 diff --git a/Week 08/id_361/leetCode_32_361.js b/Week 08/id_361/leetCode_32_361.js new file mode 100644 index 000000000..2906008a6 --- /dev/null +++ b/Week 08/id_361/leetCode_32_361.js @@ -0,0 +1,59 @@ +/** + * @param {string} s + * @return {number} + */ +var longestValidParentheses = function(s) { + var max = 0; + var stack = [-1]; + for(var i = 0;i < s.length;i++){ + if(s[i] == '('){ + stack.push(i); + }else{ + stack.pop(); + if(stack.length == 0){ + stack.push(i); + }else{ + max = Math.max(max,i - stack[stack.length-1]); + } + } + } + return max; +}; + +//dp +/** + * @param {string} s + * @return {number} + */ +var longestValidParentheses = function(s) { + var max = 0; + var left = 0; + var right = 0; + for(var i = 0;i < s.length;i++){ + if(s[i] == '('){ + left++; + }else{ + right++; + } + if( left == right){ + max = Math.max(max,2 * left); + }else if(right > left){ + left = right = 0; + } + } + left = right = 0; + for(var i = s.length-1;i >= 0;i--){ + if(s[i] == '('){ + left++; + }else{ + right++; + } + if(left == right){ + max = Math.max(max,right * 2); + }else if(left > right){ + left = right = 0; + } + } + return max; +}; + diff --git a/Week 08/id_361/leetCode_387_361.js b/Week 08/id_361/leetCode_387_361.js new file mode 100644 index 000000000..9a8ca9058 --- /dev/null +++ b/Week 08/id_361/leetCode_387_361.js @@ -0,0 +1,101 @@ +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + let hash = {}; + let result = new Map(); + for(let i = 0;i < s.length;i++){ + if(!hash[s[i]]){ + hash[s[i]] = 1; + result.set(s[i],i); + }else{ + result.delete(s[i]); + } + } + if(result.size == 0){ + return -1; + } + return result.values().next().value; +}; + +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + let hash = {}; + let result = []; + for(let i = 0;i < s.length;i++){ + if(!hash[s[i]]){ + hash[s[i]] = 1; + }else{ + hash[s[i]]++; + } + } + for(let j = 0;j < s.length;j++){ + if(hash[s[j]] == 1){ + return j; + } + } + return -1; +}; + +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + for(let i = 0;i < s.length;i++){ + if(s.indexOf(s[i]) == s.lastIndexOf(s[i])){ + return i; + } + } + return -1; +}; + +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + let countingSort = (arr,maxValue) => { + let bucket = new Array(maxValue).fill(0); + let arrLen = arr.length; + for(let i = 0;i < arrLen;i++){ + bucket[arr[i].charCodeAt() - 97]++; + } + for(let j = 0;j < arrLen;j++){ + if(bucket[arr[j].charCodeAt() - 97] == 1){ + return j; + } + } + return -1; + } + return countingSort(s,26) +}; + +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function(s) { + if(s.length === 1) { + return 0; + } + let base = ['a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z' + ]; + let minIndex = Number.MAX_SAFE_INTEGER, firstIndex; + for(let i = 0; i < base.length; i++) { + firstIndex = s.indexOf(base[i]); + if(firstIndex >=0 && firstIndex === s.lastIndexOf(base[i])) { + minIndex = Math.min(minIndex, firstIndex); + } + } + return (minIndex ^ Number.MAX_SAFE_INTEGER) == 0 ? -1 : minIndex; +}; + + diff --git a/Week 08/id_366/Leetcode_115_366.java b/Week 08/id_366/Leetcode_115_366.java new file mode 100644 index 000000000..e335a1b29 --- /dev/null +++ b/Week 08/id_366/Leetcode_115_366.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=115 lang=java + * + * [115] 不同的子序列 + */ + +// @lc code=start +class Solution { + public int numDistinct(String s, String t) { + int[][] dp = new int[t.length() + 1][s.length() + 1]; + for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1; + for (int i = 1; i < t.length() + 1; i++) { + for (int j = 1; j < s.length() + 1; j++) { + if (t.charAt(i - 1) == s.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]; + else dp[i][j] = dp[i][j - 1]; + } + } + return dp[t.length()][s.length()]; + } +} +// @lc code=end + diff --git a/Week 08/id_366/Leetcode_387_366.java b/Week 08/id_366/Leetcode_387_366.java new file mode 100644 index 000000000..0116f5f9b --- /dev/null +++ b/Week 08/id_366/Leetcode_387_366.java @@ -0,0 +1,23 @@ +/* + * @lc app=leetcode.cn id=387 lang=java + * + * [387] 字符串中的第一个唯一字符 + */ + +// @lc code=start +class Solution { + public int firstUniqChar(String s) { + Map map = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1); + } + for (int i = 0; i < s.length(); i++) { + if (map.get(s.charAt(i)) == 1) { + return i; + } + } + return -1; + } +} +// @lc code=end + diff --git a/Week 08/id_366/NOTE.md b/Week 08/id_366/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_366/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_371/Leetcode_387_371.java b/Week 08/id_371/Leetcode_387_371.java new file mode 100644 index 000000000..a7e5bfdc8 --- /dev/null +++ b/Week 08/id_371/Leetcode_387_371.java @@ -0,0 +1,74 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-05 11:31 + **/ + +public class Leetcode_387_371 { + public static void main(String[] args) { +// String s = "leetcode"; +// String s = "llttnn"; + String s = "loveleetcode"; + int i = firstUniqChar2(s); + System.out.println("i = " + i); + } + + public static int firstUniqChar(String s) { + Map map = new HashMap<>(); + //1.一次遍历,放入 map(0,l) + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + //2.存在删除 + if(map.containsKey(ch)) map.put(ch, i + 1); + else map.put(s.charAt(i), i); + + } + //3.按顺序取,取到就返回 + for (int i = 0; i < s.length(); i++) { + Integer integer = map.get(s.charAt(i)); + if (integer == i) return i; + } + return -1; + } + + /** + * 防解: + * @author Shaobo.Qian + * @date 2019/12/6 + * @link https://leetcode-cn.com/problems/first-unique-character-in-a-string/solution/zi-fu-chuan-zhong-de-di-yi-ge-wei-yi-zi-fu-by-leet/ + */ + public static int firstUniqChar1(String s) { + Map map = new HashMap<>(); + //1.一次遍历,放入 map(0,l) + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + //2.存在删除 + map.put(ch, map.getOrDefault(ch, 0) + 1); + } + //3.按顺序取,取到就返回 + for (int i = 0; i < s.length(); i++) { + if (map.get(s.charAt(i)) == 1) return i; + } + return -1; + } + + /** + * 防解2:字符转数组 + * @author Shaobo.Qian + * @date 2019/12/6 + */ + public static int firstUniqChar2(String s) { + int[] letter = new int[26]; + for (char ch : s.toCharArray()) { + letter[ch - 'a']++; + } + for (int i = 0; i < s.length(); i++) { + if (letter[s.charAt(i)-'a'] == 1) return i; + } + return -1; + } +} diff --git a/Week 08/id_371/Leetcode_438_371.java b/Week 08/id_371/Leetcode_438_371.java new file mode 100644 index 000000000..f52652f9b --- /dev/null +++ b/Week 08/id_371/Leetcode_438_371.java @@ -0,0 +1,67 @@ +import java.util.*; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-07 09:41 + **/ + +public class Leetcode_438_371 { + public static void main(String[] args) { +// String s = "cbaebabacd", p = "abc"; + String s = "abab", p = "ab"; + List anagrams = findAnagrams(s, p); + anagrams.stream().forEach(System.out::println); + } + + public static List findAnagrams(String s, String p) { + //0.处理边界 + int sLen = s.length(); + int pLen = p.length(); + //1.定义数组记录异位词的索引位置 + List indexs = new ArrayList<>(); + if (pLen > sLen) return indexs; + //2.以 p 的长度为单位从左到右滑动 + char[] pChar = p.toCharArray(); + char[] sChar = s.substring(0, pLen).toCharArray(); + for (int i = pLen; i < sLen; i++) { + char newChar = s.charAt(pLen); + //3.判断是否是异位词 + if (isAnagrams(sChar, pChar, newChar)) { + indexs.add(i); + } + } + return indexs; + } + + /** + * 记录每个字符出现的次数 + * + * @author Shaobo.Qian + * @date 2019/12/7 + */ + private static boolean isAnagrams(char[] sChar, char[] pChar,char newChar) { + //0.先判断 hash 值是否一样 + if(!sameHash(sChar,pChar,newChar)) return false; + //1.创建map + Map map = new HashMap<>(); + //2.记录 s 中的字符个数 + for (char sCh : sChar) { + map.put(sCh, map.getOrDefault(sCh, 0) + 1); + } + //3.在 p 中比较 + for (char pCh : pChar) { + if (!map.containsKey(pCh) || map.get(pCh) < 1) return false; + map.put(pCh, map.get(pCh) - 1); + } + return true; + } + + private static boolean sameHash(char[] sChar, char[] pChar, char newChar) { + sChar[0] = newChar; + return false; + } + + +} diff --git a/Week 08/id_371/Leetcode_541_371.java b/Week 08/id_371/Leetcode_541_371.java new file mode 100644 index 000000000..0506f86d0 --- /dev/null +++ b/Week 08/id_371/Leetcode_541_371.java @@ -0,0 +1,77 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-06 08:59 + **/ + +public class Leetcode_541_371 { + public static void main(String[] args) { + String s = "abcdefgttabcdb"; + int k = 3; + //"bacdfeg" + String res = reverseStr1(s, k); + System.out.println("res = " + res); + } + + /** + * 原解1 + * + * @author Shaobo.Qian + * @date 2019/12/6 + */ + public static String reverseStr(String s, int k) { + + //1.以 k 分段, + StringBuilder sb = new StringBuilder(); + int begin = 0; + int len = s.length(); + boolean oddFlag = true; + while (begin + k <= len) { + // 2.获取奇数端翻转, + if (oddFlag) { + StringBuilder kSb = new StringBuilder(); + sb.append(kSb.append(s, begin, begin + k).reverse().toString()); + oddFlag = false; + } else { + // 3.获取偶数段不变 + oddFlag = true; + sb.append(s, begin, begin + k); + } + begin += k; + } + + //4.append the remaining + if (oddFlag) { + for (int i = len - 1; i >= begin; i--) { + sb.append(s.charAt(i)); + } + } else { + sb.append(s, begin, len); + } + return sb.toString(); + } + + + /** + * 防解 + * @author Shaobo.Qian + * @date 2019/12/7 + * @link https://leetcode-cn.com/problems/reverse-string-ii/solution/fan-zhuan-zi-fu-chuan-ii-by-leetcode/ + */ + public static String reverseStr1(String s, int k) { + char[] a = s.toCharArray(); + for (int begin = 0; begin < s.length(); begin += 2 * k) { + int i = begin, j = Math.min(begin + k - 1, s.length() - 1); + while (i < j) { + char temp = a[i]; + a[i++] = a[j]; + a[j--] = temp; + } + + } + return new String(a); + + } + +} diff --git a/Week 08/id_371/Leetcode_58_371.java b/Week 08/id_371/Leetcode_58_371.java new file mode 100644 index 000000000..b386bfd82 --- /dev/null +++ b/Week 08/id_371/Leetcode_58_371.java @@ -0,0 +1,43 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-05 08:37 + **/ + +public class Leetcode_58_371 { + public static void main(String[] args) { + String str = "Hello World"; +// String str = " A"; + int len = lengthOfLastWord1(str); + System.out.println("len = " + len); + } + + /** + * 原解1:正则 + * @author Shaobo.Qian + * @date 2019/12/5 + */ + public static int lengthOfLastWord(String s) { + //1.字符串-->单词数组 + String[] strArr = s.split("( )+"); + int len = strArr.length; + return len > 0 ? strArr[len - 1].length() : 0; + } + + /** + * 防解1: + * @author Shaobo.Qian + * @date 2019/12/5 + * @link https://leetcode-cn.com/problems/length-of-last-word/solution/hua-jie-suan-fa-58-zui-hou-yi-ge-dan-ci-de-chang-d/ + */ + public static int lengthOfLastWord1(String s) { + int endIndex = s.length() - 1; + while (endIndex>=0 && s.charAt(endIndex) == ' ') endIndex--; + if (endIndex < 0) return 0; + int wordIndex = endIndex; + while (wordIndex>=0 && s.charAt(wordIndex) != ' ') wordIndex--; + + return endIndex - wordIndex; + } +} diff --git a/Week 08/id_371/Leetcode_709_371.java b/Week 08/id_371/Leetcode_709_371.java new file mode 100644 index 000000000..bc1bfc611 --- /dev/null +++ b/Week 08/id_371/Leetcode_709_371.java @@ -0,0 +1,34 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-05 07:43 + **/ + +public class Leetcode_709_371 { + public static void main(String[] args) { + String res = toLowerCase1("ABbD"); + System.out.println("res.toString() = " + res); + + } + + public static String toLowerCase(String str) { + + char[] chars = str.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char ch = chars[i]; + if(ch >=65 && ch <=90) chars[i] = (char) (ch + 32); + } + + return String.valueOf(chars); + } + + public static String toLowerCase1(String str) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + sb.append((char) (str.charAt(i) | 32)); + } + return sb.toString(); + } + +} diff --git a/Week 08/id_371/Leetcode_771_371.java b/Week 08/id_371/Leetcode_771_371.java new file mode 100644 index 000000000..0a6457b83 --- /dev/null +++ b/Week 08/id_371/Leetcode_771_371.java @@ -0,0 +1,22 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-05 09:08 + **/ + +public class Leetcode_771_371 { + public static void main(String[] args) { + String J = "aA", S = "aAAbbbb"; + int cnt = numJewelsInStones(J, S); + System.out.println("cnt = " + cnt); + } + + public static int numJewelsInStones(String J, String S) { + int cnt = 0; + for (int i = 0; i < S.length(); i++) { + if(J.contains(String.valueOf(S.charAt(i)))) cnt++; + } + return cnt; + } +} diff --git a/Week 08/id_371/Leetcode_8_371.java b/Week 08/id_371/Leetcode_8_371.java new file mode 100644 index 000000000..5ea54952d --- /dev/null +++ b/Week 08/id_371/Leetcode_8_371.java @@ -0,0 +1,109 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-06 07:30 + **/ + +public class Leetcode_8_371 { + public static void main(String[] args) { +// String str = "words and 987"; +// String str = "-41933430000 with words"; +// String str = "0000 with words"; +// String str = "20000000000000000000"; +// String str = " -42"; +// String str = " 42"; + String str = "-000000000000001"; + +// String str = "+1"; + int i = myAtoi(str); + System.out.println("i = " + i); + } + + /** + * 原解 + * @author Shaobo.Qian + * @date 2019/12/6 + */ + public static int myAtoi(String str) { + + //1.处理空格 + str = str.trim(); + if (str.length() == 0) return 0; + String first = String.valueOf(str.charAt(0)); + if (!"+-0123456789".contains(first)) return 0; + boolean isPositive = false; + StringBuilder sb = new StringBuilder(); + //2.处理正负 + //去掉零 + boolean zeroflag = false; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i == 0) { + if (c == '+') { + isPositive = true; + continue; + } else if (c <= '9' && c >= '0') { + isPositive = true; + if (c == '0') { + continue; + } + zeroflag = true; + } else if (c == '-') { +// zeroflag = true; + continue; + } + } + if (zeroflag) { + if (c <= '9' && c >= '0') { + sb.append(c); + } else { + break; + } + } else { + if (c != '0') { + if (c <= '9' && c >= '0') { + sb.append(c); + zeroflag = true; + } else { + break; + } + } + } + } + + //3.转换成数字 + String res = sb.toString(); + +// Integer res; + if (res.length() == 0) return 0; + Integer result; + if (isPositive) { + if (res.length() > 10) { + result = Integer.MAX_VALUE; + } else { + + result = Math.toIntExact(Math.min(Long.parseLong(res), Integer.MAX_VALUE)); + } + } else { + if (res.length() > 10) { + result = Integer.MIN_VALUE; + } else { + result = Math.toIntExact(Math.max(0 - Long.parseLong(res), Integer.MIN_VALUE)); + } + } + //4.处理溢出 + + return result; + } + + /** + * 重构优化:使用 continue,break代替标记 + * @author Shaobo.Qian + * @date 2019/12/6 + */ + public static int myAtoi1(String str) { + return 0; + } + +} diff --git a/Week 08/id_371/Leetcode_917_371.java b/Week 08/id_371/Leetcode_917_371.java new file mode 100644 index 000000000..b81acd7d8 --- /dev/null +++ b/Week 08/id_371/Leetcode_917_371.java @@ -0,0 +1,48 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-12-07 08:06 + **/ + +public class Leetcode_917_371 { + public static void main(String[] args) { + String s = "Test1ng-Leet=code-Q!";//"Qedo1ct-eeLg=ntse-T!" + String s1 = reverseOnlyLetters(s); + System.out.println("s1 = " + s1); + + } + + public static String reverseOnlyLetters(String S) { + //0.临界判断 + int len = S.length(); + if (len <= 1) return S; + char[] c = S.toCharArray(); + //1.定义双指针,分别指向字符串首尾 + int i = 0, j = len - 1; + //2.移动2个指针 + while (i < j) { + //2.1两个指针都指向字母时,将两个字母交换,i+1,j-1 + if (isAlpha(c[i]) && (isAlpha(c[j]))) { + char temp = c[i]; + c[i++] = c[j]; + c[j--] = temp; + } else if (isAlpha(c[i])) { + //2.2 i 指向字母,j 指向非字母,i 不变,j-1 + j--; + } else if (isAlpha(c[j])) { + //2.3 i 指向非字母,j 指向字母,i+1,j 不变 + i++; + } else { + //2.4 i,j 都指向非字母,i+1,j-1 + i++; + j--; + } + } + return new String(c); + } + + private static boolean isAlpha(char c) { + return (65 <= c && c <= 90) || (97 <= c && c <= 122); + } +} diff --git a/Week 08/id_371/NOTE.md b/Week 08/id_371/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_371/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_376/NOTE.md b/Week 08/id_376/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_376/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_381/NOTE.md b/Week 08/id_381/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_381/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_381/leetcode_387.py b/Week 08/id_381/leetcode_387.py new file mode 100644 index 000000000..47203e783 --- /dev/null +++ b/Week 08/id_381/leetcode_387.py @@ -0,0 +1,12 @@ +class Solution: + def firstUniqChar(self, s: str) -> int: + cache = {} + for c in s: + if c in cache: + cache[c] += 1 + else: + cache[c] = 1 + for i in range(len(s)): + if cache[s[i]] == 1: + return i + return -1 diff --git a/Week 08/id_381/leetcode_70.py b/Week 08/id_381/leetcode_70.py new file mode 100644 index 000000000..242327b0c --- /dev/null +++ b/Week 08/id_381/leetcode_70.py @@ -0,0 +1,8 @@ +class Solution: + cache = [0, 1, 2] + def climbStairs(self, n: int) -> int: + if n < len(self.cache): + return self.cache[n] + for i in range(len(self.cache), n+1): + self.cache.append(self.cache[i-1] + self.cache[i-2]) + return self.cache[n] diff --git a/Week 08/id_386/LeetCode_115_386.java b/Week 08/id_386/LeetCode_115_386.java new file mode 100644 index 000000000..d94ebf9c9 --- /dev/null +++ b/Week 08/id_386/LeetCode_115_386.java @@ -0,0 +1,23 @@ +class Solution { + public int numDistinct(String s, String t) { + int sl = s.length(); + int tl = t.length(); + if(sl==0||tl==0)return 0; + if(sl nums[j]){ + tempLen = Math.max(dp[j] + 1,tempLen); + } + } + //记录以索引i结尾的子数组的最长上升子序列长度 + dp[i] = tempLen; + //记录此时的全局最优解 + if(tempLen > maxLen){ + maxLen = tempLen; + } + } + return maxLen; + } +} diff --git a/Week 08/id_386/NOTE.md b/Week 08/id_386/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_386/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_391/NOTE.md b/Week 08/id_391/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_391/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_396/LeetCode_387396.swift b/Week 08/id_396/LeetCode_387396.swift new file mode 100644 index 000000000..5c9ffd415 --- /dev/null +++ b/Week 08/id_396/LeetCode_387396.swift @@ -0,0 +1,27 @@ +// +// LeetCode_221_396.swift +// +// +// Created by chenjunzhi on 2019/11/17. +// + +import UIKit +class Solution { + func firstUniqChar(_ s: String) -> Int { + var chars = Array(s) + var dic: [Int] = Array(repeating: 0, count: 256) + for char in s { + dic[Int(char.asciiValue!)] = dic[Int(char.asciiValue!)] + 1 + } + + for i in 0.. String { + var array = s.components(separatedBy: " ") + array = array.map { (str) -> String in + return String(str.reversed()) + } + return array.joined(separator: " ") + } +} diff --git a/Week 08/id_396/NOTE.md b/Week 08/id_396/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_396/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_401/NOTE.md b/Week 08/id_401/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_401/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_406/Create Leetcode_205_406.py b/Week 08/id_406/Create Leetcode_205_406.py new file mode 100644 index 000000000..594fa09a6 --- /dev/null +++ b/Week 08/id_406/Create Leetcode_205_406.py @@ -0,0 +1,21 @@ +class Solution: + def isIsomorphic(self, s: str, t: str) -> bool: + s2t = {} + mapped_t = set() + for i in range(len(s)): + if s[i] in s2t: + if s2t[s[i]] != t[i]: + return False + else: + if t[i] in mapped_t: + return False + mapped_t.add(t[i]) + s2t[s[i]] = t[i] + return True + + +def reverse(s,k): + a = list(s) + for i in xrange(0, len(a), 2*k): + a[i:i+k] = reversed(a[i:i+k]) + return "".join(a) diff --git a/Week 08/id_406/Create Leetcode_541_406.py b/Week 08/id_406/Create Leetcode_541_406.py new file mode 100644 index 000000000..224e5b0d5 --- /dev/null +++ b/Week 08/id_406/Create Leetcode_541_406.py @@ -0,0 +1,6 @@ +class Solution: + def reverseStr(self, s: str, k: int) -> str: + a = list(s) + for i in range(0, len(a), 2*k): + a[i:i+k] = reversed(a[i:i+k]) + return "".join(a) diff --git a/Week 08/id_406/Create Leetcode_818_406.py b/Week 08/id_406/Create Leetcode_818_406.py new file mode 100644 index 000000000..fb95c8d83 --- /dev/null +++ b/Week 08/id_406/Create Leetcode_818_406.py @@ -0,0 +1,21 @@ +class Solution: + def racecar(self, target: int) -> int: + K = target.bit_length() + 1 + barrier = 1 << K + pq = [(0, target)] + dist = [float('inf')] * (2 * barrier + 1) + dist[target] = 0 + + while pq: + steps, targ = heapq.heappop(pq) + if dist[targ] > steps: continue + + for k in range(K+1): + walk = (1 << k) - 1 + steps2, targ2 = steps + k + 1, walk - targ + if walk == targ: steps2 -= 1 + + if abs(targ2) <= barrier and steps2 < dist[targ2]: + heapq.heappush(pq, (steps2, targ2)) + dist[targ2] = steps2 + return dist[0] diff --git a/Week 08/id_406/NOTE.md b/Week 08/id_406/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_406/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_411/NOTE.md b/Week 08/id_411/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_411/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_416/NOTE.md b/Week 08/id_416/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_416/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_421/NOTE.md b/Week 08/id_421/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_421/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_426/NOTE.md b/Week 08/id_426/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_426/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_431/LeetCode_115_431.java b/Week 08/id_431/LeetCode_115_431.java new file mode 100644 index 000000000..26cb07c4c --- /dev/null +++ b/Week 08/id_431/LeetCode_115_431.java @@ -0,0 +1,21 @@ +package hard; + +/** + * @author 潘磊明 + * @date 2019/12/10 + */ +public class DistinctSubsequences { + public int numDistinct(String s, String t) { + char[] sarray = s.toCharArray(); + char[] tarray = t.toCharArray(); + int[][] dp = new int[tarray.length + 1][sarray.length + 1]; + for (int i = 0; i < sarray.length + 1; i++) dp[0][i] = 1; //空字符串是所有字符串的子序列 + for (int i = 1; i < tarray.length + 1; i++) { + for (int j = 1; j < sarray.length + 1; j++) { + if (tarray[i - 1] == sarray[j - 1]) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]; + else dp[i][j] = dp[i][j - 1]; + } + } + return dp[tarray.length][sarray.length]; + } +} diff --git a/Week 08/id_431/LeetCode_300_431.java b/Week 08/id_431/LeetCode_300_431.java new file mode 100644 index 000000000..8a48062f6 --- /dev/null +++ b/Week 08/id_431/LeetCode_300_431.java @@ -0,0 +1,60 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/12/9 + */ +public class LongestIncreasingSubsequence { + /** + * 时间复杂度:O(n^2) + * @param nums + * @return + */ +// public int lengthOfLIS(int[] nums) { +// if (nums.length == 0) return 0; +// int[] dp = new int[nums.length]; +// dp[0] = 1; +// int max = 1; +// for (int i = 1; i < nums.length; i++) { +// int maxval = 0; +// for (int j = 0; j < i; j++) { +// if (nums[i] > nums[j]) { +// maxval = Math.max(maxval, dp[j]); +// } +// } +// dp[i] = maxval + 1; +// max = Math.max(max, dp[i]); +// } +// return max; +// } + + /** + * 动态递归 + 二分查找 + * 时间复杂度:O(nlogn) + * @param nums + * @return + */ + public int lengthOfLIS(int[] nums) { + if (nums.length < 1) { return 0; } + int[] tails = new int[nums.length]; + tails[0] = nums[0]; //init + int end = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] > tails[end]) { + end++; + tails[end] = nums[i]; + } else { + int left = 0; + int right = end; + while (left < right) { + int mid = (left + right) / 2; + if (tails[mid] > nums[i]) right = mid; + else if (tails[mid] < nums[i]) left = mid + 1; + else {left = mid; break;} + } + tails[left] = nums[i]; + } + } + return end + 1; + } +} diff --git a/Week 08/id_431/LeetCode_32_431.java b/Week 08/id_431/LeetCode_32_431.java new file mode 100644 index 000000000..30c78f5b8 --- /dev/null +++ b/Week 08/id_431/LeetCode_32_431.java @@ -0,0 +1,107 @@ +package hard; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * @author 潘磊明 + * @date 2019/11/15 + */ +public class LongestValidParentheses { + +// public int longestValidParentheses(String s) { +// if (s.length() <= 1) return 0; +// /** +// * 状态方程,存储当前有效括号的最大距离 +// */ +// int[] dp = new int[s.length()]; +// char[] array = s.toCharArray(); +// int max = 0; +// dp[0] = 0; +// for (int i = 1; i < array.length; i++) { +// if (array[i] == ')') { +// if (array[i - 1] == '(') { +// dp[i] = i >= 2 ? dp[i] = dp[i - 2] + 2 : 2; +// }else { +// if (i - dp[i - 1] - 1 >= 0 +// && array[i - dp[i - 1] - 1] == '(') { +// //还需判断前面的有效括号能不能组合在一起,例如()(()) +// dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 > 0 ? dp[i - dp[i - 1] - 2] : 0); +// } +// } +// max = Math.max(max, dp[i]); +// } +// } +// return max; +// } + + /** + * 使用栈 + * @param s + * @return + */ +// public int longestValidParentheses(String s) { +// Deque deque = new LinkedList<>(); +// char[] arr = s.toCharArray(); +// for (int i = 0; i < arr.length; i++) { +// if (arr[i] == ')' && !deque.isEmpty() && arr[deque.getFirst()] == '(') { +// deque.removeFirst(); +// } else { +// deque.addFirst(i); +// } +// } +// if (deque.isEmpty()) return s.length(); +// int a = s.length() - 1, max = 0; +// while (!deque.isEmpty()) { +// int tmp = deque.removeFirst(); +// max = Math.max(a - tmp, max); +// a = tmp - 1; +// } +// max = Math.max(a, max); +// return max; +// } + +// public int longestValidParentheses(String s) { +// char[] array = s.toCharArray(); +// if (array.length < 2) return 0; +// int[] dp = new int[array.length]; +// int max = 0; +// dp[0] = 0; +// for (int i = 1; i < array.length; i++) { +// if (array[i] == ')') { +// if (array[i - 1] == '(') { +// dp[i] = i - 2 >= 0 ? dp[i - 2] + 2 : 2; +// } +// else { +// //判断前方是否有多余的( +// int ind = i - dp[i - 1] - 1; +// if (ind >= 0 && array[ind] == '(') { +// dp[i] = dp[i - 1] + 2 + (ind - 1 > 0 ? dp[ind - 1] : 0); +// } +// } +// } +// max = Math.max(max, dp[i]); +// } +// return max; +// } + + public int longestValidParentheses(String s) { + char[] array = s.toCharArray(); + if (array.length < 2) return 0; + Deque deque = new LinkedList<>(); + for (int i = 0; i < array.length; i++) { + if (!deque.isEmpty() && array[i] == ')' && array[deque.getLast()] == '(') deque.removeLast(); + else deque.addLast(i); + } + if (deque.isEmpty()) return array.length; + int max = 0; + int first = 0; + deque.addLast(array.length); + while (!deque.isEmpty()) { + int tmp = deque.removeFirst(); + max = Math.max(tmp - first - 1, max); + first = tmp; + } + return max; + } +} diff --git a/Week 08/id_431/LeetCode_387_431.java b/Week 08/id_431/LeetCode_387_431.java new file mode 100644 index 000000000..33bec7d61 --- /dev/null +++ b/Week 08/id_431/LeetCode_387_431.java @@ -0,0 +1,80 @@ +package easy; + +import javax.naming.Name; +import java.awt.dnd.DnDConstants; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; + +/** + * @author 潘磊明 + * @date 2019/12/11 + */ +public class FirstUniqueCharacterInAString { +// public int firstUniqChar(String s) { +// char[] array = s.toCharArray(); +// char c = '@'; +// Map map = new HashMap<>(); +// for (int i = 0; i < array.length; i++) { +// if (map.containsKey(array[i])) { +// array[map.get(array[i])] = c; +// array[i] = c; +// } else { +// map.put(array[i], i); +// } +// } +// for (int i = 0; i < array.length; i++) { +// if (array[i] != c) return i; +// } +// return -1; +// } + + DNode head = new DNode(); + DNode tail = new DNode(); + + public int firstUniqChar(String s) { + char[] array = s.toCharArray(); + head.next = tail; + tail.prev = head; + Map map = new HashMap<>(); + for (int i = 0; i < array.length; i++) { + if (map.containsKey(array[i])) { + DNode node = map.get(array[i]); + node.count += 1; + moveNodeToEnd(node); + } else { + DNode node = new DNode(); + node.i = i; + node.count = 1; + addNode(node); + map.put(array[i], node); + } + } + DNode d = head.next; + if (d.count == 1) return d.i; + else return -1; + } + + private void addNode(DNode node){ + DNode tmp = tail.prev; + tmp.next = node; + node.next = tail; + tail.prev = node; + node.prev = tmp; + } + + private void moveNodeToEnd(DNode node){ + if (node.prev == null) return; + node.prev.next = node.next; + node.next.prev = node.prev; + node.next = null; + node.prev = null; + } + + class DNode { + private int i; + private int count; + DNode prev; + DNode next; + } +} diff --git a/Week 08/id_431/LeetCode_58_431.java b/Week 08/id_431/LeetCode_58_431.java new file mode 100644 index 000000000..b6d945166 --- /dev/null +++ b/Week 08/id_431/LeetCode_58_431.java @@ -0,0 +1,28 @@ +package easy; + +import java.util.Deque; + +/** + * @author 潘磊明 + * @date 2019/12/11 + */ +public class LengthOfLastWord { +// public int lengthOfLastWord(String s) { +// int length = 0; +// int tmp = 0; +// char[] chars = s.toCharArray(); +// for (int i = 0; i < chars.length; i++) { +// if (chars[i] == ' ') { +// if (tmp != 0) length = tmp; +// tmp = 0; +// } +// else tmp += 1; +// } +// return tmp == 0 ? length : tmp; +// } + + public int lengthOfLastWord(String s) { + String[] tmp = s.trim().split(" "); + return tmp[tmp.length - 1].length(); + } +} diff --git a/Week 08/id_431/LeetCode_709_431.java b/Week 08/id_431/LeetCode_709_431.java new file mode 100644 index 000000000..62d3b785a --- /dev/null +++ b/Week 08/id_431/LeetCode_709_431.java @@ -0,0 +1,17 @@ +package easy; + +/** + * @author 潘磊明 + * @date 2019/12/11 + */ +public class ToLowerCase { + public String toLowerCase(String str) { + char[] chars = str.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] <= 'Z' && chars[i] >= 'A') { + chars[i] += 32; + } + } + return new String(chars); + } +} diff --git a/Week 08/id_431/LeetCode_771_431.java b/Week 08/id_431/LeetCode_771_431.java new file mode 100644 index 000000000..35b2a62ac --- /dev/null +++ b/Week 08/id_431/LeetCode_771_431.java @@ -0,0 +1,21 @@ +package easy; + +import java.util.HashSet; + +/** + * @author 潘磊明 + * @date 2019/12/11 + */ +public class JewelsAndStones { + public int numJewelsInStones(String J, String S) { + HashSet set = new HashSet<>(); + char[] jchars = J.toCharArray(); + for (char c : jchars) set.add(c); + int length = 0; + char[] chars = S.toCharArray(); + for (char c : chars) { + if (set.contains(c)) length++; + } + return length; + } +} diff --git a/Week 08/id_431/LeetCode_85_431.java b/Week 08/id_431/LeetCode_85_431.java new file mode 100644 index 000000000..f6cb05148 --- /dev/null +++ b/Week 08/id_431/LeetCode_85_431.java @@ -0,0 +1,48 @@ +package hard; + +import java.util.Arrays; + +/** + * @author 潘磊明 + * @date 2019/12/10 + */ +public class MaximalRectangle { + + public int maximalRectangle(char[][] matrix) { + int m = matrix.length; + if (m == 0) return 0; + int n = matrix[0].length; + int[] left = new int[n]; + int[] right = new int[n]; + int[] height = new int[n]; + + //init + Arrays.fill(right, n); + + int maxarea = 0; + for (int i = 0; i < m; i++) { + //update height + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') height[j]++; + else height[j] = 0; + } + //update left + int curleft = 0; + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') left[j] = Math.max(curleft, left[j]); + else {left[j] = 0; curleft = j + 1;} + } + //update right + int curright = n; + for (int j = n - 1; j >= 0; j--) { + if (matrix[i][j] == '1') right[j] = Math.min(curright, right[j]); + else {right[j] = n; curright = j;} + } + + for(int j = 0; j < n; j++) { + maxarea = Math.max(maxarea, (right[j] - left[j]) * height[j]); + } + } + return maxarea; + } +} diff --git a/Week 08/id_431/LeetCode_8_431.java b/Week 08/id_431/LeetCode_8_431.java new file mode 100644 index 000000000..18d1bcf2d --- /dev/null +++ b/Week 08/id_431/LeetCode_8_431.java @@ -0,0 +1,50 @@ +package medium; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.Map; + +/** + * @author 潘磊明 + * @date 2019/12/11 + */ +public class StringToIntegerAtoi { + public int myAtoi(String str) { + String s = str.trim(); + char[] chars = s.toCharArray(); + if (chars.length == 0) return 0; + Deque deque = new LinkedList<>(); + //判断首字母 + if (!isEffective(chars[0])) return 0; + deque.addLast(chars[0]); + for (int i = 1; i < chars.length; i++) { + if (chars[i] >= '0' && chars[i] <= '9') deque.addLast(chars[i]); + else { + break; + } + } + long num = 0L; + boolean flag = true; //是正还是负 + //初始化 + char first = deque.removeFirst(); + if (first == '-') flag = false; + else if (first >= '0' && first <= '9') num += (first - '0') * Math.pow(10, deque.size()); + while (!deque.isEmpty()) { + first = deque.removeFirst(); + if (flag) { + num += (first - '0') * Math.pow(10, deque.size()); + if (num > Integer.MAX_VALUE) return Integer.MAX_VALUE; + } + else { + num -= (first - '0') * Math.pow(10, deque.size()); + if (num < Integer.MIN_VALUE) return Integer.MIN_VALUE; + } + } + return (int)num; + } + + private boolean isEffective(char c) { + if (c == '+' || c == '-' || (c >= '0' && c <= '9')) return true; + return false; + } +} diff --git a/Week 08/id_431/LeetCode_91_431.java b/Week 08/id_431/LeetCode_91_431.java new file mode 100644 index 000000000..bb44950fb --- /dev/null +++ b/Week 08/id_431/LeetCode_91_431.java @@ -0,0 +1,71 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/11/18 + */ +public class DecodeWays { +// public int numDecodings(String s) { +// if (s.startsWith("0")) return 0; +// if (s.length() == 1) return 1; +// int[] array = new int[s.length()]; +// for(int i = 0; i < s.length(); i++) { +// array[i] = Integer.valueOf(s.substring(i, i + 1)); +// } +// int[] dp = new int[array.length]; +// dp[0] = 1; +// +// for (int i = 1; i < array.length; i++) { +// if (dp[i - 1] == 0) dp[i] = 0; +// else if (array[i] == 0) { +// if(array[i - 1] == 1 || array[i - 1] == 2) { +// if (i != 1) dp[i] = dp[i - 2]; +// else dp[i] = 1; +// } +// else dp[i] = 0; +// } +// else { +// int tmp = array[i - 1] * 10 + array[i]; +// if (tmp > 10 && tmp < 27) { +// if (i == 1) dp[i] = 2; +// else dp[i] = dp[i - 1] + dp[i - 2]; +// } +// else dp[i] = dp[i - 1]; +// } +// } +// return dp[array.length - 1]; +// } + + public int numDecodings(String s) { + char[] array = s.toCharArray(); + if (array.length < 1) return 0; + if (s.startsWith("0")) return 0; + int[] mem = new int[array.length + 1]; + //init + int val1 = array[0] - '0'; + mem[0] = val1 == 0 ? 0 : 1; + for (int i = 1; i < array.length; i++) { + traserval(array, i, mem); + } + return mem[array.length - 1]; + } + + private void traserval(char[] array, int i, int[] mem) { + int val = array[i] - '0'; + int tenVal = array[i - 1] - '0'; + if (val == 0) { + if (tenVal == 1 || tenVal == 2) + mem[i] = i - 2 > 0 ? mem[i - 2] : 1; + else mem[i] = 0; + } else if (tenVal == 0) { + mem[i] = mem[i - 1]; + } else { + int tmpVal = tenVal * 10 + val; + if (tmpVal > 0 && tmpVal < 27) { + mem[i] = mem[i - 1] + (i - 2 > 0 ? mem[i - 2] : 1); + } else { + mem[i] = mem[i - 1]; + } + } + } +} diff --git a/Week 08/id_431/NOTE.md b/Week 08/id_431/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_431/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_436/Leetcode_44_436.java b/Week 08/id_436/Leetcode_44_436.java new file mode 100644 index 000000000..1348c360b --- /dev/null +++ b/Week 08/id_436/Leetcode_44_436.java @@ -0,0 +1,51 @@ +class Solution { + public boolean isMatch(String s, String p) { + if (s == null || p == null) { + return false; + } + boolean[][] memo = new boolean[s.length()][p.length()]; + boolean[][] visited = new boolean[s.length()][p.length()]; + return isMatchHelper(s, 0, p, 0, memo, visited); + } + private boolean charMatch(char sChar, char pChar) { + return (sChar == pChar || pChar == '?'); + } + private boolean allStar(String p, int pIndex) { + for (int i = pIndex; i < p.length(); i++) { + if (p.charAt(i) != '*') { + return false; + } + } + return true; + } + private boolean isMatchHelper(String s, int sIndex, + String p, int pIndex, + boolean[][] memo, + boolean[][] visited) { + if (pIndex == p.length()) { + return sIndex == s.length(); + } + if (sIndex == s.length()) { + return allStar(p, pIndex); + } + if (visited[sIndex][pIndex]) { + return memo[sIndex][pIndex]; + } + + char sChar = s.charAt(sIndex); + char pChar = p.charAt(pIndex); + boolean match; + + if (pChar == '*') { + match = isMatchHelper(s, sIndex, p, pIndex + 1, memo, visited) || + isMatchHelper(s, sIndex + 1, p, pIndex, memo, visited); + } else { + match = charMatch(sChar, pChar) && + isMatchHelper(s, sIndex + 1, p, pIndex + 1, memo, visited); + } + + visited[sIndex][pIndex] = true; + memo[sIndex][pIndex] = match; + return match; + } +} diff --git a/Week 08/id_436/Leetcode_91_436.java b/Week 08/id_436/Leetcode_91_436.java new file mode 100644 index 000000000..4803ae0ba --- /dev/null +++ b/Week 08/id_436/Leetcode_91_436.java @@ -0,0 +1,24 @@ +class Solution { + public int numDecodings(String s) { + if (s.length() == 0) { + return 0; + } + char[] c = s.toCharArray(); + int[] f = new int[s.length() + 1]; + f[0] = 1; + for (int i = 1; i <= s.length(); ++i) { + if (c[i - 1] != '0') { + f[i] += f[i - 1]; + } + if (i >= 2) { + int val = (c[i - 2] - '0') * 10 + c[i - 1] - '0'; + if (10 <= val && val <= 26) { + f[i] += f[i - 2]; + } + } + } + return f[s.length()]; + } + //in: 0 2 2 6 + //ou: 1 1 2 4 +} diff --git a/Week 08/id_436/NOTE.md b/Week 08/id_436/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_436/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_441/NOTE.md b/Week 08/id_441/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_441/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_446/NOTE.md b/Week 08/id_446/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_446/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_451/LeetCode_300_451.go b/Week 08/id_451/LeetCode_300_451.go new file mode 100644 index 000000000..a0ffac223 --- /dev/null +++ b/Week 08/id_451/LeetCode_300_451.go @@ -0,0 +1,52 @@ +type state struct { + s [][]int +} + +func (s *state) Add(n int) { + ok := true + for i, l := range s.s { + if n >= l[0] { + ok = false + } + if n > l[len(l)-1] { + s.s[i] = append(l, n) + } else { + if len(l)-2 < 0 || len(l)-2 >= 0 && n > l[len(l)-2] { + l[len(l)-1] = n + } + s.s[i] = l + } + } + if ok { + // fmt.Printf("%v ?? %v \n", n, s.s) + s.s = append(s.s, []int{n}) + } +} +func (s *state) Res() int { + max := 0 + for _, l := range s.s { + if len(l) > max { + max = len(l) + } + } + return max +} +func lengthOfLIS(nums []int) int { + if len(nums) <= 1 { + return len(nums) + } + s := &state{} + + for i, n := range nums { + if i == 0 { + s = &state{s: [][]int{{n}}} + continue + } + s.Add(n) + + } + ans := s.Res() + // fmt.Printf("%v\n", s) + return ans +} + diff --git a/Week 08/id_451/LeetCode_387_451.go b/Week 08/id_451/LeetCode_387_451.go new file mode 100644 index 000000000..6a7e85a9a --- /dev/null +++ b/Week 08/id_451/LeetCode_387_451.go @@ -0,0 +1,16 @@ +func firstUniqChar(s string) int { + m := make(map[int32]int) + for _, a := range s { + if c, ok := m[a]; ok { + m[a] = c + 1 + } else { + m[a] = 1 + } + } + for i, a := range s { + if m[a] == 1 { + return i + } + } + return -1 +} diff --git a/Week 08/id_451/NOTE.md b/Week 08/id_451/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_451/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_456/NOTE.md b/Week 08/id_456/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_456/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_461/NOTE.md b/Week 08/id_461/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_461/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_466/LeetCode_205_466.java b/Week 08/id_466/LeetCode_205_466.java new file mode 100644 index 000000000..cc9f12b9b --- /dev/null +++ b/Week 08/id_466/LeetCode_205_466.java @@ -0,0 +1,87 @@ +//给定两个字符串 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 哈希表 +package com.aseara.leetcode.editor.cn.a205; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * desc: 205.同构字符串
    + * Date: 2019/12/8
    + * + * @author qiujingde + */ +class IsomorphicStrings { + private Solution solution = new Solution(); + + @Test + void test1() { + assertTrue(solution.isIsomorphic("egg", "add")); + assertFalse(solution.isIsomorphic("foo", "bar")); + assertTrue(solution.isIsomorphic("paper", "title")); + assertFalse(solution.isIsomorphic("aa", "ab")); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean isIsomorphic(String s, String t) { + if (s == null && t == null) { + return true; + } + if (s == null || t == null) { + return false; + } + if (s.length() != t.length()) { + return false; + } + if (s.length() == 1) { + return true; + } + char[] ss = s.toCharArray(); + char[] ts = t.toCharArray(); + Map sMap = new HashMap<>(); + Map tMap = new HashMap<>(); + + for (int i = 0; i < ss.length; i++) { + char sc = ss[i]; + char tc = ts[i]; + if (sMap.computeIfAbsent(sc, c -> tc) != tc || + tMap.computeIfAbsent(tc, c -> sc) != sc) { + return false; + } + } + return true; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 08/id_466/LeetCode_680_466.java b/Week 08/id_466/LeetCode_680_466.java new file mode 100644 index 000000000..cd23631ce --- /dev/null +++ b/Week 08/id_466/LeetCode_680_466.java @@ -0,0 +1,74 @@ +//给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。 +// +// 示例 1: +// +// +//输入: "aba" +//输出: True +// +// +// 示例 2: +// +// +//输入: "abca" +//输出: True +//解释: 你可以删除c字符。 +// +// +// 注意: +// +// +// 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。 +// +// Related Topics 字符串 +package com.aseara.leetcode.editor.cn.a680; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * desc: 680.验证回文字符串 Ⅱ
    + * Date: 2019/12/8
    + * + * @author qiujingde + */ +class ValidPalindromeIi { + private Solution solution = new Solution(); + + @Test + void test1() { + assertTrue(solution.validPalindrome("aba")); + assertTrue(solution.validPalindrome("abca")); + assertFalse(solution.validPalindrome("abcd")); + assertTrue(solution.validPalindrome("aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga")); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean validPalindrome(String s) { + if (s == null || s.length() == 0 || s.length() == 1) { + return true; + } + return valid(s.toCharArray(), 0, s.length() - 1, false); + } + + private boolean valid(char[] chars, int i, int j, boolean remove) { + if (i >= j) { + return true; + } + if (chars[i] == chars[j]) { + return valid(chars, i + 1, j - 1, remove); + } + if (remove) { + return false; + } + return valid(chars, i + 1, j, true) || valid(chars, i, j - 1, true); + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 08/id_466/NOTE.md b/Week 08/id_466/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_466/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_471/LeetCode_198_471.java b/Week 08/id_471/LeetCode_198_471.java new file mode 100644 index 000000000..850c84189 --- /dev/null +++ b/Week 08/id_471/LeetCode_198_471.java @@ -0,0 +1,15 @@ +class Solution { + public int rob(int[] nums) { + int preTwo = 0; + int pre = 0; + int max = pre; + + for (int i = 0; i < nums.length; i++) { + max = Math.max(preTwo + nums[i], pre); + preTwo = pre; + pre = max; + } + + return max; + } +} \ No newline at end of file diff --git a/Week 08/id_471/LeetCode_300_471.java b/Week 08/id_471/LeetCode_300_471.java new file mode 100644 index 000000000..e06de3212 --- /dev/null +++ b/Week 08/id_471/LeetCode_300_471.java @@ -0,0 +1,26 @@ +class Solution { + public int lengthOfLIS(int[] nums) { + int tail[] = new int[nums.length]; + int size = 0; + + for (int num : nums) { + + int i = 0, j = size; + while (i < j) { + int mid = i + ((j - i) >> 1); + + if (tail[mid] < num) { + i = mid + 1; + } else { + j = mid; + } + } + tail[i] = num; + if (i == size) { + size++; + } + } + + return size; + } +} \ No newline at end of file diff --git a/Week 08/id_471/LeetCode_62_471.java b/Week 08/id_471/LeetCode_62_471.java new file mode 100644 index 000000000..07a6caf5b --- /dev/null +++ b/Week 08/id_471/LeetCode_62_471.java @@ -0,0 +1,14 @@ +class Solution { + public int uniquePaths(int m, int n) { + int dp[] = new int[n]; + Arrays.fill(dp, 1); + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[j] += dp[j-1]; + } + } + + return dp[n-1]; + } +} \ No newline at end of file diff --git a/Week 08/id_471/LeetCode_64_471.java b/Week 08/id_471/LeetCode_64_471.java new file mode 100644 index 000000000..127e14f62 --- /dev/null +++ b/Week 08/id_471/LeetCode_64_471.java @@ -0,0 +1,19 @@ +class Solution { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + int dp[] = new int[n]; + + for (int i = 0; i < grid[0].length; i++) { + dp[i] = i == 0 ? grid[0][i] : dp[i - 1] + grid[0][i]; + } + + for (int i = 1; i < m; i++) { + dp[0] = dp[0] + grid[i][0]; + for (int j = 1; j < n; j++) { + dp[j] = Math.min(dp[j-1], dp[j]) + grid[i][j]; + } + } + return dp[n - 1]; + } +} \ No newline at end of file diff --git a/Week 08/id_471/LeetCode_91_471.java b/Week 08/id_471/LeetCode_91_471.java new file mode 100644 index 000000000..9384d235b --- /dev/null +++ b/Week 08/id_471/LeetCode_91_471.java @@ -0,0 +1,26 @@ +class Solution { + public int numDecodings(String s) { + if (s.length() == 0) { + return 0; + } + + int dp[] = new int[s.length() + 1]; + dp[0] = 1; + dp[1] = s.charAt(0) == '0' ? 0 : 1; + + for (int i = 2; i <= s.length(); i++) { + int first = Integer.valueOf(s.substring(i - 1, i)); + int second = Integer.valueOf(s.substring(i - 2, i)); + + if (first >= 1 && first <= 9) { + dp[i] += dp[i - 1]; + } + + if (second >= 10 && second <= 26) { + dp[i] += dp[i - 2]; + } + } + + return dp[s.length()]; + } +} \ No newline at end of file diff --git a/Week 08/id_471/NOTE.md b/Week 08/id_471/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_471/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_476/LeetCode_198_476.java b/Week 08/id_476/LeetCode_198_476.java new file mode 100644 index 000000000..52bbfdd39 --- /dev/null +++ b/Week 08/id_476/LeetCode_198_476.java @@ -0,0 +1,31 @@ +public class LeetCode_198_HouseRobber { + public static void main(String[] args) { + Solution solution = new LeetCode_198_HouseRobber().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int rob(int[] nums) { + + if (nums == null || nums.length == 0) return 0; + // 分解子问题 + // 第 i 个房子能偷到的最大金额 + // 1、偷这个房子,则不能偷第 i-1 个房子,最大金额为:第 i-2 个房子的最大金额 + 当前房子的金额 + // 2、不偷这个房子,则必偷第 i-1 个房子(因为都是正数),最大金额为:第 i-1 个房子的最大金额(包含了偷和不偷的情况) + // 定义状态数组 + // dp[i] 代表第 i 个房子能偷到的最大金额 + // DP方程 + // dp(i) = max(dp(i - 2) + nums[i], dp(i - 1)) + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + for (int i = 2; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); + } + return dp[nums.length - 1]; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 08/id_476/LeetCode_300_476.java b/Week 08/id_476/LeetCode_300_476.java new file mode 100644 index 000000000..189f54f9d --- /dev/null +++ b/Week 08/id_476/LeetCode_300_476.java @@ -0,0 +1,64 @@ +public class LeetCode_300_LongestIncreasingSubsequence { + public static void main(String[] args) { + Solution solution = new LeetCode_300_LongestIncreasingSubsequence().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + + class Solution { + public int lengthOfLIS(int[] nums) { + + if (nums == null || nums.length == 0) return 0; + + // 蜘蛛纸牌 + // 牌堆数 + int cols = 0; + // dp[i] 存放的是每个牌堆最后一张牌的数字 + int[] dp = new int[nums.length]; + for (int num : nums) { + // 判断当前牌应该放在哪个牌堆 + int left = 0; int right = cols; + while (left < right) { + // 左中位数 + int mid = left + (right - left) / 2; + if (dp[mid] < num) { + left = mid + 1; + } else { + right = mid; + } + } + // 未找到合适的牌堆,则新增一堆 + if (left == cols) cols++; + // 将该牌放到找到的牌堆;如果没找到,由于初始时,最后一堆是空的,因此也只需放到最后一堆(left)即可 + dp[left] = num; + + } + return cols; + } + } + class Solution1 { + public int lengthOfLIS(int[] nums) { + + if (nums == null || nums.length == 0) return 0; + + int max = 0; + // dp[i] 代表位置 i 处的最长升序子串长度 + int[] dp = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + dp[i] = 1; + } + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] > nums[i]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + max = Math.max(max, dp[i]); + } + return max; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 08/id_476/LeetCode_387_476.java b/Week 08/id_476/LeetCode_387_476.java new file mode 100644 index 000000000..9e439e822 --- /dev/null +++ b/Week 08/id_476/LeetCode_387_476.java @@ -0,0 +1,42 @@ +public class LeetCode_387_FirstUniqueCharacterInAString { + public static void main(String[] args) { + Solution solution = new LeetCode_387_FirstUniqueCharacterInAString().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int firstUniqChar(String s) { + + int res = Integer.MAX_VALUE; + for (char ch = 'a'; ch <= 'z'; ch++) { + int index = s.indexOf(ch); + if (index != -1 && index == s.lastIndexOf(ch)) { + res = Math.min(res, index); + } + } + return res == Integer.MAX_VALUE ? -1 : res; + } + } + class Solution1 { + public int firstUniqChar(String s) { + + if (s == null || s.length() == 0) return -1; + + Map counter = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + counter.put(ch, counter.getOrDefault(ch, 0) + 1); + } + + for (int i = 0; i < s.length(); i++) { + if (counter.get(s.charAt(i)) == 1) { + return i; + } + } + return -1; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 08/id_476/LeetCode_680_476.java b/Week 08/id_476/LeetCode_680_476.java new file mode 100644 index 000000000..81a3032df --- /dev/null +++ b/Week 08/id_476/LeetCode_680_476.java @@ -0,0 +1,63 @@ +public class LeetCode_680_ValidPalindromeIi { + public static void main(String[] args) { + Solution solution = new LeetCode_680_ValidPalindromeIi().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + + class Solution { + public boolean validPalindrome(String s) { + + int i = 0; + int j = s.length() - 1; + while (i < j && s.charAt(i) == s.charAt(j)) { + i++; + j--; + } + if (isValid(s, i, j - 1)) return true; + if (isValid(s, i + 1, j)) return true; + return false; + } + private boolean isValid(String s, int begin, int end) { + while (begin < end) { + if (s.charAt(begin) != s.charAt(end)) { + return false; + } + begin++; + end--; + } + return true; + } + } + class Solution1 { + public boolean validPalindrome(String s) { + + int count = 2; + int begin = 0, end = 0; + for (int i = 0, j = s.length() - 1; i < j; ) { + if (s.charAt(i) == s.charAt(j)) { + i++; + j--; + } else { + if (count == 2) { + begin = i; + end = j; + i++; + count--; + } else if (count == 1) { + i = begin; + j = end; + j--; + count--; + } else { + return false; + } + } + } + return true; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 08/id_476/LeetCode_8_476.java b/Week 08/id_476/LeetCode_8_476.java new file mode 100644 index 000000000..2a1d0e4ba --- /dev/null +++ b/Week 08/id_476/LeetCode_8_476.java @@ -0,0 +1,54 @@ +public class LeetCode_8_StringToIntegerAtoi { + public static void main(String[] args) { + Solution solution = new LeetCode_8_StringToIntegerAtoi().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int myAtoi(String str) { + + if (str == null || str.length() == 0) return 0; + + int i = 0; + while (i < str.length() && str.charAt(i) == ' ') { + i++; + } + if (i == str.length()) return 0; + + boolean negative = false; + if (str.charAt(i) == '-') { + negative = true; + i++; + } else if (str.charAt(i) == '+') { + i++; + } + + int res = 0; + for (int j = i; j < str.length(); j++) { + char ch = str.charAt(j); + if (ch < '0' || ch > '9') { + break; + } + if (!negative && res > Integer.MAX_VALUE / 10) { + res = Integer.MAX_VALUE; + break; + } else if (!negative && res == Integer.MAX_VALUE / 10 && (ch - '0') > Integer.MAX_VALUE % 10) { + res = Integer.MAX_VALUE; + break; + } else if (negative && (0 - res) < Integer.MIN_VALUE / 10) { + res = Integer.MIN_VALUE; + break; + } else if (negative && (0 - res) == Integer.MIN_VALUE / 10 && ('0' - ch) < Integer.MIN_VALUE % 10) { + res = Integer.MIN_VALUE; + break; + } + res = res * 10 + ch - '0'; + } + + return negative ? -res : res; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 08/id_476/NOTE.md b/Week 08/id_476/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_476/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_481/NOTE.md b/Week 08/id_481/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_481/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_486/NOTE.md b/Week 08/id_486/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_486/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_491/LeetCode_300_491.java b/Week 08/id_491/LeetCode_300_491.java new file mode 100644 index 000000000..efa599b60 --- /dev/null +++ b/Week 08/id_491/LeetCode_300_491.java @@ -0,0 +1,23 @@ +class Solution { + public int lengthOfLIS(int[] nums) { + int max = 0; + int[] memo = new int[nums.length]; + for(int i = 0; i < nums.length; i++) { + int tempMax = 0; + if(i == 0) { + tempMax = 1; + } else { + for(int j = i - 1; j >= 0; j--) { + if(nums[j] < nums[i]) { + tempMax = Math.max(tempMax, memo[j] + 1); + } + } + } + tempMax = Math.max(tempMax, 1); + memo[i] = tempMax; + max = Math.max(tempMax, max); + } + + return max; + } +} diff --git a/Week 08/id_491/LeetCode_8_491.java b/Week 08/id_491/LeetCode_8_491.java new file mode 100644 index 000000000..bb09e30b5 --- /dev/null +++ b/Week 08/id_491/LeetCode_8_491.java @@ -0,0 +1,46 @@ +class Solution { + public int myAtoi(String str) { + boolean isMinus = false; + String result = ""; + if(str == null){ + return 0; + } else { + str = str.trim(); + if(str.length() == 0){ + return 0; + } else if((str.startsWith("-") || str.startsWith("+"))) { + if((str.length() == 1 || str.charAt(1) < 48 || str.charAt(1) > 57)){ + return 0; + } else { + isMinus = str.startsWith("-"); + str = str.substring(1, str.length()); + } + } else if(str.charAt(0) < 48 || str.charAt(0) > 57){ + return 0; + } + + for(int i = 0; i < str.length(); i++) { + if(str.charAt(i) >= 48 && str.charAt(i) <= 57){ + result += String.valueOf(str.charAt(i)); + } else { + break; + } + } + try{ + if(isMinus){ + return 0 - Integer.valueOf(result); + } else { + return 0 + Integer.valueOf(result); + } + + } catch(Exception ex){ + if(isMinus){ + return Integer.MIN_VALUE; + } else { + return Integer.MAX_VALUE; + } + } + } + + } +} diff --git a/Week 08/id_491/NOTE.md b/Week 08/id_491/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_491/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_496/NOTE.md b/Week 08/id_496/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_496/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_501/NOTE.md b/Week 08/id_501/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_501/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_501/week08/LeetCode_151_501.java b/Week 08/id_501/week08/LeetCode_151_501.java new file mode 100644 index 000000000..3a2c1a301 --- /dev/null +++ b/Week 08/id_501/week08/LeetCode_151_501.java @@ -0,0 +1,26 @@ +package homework.week08; + +/** + * 151. 翻转字符串里的单词 + * https://leetcode-cn.com/problems/reverse-words-in-a-string/ + * @author: sintang + * @date: 2019-12-08 + */ +public class LeetCode_151_501 { + public static String reverseWords(String s) { + String[] arr = s.split(" "); + StringBuilder sb = new StringBuilder(); + for (int i = arr.length - 1; i >= 0;i --) { + if("".equals(arr[i])){ + continue; + } + sb.append(arr[i]).append(" "); + } + return sb.toString().trim(); + } + + public static void main(String[] args) { + String s = "a good example"; + System.out.println(reverseWords(s)); + } +} diff --git a/Week 08/id_501/week08/LeetCode_300_501.java b/Week 08/id_501/week08/LeetCode_300_501.java new file mode 100644 index 000000000..0eeb8d0c9 --- /dev/null +++ b/Week 08/id_501/week08/LeetCode_300_501.java @@ -0,0 +1,29 @@ +package homework.week08; + +/** + * 300. 最长上升子序列 + * https://leetcode-cn.com/problems/longest-increasing-subsequence + * @author: sintang + * @date: 2019-12-08 + */ +public class LeetCode_300_501 { + public int lengthOfLIS(int[] nums) { + if(nums.length == 0){ + return 0; + } + int[] dp = new int[nums.length]; + dp[0] = 1; + int maxResult = 1; + for (int i = 0; i < dp.length; i++) { + int maxVal = 0; + for(int j = 0;j nums[j]){ + maxVal = Math.max(maxVal,dp[j]); + } + } + dp[i] = maxVal + 1; + maxResult = Math.max(maxResult,dp[i]); + } + return maxResult; + } +} diff --git a/Week 08/id_501/week08/LeetCode_387_501.java b/Week 08/id_501/week08/LeetCode_387_501.java new file mode 100644 index 000000000..bb96cf980 --- /dev/null +++ b/Week 08/id_501/week08/LeetCode_387_501.java @@ -0,0 +1,67 @@ +package homework.week08; + +import java.util.HashMap; +import java.util.Map; + +/** + * 387. 字符串中的第一个唯一字符 + * https://leetcode-cn.com/problems/first-unique-character-in-a-string/ + * @author: sintang + * @date: 2019-12-08 + */ +public class LeetCode_387_501 { + /** + * 暴力 + * @param s + * @return + */ + public int firstUniqChar(String s) { + Map map = new HashMap<>(); + Character c; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + map.put(c,map.getOrDefault(c,0) + 1); + } + + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + if(map.get(c) == 1){ + return i; + } + } + return -1; + } + + /** + * 记录每个字符出现了几次,然后获取 + * @param s + * @return + */ + public int firstUniqChar2(String s) { + int[] letter = new int[26]; + for (char c : s.toCharArray()) { + letter[c - 'a'] ++; + } + for (int i = 0; i < s.length(); i++) { + if(letter[s.charAt(i) - 'a'] == 1){ + return i; + } + } + return -1; + } + + /** + * 使用api 获取到最后一次出现此字符和第一次出现此字符是否相等 + * @param s + * @return + */ + public int firstUniqChar3(String s) { + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if(s.indexOf(ch) == s.lastIndexOf(ch)){ + return i; + } + } + return -1; + } +} diff --git a/Week 08/id_501/week08/LeetCode_557_501.java b/Week 08/id_501/week08/LeetCode_557_501.java new file mode 100644 index 000000000..7851f09f2 --- /dev/null +++ b/Week 08/id_501/week08/LeetCode_557_501.java @@ -0,0 +1,33 @@ +package homework.week08; + +/** + * 557. 反转字符串中的单词 III + * https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ + * @author: sintang + * @date: 2019-12-08 + */ +public class LeetCode_557_501 { + public static String reverseWords(String s) { + char[] chars = new char[s.length()]; + int j = 0; + String[] arr = s.split(" "); + for(String str : arr){ + for (int i = str.length() - 1; i >= 0 ; i--) { + chars[j] = str.charAt(i); + j ++; + } + if(j < s.length()){ + chars[j] = ' '; + j++; + } + + } + + return new String(chars); + } + + public static void main(String[] args) { + String s = "Let's take LeetCode contest"; + System.out.println(reverseWords(s)); + } +} diff --git a/Week 08/id_501/week08/LeetCode_91_501.java b/Week 08/id_501/week08/LeetCode_91_501.java new file mode 100644 index 000000000..7f447ef7e --- /dev/null +++ b/Week 08/id_501/week08/LeetCode_91_501.java @@ -0,0 +1,61 @@ +package homework.week08; + +/** + * 91. 解码方法 + * https://leetcode-cn.com/problems/decode-ways/ + * @author: sintang + * @date: 2019-12-08 + */ +public class LeetCode_91_501 { + + public int numDecodings(String s) { + if(s == null || s.length() == 0){ + return 0; + } + return digui(s,0); + } + + public int numDecodings2(String s) { + int length = s.length(); + int[] dp = new int[length + 1]; + dp[length] = 1; + if(s.charAt(length - 1) != '0'){ + dp[length - 1] = 1; + } + for(int i = length - 2;i>=0;i--){ + if(s.charAt(i) == '0'){ + continue; + } + int ans1 = dp[i + 1]; + int ans2 = 0; + int ten = (s.charAt(i) - '0' )* 10; + int one = s.charAt(i + 1) - '0'; + if(ten + one <= 26){ + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + } + return dp[0]; + } + + + public int digui(String str,int start){ + if(str.length() == start){ + return 1; + } + // 不能已0开始 + if(str.charAt(start) == '0'){ + return 0; + } + int ans1 = digui(str,start + 1); + int ans2 = 0; + if(start < str.length() - 1){ + int ten = (str.charAt(start) - '0') * 10; + int one = str.charAt(start + 1) - '0'; + if(ten + one <= 26){ + ans2 = digui(str,start + 2); + } + } + return ans1 + ans2; + } +} diff --git a/Week 08/id_506/LeetCode_387_506.java b/Week 08/id_506/LeetCode_387_506.java new file mode 100644 index 000000000..dac4492ab --- /dev/null +++ b/Week 08/id_506/LeetCode_387_506.java @@ -0,0 +1,16 @@ +class Solution { + public int firstUniqChar(String s) { + int[] letter=new int[26]; + for (char c:s.toCharArray()){ + letter[c-'a']++; + } + for (int i = 0; i words = new ArrayList < > (); + StringBuilder word = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == ' ') { + words.add(word.toString()); + word = new StringBuilder(); + } else + word.append( s.charAt(i)); + } + words.add(word.toString()); + return words.toArray(new String[words.size()]); + } + + public String reverse(String s) { + StringBuilder res=new StringBuilder(); + for (int i = 0; i < s.length(); i++){ + res.insert(0,s.charAt(i)); + } + return res.toString(); + } +} diff --git a/Week 08/id_506/NOTE.md b/Week 08/id_506/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_506/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_511/NOTE.md b/Week 08/id_511/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_511/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_516/Leetcode_5_516.java b/Week 08/id_516/Leetcode_5_516.java new file mode 100644 index 000000000..ea5c3aed3 --- /dev/null +++ b/Week 08/id_516/Leetcode_5_516.java @@ -0,0 +1,16 @@ +class Solution { + public String longestPalindrome(String s) { + int n = s.length(); + String res = ""; + boolean [][] dp = new boolean[n][n]; + for (int i = n -1;i >= 0; i--) { + for (int j = i; j < n; j++) { + dp[i][j] = s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i + 1][j - 1]); + if (dp[i][j] && j - i + 1 > res.length()) { + res = s.substring(i, j + 1); + } + } + } + return res; + } +} diff --git a/Week 08/id_516/Leetcode_818_516.java b/Week 08/id_516/Leetcode_818_516.java new file mode 100644 index 000000000..4f2cf0e9d --- /dev/null +++ b/Week 08/id_516/Leetcode_818_516.java @@ -0,0 +1,14 @@ +class Solution { + int[] dp = new int[10001]; + public int racecar(int target) { + if (dp[target] > 0) return dp[target]; + int n = (int) (Math.log(target) / Math.log(2)) + 1; + if (1 << n == target + 1) dp[target] = n; + else { + dp[target] = racecar((1 << n) - 1 - target) + n + 1; + for (int m = 0; m < n - 1; ++m) + dp[target] = Math.min(dp[target],racecar(target - (1 << (n - 1)) + (1 << m)) + n + m + 1); + } + return dp[target]; + } +} diff --git a/Week 08/id_516/NOTE.md b/Week 08/id_516/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_516/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_521/NOTE.md b/Week 08/id_521/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_521/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_526/NOTE.md b/Week 08/id_526/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_526/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_531/NOTE.md b/Week 08/id_531/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_531/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_536/NOTE.md b/Week 08/id_536/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_536/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_536/leetcode_387_536.cpp b/Week 08/id_536/leetcode_387_536.cpp new file mode 100644 index 000000000..3d05029d7 --- /dev/null +++ b/Week 08/id_536/leetcode_387_536.cpp @@ -0,0 +1,28 @@ +#include +#include + +using namespace std; +//ʱ临ӶȣO(n)nΪַij +//ռ临ӶȣO(n) +class Solution { +public: + int firstUniqChar(string s) { + //unordered_map mapS; + map mapS; + for(auto c : s) + ++ mapS[c]; + for(int i = 0; i < s.size(); ++i) { + if(mapS[s[i]] == 1) + return i; + } + return -1; + } +}; + +int main() +{ + Solution s; + int res = s.firstUniqChar("lol"); + cout << res << endl; + return 0; +} diff --git a/Week 08/id_536/leetcode_58_536.cpp b/Week 08/id_536/leetcode_58_536.cpp new file mode 100644 index 000000000..da4e0e243 --- /dev/null +++ b/Week 08/id_536/leetcode_58_536.cpp @@ -0,0 +1,28 @@ +#include +#include + +using namespace std; + +class Solution { +public: + int lengthOfLastWord(string s) { + int res = 0; + for(int i = s.length()-1; i >= 0; --i) { + if(s[i] != ' ') + ++ res; + else { + if(res) + break; + } + } + return res; + } +}; + +int main() +{ + Solution s; + int res = s.lengthOfLastWord("djfks djsjd dd 23234"); + cout << res << endl; + return 0; +} diff --git a/Week 08/id_536/leetcode_771_536.cpp b/Week 08/id_536/leetcode_771_536.cpp new file mode 100644 index 000000000..5a627da0d --- /dev/null +++ b/Week 08/id_536/leetcode_771_536.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +using namespace std; + +class Solution { +public: + /***** + ⷨ1 + ʱ临ӶȣO(J*S) + ռ临ӶȣO(1) + *****/ + int helper1(string J, string S) { + int res = 0; + for(int i = 0; i < S.length(); ++ i) { + for(int j = 0; j < J.length(); ++ j) { + if(S[i] == J[j]) { + ++ res; + } + } + } + return res; + } + + /***** + ⷨ2setʵ + ʱ临ӶȣO(J+S) + ռ临ӶȣO(J) + *****/ + int helper2(string J, string S) { + int res = 0; + //unordered_set setJ(J.begin(),J.end()); + set setJ(J.begin(),J.end()); + for(int i = 0; i < S.length(); ++i) { + if(setJ.count(S[i])) + ++ res; + } + return res; + } + + /***** + ⷨ3mapʵ + ʱ临ӶȣO(J+S) + ռ临ӶȣO(J) + *****/ + int helper3(string J, string S) { + int res = 0; + //unordered_map mapJ; + map mapJ; + for(auto c : J) + mapJ[c] = 1; + for(auto c : S) + res += mapJ[c]; + return res; + } + + int numJewelsInStones(string J, string S) { + int res = 0; + //res = helper1(J,S); + //res = helper2(J,S); + res = helper3(J,S); + return res; + } +}; + +int main() +{ + Solution s; + int res = s.numJewelsInStones("aA","aAAbbbb"); + cout << res << endl; + return 0; +} diff --git a/Week 08/id_541/NOTE.md b/Week 08/id_541/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_541/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_546/NOTE.md b/Week 08/id_546/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_546/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_551/LeetCode_151_551.py b/Week 08/id_551/LeetCode_151_551.py new file mode 100644 index 000000000..b6ef650bd --- /dev/null +++ b/Week 08/id_551/LeetCode_151_551.py @@ -0,0 +1,3 @@ +class Solution: + def reverseWords(self, s: str) -> str: + return " ".join(s.split()[::-1]) diff --git a/Week 08/id_551/LeetCode_541_551.py b/Week 08/id_551/LeetCode_541_551.py new file mode 100644 index 000000000..e85abf036 --- /dev/null +++ b/Week 08/id_551/LeetCode_541_551.py @@ -0,0 +1,15 @@ +class Solution: +def reverseStr(self, s: str, k: int) -> str: + lists=[] + a=0 + while a0;$i--){ + if($s[$i]===' '){ + $s2 .= substr($s,$i+1,$j-$i-1)." "; + while($s[$i-1]===' ') $i--; + $j = $i; + } + } + $s2 .= substr($s,0,$j); + return $s2; + } +} +?> \ No newline at end of file diff --git a/Week 08/id_566/leetcode_541_566.php b/Week 08/id_566/leetcode_541_566.php new file mode 100644 index 000000000..7b5bb83b4 --- /dev/null +++ b/Week 08/id_566/leetcode_541_566.php @@ -0,0 +1,36 @@ + $value) { + $len = strlen($value); + if ($len < $k) { + $single = strrev($value); + } else { + $singArr = str_split($value, $k); + $single = strrev($singArr[0]) . $singArr[1]; + } + $total .= $single; + } + return $total; + } + +} +?> \ No newline at end of file diff --git a/Week 08/id_571/NOTE.md b/Week 08/id_571/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_571/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_576/NOTE.md b/Week 08/id_576/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_576/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_581/NOTE.md b/Week 08/id_581/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_581/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_586/NOTE.md b/Week 08/id_586/NOTE.md new file mode 100755 index 000000000..8767ddf71 --- /dev/null +++ b/Week 08/id_586/NOTE.md @@ -0,0 +1,201 @@ +# 学习总结 + +## 高级DP + +复杂度来源: +状态拥有更多的维度(二维、三维、或者更多、甚至需要压缩) +状态方程更加复杂 + +## 字符串算法 + +- 暴力法 +- Rabin-karp 算法 +- KMP算法 + +参考链接 + + 不可变字符串 https://lemire.me/blog/2017/07/07/are-your-strings-immutable/ + Atoi 代码示例 https://shimo.im/docs/KkDKkpWxjjrJXdpY/read + +```java +public int myAtoi(String str) { + int index = 0, sign = 1, total = 0; + //1. Empty string + if(str.length() == 0) return 0; + + //2. Remove Spaces + while(str.charAt(index) == ' ' && index < str.length()) + index ++; + + //3. Handle signs + if(str.charAt(index) == '+' || str.charAt(index) == '-'){ + sign = str.charAt(index) == '+' ? 1 : -1; + index ++; + } + + //4. Convert number and avoid overflow + while(index < str.length()){ + int digit = str.charAt(index) - '0'; + if(digit < 0 || digit > 9) break; + + //check if total will be overflow after 10 times and add digit + if(Integer.MAX_VALUE/10 < total || + Integer.MAX_VALUE/10 == total && Integer.MAX_VALUE %10 < digit) + return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE; + + total = 10 * total + digit; + index ++; + } + return total * sign; +} +``` + +```python +class Solution(object): + + def myAtoi(self, s): + + if len(s) == 0 : return 0 + ls = list(s.strip()) + + sign = -1 if ls[0] == '-' else 1 + + if ls[0] in ['-','+'] : del ls[0] + + ret, i = 0, 0 + + while i < len(ls) and ls[i].isdigit() : + ret = ret*10 + ord(ls[i]) - ord('0') + i += 1 + + return max(-2**31, min(sign * ret,2**31-1)) +``` + +字符串基础问题 + + https://leetcode-cn.com/problems/to-lower-case/ + https://leetcode-cn.com/problems/length-of-last-word/ + https://leetcode-cn.com/problems/jewels-and-stones/ + https://leetcode-cn.com/problems/first-unique-character-in-a-string/ + https://leetcode-cn.com/problems/string-to-integer-atoi/ + +字符串操作问题 + + https://leetcode-cn.com/problems/longest-common-prefix/description/ + https://leetcode-cn.com/problems/reverse-string + https://leetcode-cn.com/problems/reverse-string-ii/ + https://leetcode-cn.com/problems/reverse-words-in-a-string/ + https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ + https://leetcode-cn.com/problems/reverse-only-letters/ + +异位词问题 + + https://leetcode-cn.com/problems/valid-anagram/ + https://leetcode-cn.com/problems/group-anagrams/ + https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + +回文串问题 + + https://leetcode-cn.com/problems/valid-palindrome/ + https://leetcode-cn.com/problems/valid-palindrome-ii/ + https://leetcode-cn.com/problems/longest-palindromic-substring/ + + +最长子串、子序列问题 + + https://leetcode-cn.com/problems/longest-common-subsequence/ + https://leetcode-cn.com/problems/edit-distance/ + https://leetcode-cn.com/problems/longest-palindromic-substring/ + +字符串 +DP 问题 + + https://leetcode-cn.com/problems/regular-expression-matching/ + https://leetcode-cn.com/problems/regular-expression-matching/solution/ji-yu-guan-fang-ti-jie-gen-xiang-xi-de-jiang-jie-b/ + https://leetcode-cn.com/problems/wildcard-matching/ + https://leetcode-cn.com/problems/distinct-subsequences/ + + +参考链接 + + Boyer-Moore 算法 http://xn--https-ni33a//www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html + Sunday 算法 https://blog.csdn.net/u012505432/article/details/52210975 + 字符串匹配暴力法代码示例 https://shimo.im/docs/dQDxQW8yXPXxh3Hg/read +``` +public static int forceSearch(String txt, String pat) { + int M = txt.length(); + int N = pat.length(); + + for (int i = 0; i <= M - N; i++) { + int j; + for (j = 0; j < N; j++) { + if (txt.charAt(i + j) != pat.charAt(j)) + break; + } + if (j == N) { + return i; + } + // 更加聪明? + // 1. 预先判断 hash(txt.substring(i, M)) == hash(pat) + // 2. KMP + } + return -1; +} +``` + Rabin-Karp 代码示例 +``` +public final static int D = 256; +public final static int Q = 9997; + +static int RabinKarpSerach(String txt, String pat) { + int M = pat.length(); + int N = txt.length(); + int i, j; + int patHash = 0, txtHash = 0; + + for (i = 0; i < M; i++) { + patHash = (D * patHash + pat.charAt(i)) % Q; + txtHash = (D * txtHash + txt.charAt(i)) % Q; + } + + int highestPow = 1; // pow(256, M-1) + for (i = 0; i < M - 1; i++) + highestPow = (highestPow * D) % Q; + + for (i = 0; i <= N - M; i++) { // 枚举起点 + if (patHash == txtHash) { + for (j = 0; j < M; j++) { + if (txt.charAt(i + j) != pat.charAt(j)) + break; + } + if (j == M) + return i; + } + if (i < N - M) { + txtHash = (D * (txtHash - txt.charAt(i) * highestPow) + txt.charAt(i + M)) % Q; + if (txtHash < 0) + txtHash += Q; + } + } + + return -1; +} +``` + KMP 字符串匹配算法视频 https://www.bilibili.com/video/av11866460?from=search&seid=17425875345653862171 + 字符串匹配的 KMP 算法 http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html + +课后作业 + + https://leetcode-cn.com/problems/first-unique-character-in-a-string/ + https://leetcode-cn.com/problems/string-to-integer-atoi/ + https://leetcode-cn.com/problems/reverse-string-ii/ + https://leetcode-cn.com/problems/reverse-words-in-a-string/ + https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ + https://leetcode-cn.com/problems/reverse-only-letters/ + https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + https://leetcode-cn.com/problems/longest-palindromic-substring/ + https://leetcode-cn.com/problems/isomorphic-strings/ + https://leetcode-cn.com/problems/valid-palindrome-ii/ + https://leetcode-cn.com/problems/wildcard-matching + https://leetcode-cn.com/problems/longest-valid-parentheses + https://leetcode-cn.com/problems/distinct-subsequences/ + diff --git a/Week 08/id_586/leetcode_10.cc b/Week 08/id_586/leetcode_10.cc new file mode 100644 index 000000000..27a146086 --- /dev/null +++ b/Week 08/id_586/leetcode_10.cc @@ -0,0 +1,72 @@ +// We define dp[i][j] to be true if s[0..i) matches p[0..j) and false otherwise. The state equations will be: + + // dp[i][j] = dp[i - 1][j - 1], if p[j - 1] != '*' && (s[i - 1] == p[j - 1] || p[j - 1] == '.'); + // dp[i][j] = dp[i][j - 2], if p[j - 1] == '*' and the pattern repeats for 0 time; + // dp[i][j] = dp[i - 1][j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.'), if p[j - 1] == '*' and the pattern repeats for at least 1 time. + +class Solution { +public: + bool isMatch(string s, string p) { + int m = s.size(), n = p.size(); + vector> dp(m + 1, vector(n + 1, false)); + dp[0][0] = true; + for (int i = 0; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (p[j - 1] == '*') { + dp[i][j] = dp[i][j - 2] || (i && dp[i - 1][j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.')); + } else { + dp[i][j] = i && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.'); + } + } + } + return dp[m][n]; + } +}; + +// And you may further reduce the memory usage down to two vectors (O(n)). + +class Solution { +public: + bool isMatch(string s, string p) { + int m = s.size(), n = p.size(); + vector pre(n + 1, false), cur(n + 1, false); + cur[0] = true; + for (int i = 0; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (p[j - 1] == '*') { + cur[j] = cur[j - 2] || (i && pre[j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.')); + } else { + cur[j] = i && pre[j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.'); + } + } + fill(pre.begin(), pre.end(), false); + swap(pre, cur); + } + return pre[n]; + } +}; + +// Or even just one vector. + +class Solution { +public: + bool isMatch(string s, string p) { + int m = s.size(), n = p.size(); + vector cur(n + 1, false); + for (int i = 0; i <= m; i++) { + bool pre = cur[0]; + cur[0] = !i; + for (int j = 1; j <= n; j++) { + bool temp = cur[j]; + if (p[j - 1] == '*') { + cur[j] = cur[j - 2] || (i && cur[j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.')); + } else { + cur[j] = i && pre && (s[i - 1] == p[j - 1] || p[j - 1] == '.'); + } + pre = temp; + } + } + return cur[n]; + } +}; + diff --git a/Week 08/id_586/leetcode_125.cc b/Week 08/id_586/leetcode_125.cc new file mode 100644 index 000000000..eb2dade85 --- /dev/null +++ b/Week 08/id_586/leetcode_125.cc @@ -0,0 +1,10 @@ + +bool isPalindrome(string s) { + for (int i = 0, j = s.size() - 1; i < j; i++, j--) { // Move 2 pointers from each end until they collide + while (isalnum(s[i]) == false && i < j) i++; // Increment left pointer if not alphanumeric + while (isalnum(s[j]) == false && i < j) j--; // Decrement right pointer if no alphanumeric + if (toupper(s[i]) != toupper(s[j])) return false; // Exit and return error if not match + } + + return true; +} diff --git a/Week 08/id_586/leetcode_14.cc b/Week 08/id_586/leetcode_14.cc new file mode 100644 index 000000000..b5589cc16 --- /dev/null +++ b/Week 08/id_586/leetcode_14.cc @@ -0,0 +1,11 @@ +class Solution { +public: + string longestCommonPrefix(vector& strs) { + string prefix = ""; + for(int idx=0; strs.size()>0; prefix+=strs[0][idx], idx++) + for(int i=0; i= strs[i].size() ||(i > 0 && strs[i][idx] != strs[i-1][idx])) + return prefix; + return prefix; + } +}; diff --git a/Week 08/id_586/leetcode_344.cc b/Week 08/id_586/leetcode_344.cc new file mode 100644 index 000000000..5b333aa72 --- /dev/null +++ b/Week 08/id_586/leetcode_344.cc @@ -0,0 +1,11 @@ +class Solution { +public: + string reverseString(string s) { + int i = 0, j = s.size() - 1; + while(i < j){ + swap(s[i++], s[j--]); + } + + return s; + } +}; diff --git a/Week 08/id_586/leetcode_387.cc b/Week 08/id_586/leetcode_387.cc new file mode 100644 index 000000000..5ebf9d32d --- /dev/null +++ b/Week 08/id_586/leetcode_387.cc @@ -0,0 +1,14 @@ +class Solution { +public: + int firstUniqChar(string s) { + vector v(26); + + for(int i = 0; i < s.length(); ++i) + v[s[i]-'a']++; + + for(int i = 0; i < s.length(); ++i) + if(v[s[i]-'a'] == 1) + return i; + return -1; + } +}; diff --git a/Week 08/id_586/leetcode_5.cc b/Week 08/id_586/leetcode_5.cc new file mode 100644 index 000000000..0eca55127 --- /dev/null +++ b/Week 08/id_586/leetcode_5.cc @@ -0,0 +1,55 @@ +class Solution { +public: + string longestPalindrome(string s) { + int len = s.size(); + if(len == 0 || len == 1) return s; + + int start = 0; + int max = 1; + vector> dp(len, vector(len)); + + for (int i = 0; i < len; i++) { + dp[i][i] = 1; + if(i < len - 1 && s[i] == s[i+1]) { + dp[i][i+1] = 1; + max = 2; + start = i; + } + } + + for (int i = 3;i <= len; i++) { + for (int j = 0; i + j - 1 < len; j++) { + int end = i + j - 1; + if(s[j] == s[end] && dp[j+1][end-1] == 1) { + dp[j][end]=1; + start=j; + max=i; + } + } + } + + return s.substr(start, max); + } + + // string longestPalindrome(string s) { + // int len = s.size(); + // if (len <= 1) return s; + // int lpos = 0, lm = 0; // position of first letter and length + // for ( int i = 0; i < len - 1; i++) { + // if (lm >= (len - i) * 2) return s.substr(lpos,lm); + // int count = 0; + // while (s[i + 1] == s[i] && i++ < len - 1) + // count++; + // int end = i; + // int first = i - count; + // while (s[--first] == s[++end] && first >= 0 && end < len); + // end--; + // first++; + // if ( lm < end - first + 1){ + // lpos = first; + // lm = end - first + 1; + // } + // } + // return s.substr(lpos, lm); + // } +}; diff --git a/Week 08/id_586/leetcode_541.cc b/Week 08/id_586/leetcode_541.cc new file mode 100644 index 000000000..6a33ff2a1 --- /dev/null +++ b/Week 08/id_586/leetcode_541.cc @@ -0,0 +1,17 @@ + +class Solution { +public: + /** + * 0 k 2k 3k + * |-----------|-----------|-----------|--- + * +--reverse--+ +--reverse--+ + */ + string reverseStr(string s, int k) { + for (int left = 0; left < s.size(); left += 2 * k) { + for (int i = left, j = min(left + k - 1, (int)s.size() - 1); i < j; i++, j--) { + swap(s[i], s[j]); + } + } + return s; + } +}; diff --git a/Week 08/id_586/leetcode_680.cc b/Week 08/id_586/leetcode_680.cc new file mode 100644 index 000000000..95b14c40a --- /dev/null +++ b/Week 08/id_586/leetcode_680.cc @@ -0,0 +1,10 @@ +bool validPalindrome(string s) { + for (int i = 0, j = s.size() - 1; i < j; i++, j--) + if (s[i] != s[j]) { + int i1 = i, j1 = j - 1, i2 = i + 1, j2 = j; + while (i1 < j1 && s[i1] == s[j1]) {i1++; j1--;}; + while (i2 < j2 && s[i2] == s[j2]) {i2++; j2--;}; + return i1 >= j1 || i2 >= j2; + } + return true; +} diff --git a/Week 08/id_586/leetcode_72.cc b/Week 08/id_586/leetcode_72.cc new file mode 100644 index 000000000..a1cb7473e --- /dev/null +++ b/Week 08/id_586/leetcode_72.cc @@ -0,0 +1,91 @@ +// To apply DP, we define the state dp[i][j] to be the minimum number of operations to convert word1[0..i) to word2[0..j). + +// For the base case, that is, to convert a string to an empty string, the mininum number of operations (deletions) is just the length of the string. So we have dp[i][0] = i and dp[0][j] = j. + +// For the general case to convert word1[0..i) to word2[0..j), we break this problem down into sub-problems. Suppose we have already known how to convert word1[0..i - 1) to word2[0..j - 1) (dp[i - 1][j - 1]), if word1[i - 1] == word2[j - 1], then no more operation is needed and dp[i][j] = dp[i - 1][j - 1]. + +// If word1[i - 1] != word2[j - 1], we need to consider three cases. + + // Replace word1[i - 1] by word2[j - 1] (dp[i][j] = dp[i - 1][j - 1] + 1); + // If word1[0..i - 1) = word2[0..j) then delete word1[i - 1] (dp[i][j] = dp[i - 1][j] + 1); + // If word1[0..i) + word2[j - 1] = word2[0..j) then insert word2[j - 1] to word1[0..i) (dp[i][j] = dp[i][j - 1] + 1). + +// So when word1[i - 1] != word2[j - 1], dp[i][j] will just be the minimum of the above three cases. + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 1; j <= n; j++) { + dp[0][j] = j; + } + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (word1[i - 1] == word2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1; + } + } + } + return dp[m][n]; + } +}; + +// Note that each time when we update dp[i][j], we only need dp[i - 1][j - 1], dp[i][j - 1] and dp[i - 1][j]. We may optimize the space of the code to use only two vectors. + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(); + vector pre(n + 1, 0), cur(n + 1, 0); + for (int j = 1; j <= n; j++) { + pre[j] = j; + } + for (int i = 1; i <= m; i++) { + cur[0] = i; + for (int j = 1; j <= n; j++) { + if (word1[i - 1] == word2[j - 1]) { + cur[j] = pre[j - 1]; + } else { + cur[j] = min(pre[j - 1], min(cur[j - 1], pre[j])) + 1; + } + } + fill(pre.begin(), pre.end(), 0); + swap(pre, cur); + } + return pre[n]; + } +}; + +// Or even just one vector. + +class Solution { +public: + int minDistance(string word1, string word2) { + int m = word1.size(), n = word2.size(), pre; + vector cur(n + 1, 0); + for (int j = 1; j <= n; j++) { + cur[j] = j; + } + for (int i = 1; i <= m; i++) { + pre = cur[0]; + cur[0] = i; + for (int j = 1; j <= n; j++) { + int temp = cur[j]; + if (word1[i - 1] == word2[j - 1]) { + cur[j] = pre; + } else { + cur[j] = min(pre, min(cur[j - 1], cur[j])) + 1; + } + pre = temp; + } + } + return cur[n]; + } +}; + diff --git a/Week 08/id_586/leetcode_8.cc b/Week 08/id_586/leetcode_8.cc new file mode 100644 index 000000000..8cfc73d62 --- /dev/null +++ b/Week 08/id_586/leetcode_8.cc @@ -0,0 +1,28 @@ +class Solution { +public: + int myAtoi(string str) { + int res = 0; + int i = 0; + int flag = 1; + + // 1. 检查空格 + while (str[i] == ' ') i++; + + // 2. 检查符号 + if (str[i] == '-') flag = -1; + if (str[i] == '+' || str[i] == '-') i++; + + // 3. 计算数字 + while (i < str.size() && isdigit(str[i])) { + int r = str[i] - '0'; + + // ------ 4. 处理溢出,这是关键步骤 ------ + if (res > INT_MAX / 10 || (res == INT_MAX / 10 && r > 7)) + return flag > 0 ? INT_MAX : INT_MIN; + + res = res * 10 + r; + i++; + } + return flag > 0 ? res : -res; + } +}; diff --git a/Week 08/id_591/NOTE.md b/Week 08/id_591/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_591/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_596/LeetCode_300_596.py b/Week 08/id_596/LeetCode_300_596.py new file mode 100644 index 000000000..a9721b6e3 --- /dev/null +++ b/Week 08/id_596/LeetCode_300_596.py @@ -0,0 +1,10 @@ +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + if nums == []: + return 0 + cell = [1] * len(nums) + for i in range(1, len(nums)): + for j in range(i): + if nums[j] < nums[i]: + cell[i] = max(cell[i], cell[j]+1) + return max(cell) \ No newline at end of file diff --git a/Week 08/id_596/LeetCode_917_596.py b/Week 08/id_596/LeetCode_917_596.py new file mode 100644 index 000000000..bd0545be2 --- /dev/null +++ b/Week 08/id_596/LeetCode_917_596.py @@ -0,0 +1,14 @@ +class Solution: + def reverseOnlyLetters(self, S: str) -> str: + chars = list(S) + low, high = 0, len(chars) - 1 + while low < high: + if not chars[low].isalpha(): + low += 1 + elif not chars[high].isalpha(): + high -= 1 + else: + chars[low], chars[high] = chars[high], chars[low] + low += 1 + high -= 1 + return "".join(chars) \ No newline at end of file diff --git a/Week 08/id_596/NOTE.md b/Week 08/id_596/NOTE.md new file mode 100755 index 000000000..2ea3717ba --- /dev/null +++ b/Week 08/id_596/NOTE.md @@ -0,0 +1,33 @@ +# 学习笔记 + +## 高级动态规划 + +动态规划 和 递归或者分治:没有根本上的区别(关键看有无最优的子结构) + +拥有共性:找到重复子问题差异性:最优子结构、中途可以淘汰次优解。 + +### 复杂度来源 + +1. 状态拥有更多维度(二维、三维、或者更多、甚至需要压缩) +2. 状态方程更加复杂 + +## 字符串匹配算法 + +### 朴素算法 + +遍历字符串的起始位置,挨个比较后面的所有字符是否与匹配字符串相同。 + +### Rabin-Carp算法 + +为了避免挨个字符对目标字符串和子串进行比较,我们可以尝试一次性判断两者是否相等。因此,我们需要一个好的哈希函数(hash function)。通过哈希函数,我们可以算出子串呆鹅哈希值,然后将它和目标字符串中的子串的哈希值进行比较。这个新方法在速度上比暴力法有显著提升。 + +#### 算法思想 + +1. 假设子串的长度为M(pat),目标字符串的长度为N(txt) +2. 计算子串的hash值hash_pat +3. 计算目标字符串txt中每个长度为M的子串的hash值(共需要计算N-M+1次) +4. 比较hash值:如果hash值不同,字符串必然不匹配;如果hash值相同,还需要使用朴素算法再次判断。 + +### KMP算法 + +思想是设法利用已知信息,不要把“搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。 \ No newline at end of file diff --git a/Week 08/id_601/NOTE.md b/Week 08/id_601/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_601/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git "a/Week 08/id_606/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/Week 08/id_606/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 000000000..bf241f2a5 --- /dev/null +++ "b/Week 08/id_606/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,48 @@ +/* + * @lc app=leetcode.cn id=387 lang=java + * + * [387] 字符串中的第一个唯一字符 + * + * https://leetcode-cn.com/problems/first-unique-character-in-a-string/description/ + * + * algorithms + * Easy (41.50%) + * Likes: 162 + * Dislikes: 0 + * Total Accepted: 51.6K + * Total Submissions: 123.3K + * Testcase Example: '"leetcode"' + * + * 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 + * + * 案例: + * + * + * s = "leetcode" + * 返回 0. + * + * s = "loveleetcode", + * 返回 2. + * + * + * + * + * 注意事项:您可以假定该字符串只包含小写字母。 + * + */ + +// @lc code=start +class Solution { + public int firstUniqChar(String s) { + int[] letter = new int[26];//存储各字符出现次数 + for (char c : s.toCharArray())//第一次遍历 + letter[c - 'a']++; + for (int i = 0; i < s.length(); i++) {//第二次遍历 + if (letter[s.charAt(i) - 'a'] == 1) + return i; + } + return -1;//无解 + + } +} +// @lc code=end diff --git "a/Week 08/id_606/8.\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260-atoi.java" "b/Week 08/id_606/8.\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260-atoi.java" new file mode 100644 index 000000000..3eb358a88 --- /dev/null +++ "b/Week 08/id_606/8.\345\255\227\347\254\246\344\270\262\350\275\254\346\215\242\346\225\264\346\225\260-atoi.java" @@ -0,0 +1,105 @@ +/* + * @lc app=leetcode.cn id=8 lang=java + * + * [8] 字符串转换整数 (atoi) + * + * https://leetcode-cn.com/problems/string-to-integer-atoi/description/ + * + * algorithms + * Medium (18.50%) + * Likes: 484 + * Dislikes: 0 + * Total Accepted: 90.5K + * Total Submissions: 486K + * Testcase Example: '"42"' + * + * 请你来实现一个 atoi 函数,使其能将字符串转换成整数。 + * + * 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。 + * + * + * 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。 + * + * 该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。 + * + * 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。 + * + * 在任何情况下,若函数不能进行有效的转换时,请返回 0。 + * + * 说明: + * + * 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31,  2^31 − 1]。如果数值超过这个范围,请返回  INT_MAX + * (2^31 − 1) 或 INT_MIN (−2^31) 。 + * + * 示例 1: + * + * 输入: "42" + * 输出: 42 + * + * + * 示例 2: + * + * 输入: " -42" + * 输出: -42 + * 解释: 第一个非空白字符为 '-', 它是一个负号。 + * 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 + * + * + * 示例 3: + * + * 输入: "4193 with words" + * 输出: 4193 + * 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。 + * + * + * 示例 4: + * + * 输入: "words and 987" + * 输出: 0 + * 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 + * ⁠ 因此无法执行有效的转换。 + * + * 示例 5: + * + * 输入: "-91283472332" + * 输出: -2147483648 + * 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 + * 因此返回 INT_MIN (−2^31) 。 + * + * + */ + +// @lc code=start +class Solution { + public int myAtoi(String str) { + if (str.isEmpty()) + return 0; + char[] mychar = str.toCharArray(); + long ans = 0; + int i = 0, sign = 1, n = str.length(); + while (i < n && mychar[i] == ' ') { + i++; + } + if (i < n && mychar[i] == '+') { + i++; + } else if (i < n && mychar[i] == '-') { + i++; + sign = -1; + } + //重点:只管是数字的时候,其余取0 + while (i < n && (mychar[i] >= '0' && mychar[i] <= '9')) { + if (ans != (int) ans) { + return (sign == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE; + } + ans = ans * 10 + mychar[i++] - '0'; + } + + if (ans != (int) ans) { + return (sign == 1) ? Integer.MAX_VALUE : Integer.MIN_VALUE; + } + + return (int) (ans * sign); + + } +} +// @lc code=end diff --git a/Week 08/id_606/NOTE.md b/Week 08/id_606/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_606/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_611/NOTE.md b/Week 08/id_611/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_611/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_611/leetcode_115_611.java b/Week 08/id_611/leetcode_115_611.java new file mode 100644 index 000000000..567fae2a0 --- /dev/null +++ b/Week 08/id_611/leetcode_115_611.java @@ -0,0 +1,16 @@ +class Solution { + public int numDistinct(String s, String t) { + int[][] dp = new int[t.length()+1][s.length()+1]; + for(int j =0; j < s.length()+1; j++) + dp[0][j] =1; + for(int i =1; i < t.length() + 1; i++){ + for(int j =1; j < s.length() + 1; j++){ + if(t.charAt(i-1) == s.charAt(j-1)) + dp[i][j] = dp[i-1][j-1] + dp[i][j-1]; + else + dp[i][j] = dp[i][j-1]; + } + } + return dp[t.length()][s.length()]; + } +} \ No newline at end of file diff --git a/Week 08/id_611/leetcode_300_611.java b/Week 08/id_611/leetcode_300_611.java new file mode 100644 index 000000000..463be5592 --- /dev/null +++ b/Week 08/id_611/leetcode_300_611.java @@ -0,0 +1,21 @@ +class Solution { + public int lengthOfLIS(int[] nums) { + if(nums.length == 0){ + return 0; + } + int[] dp = new int[nums.length]; + dp[0] = 1; + int max = 1; + for(int i = 1; i < dp.length; i++){ + int maxval = 0; + for(int j = 0; j < i; j++){ + if(nums[i] > nums[j]){ + maxval = Math.max(maxval,dp[j]); + } + } + dp[i] = maxval +1; + max = Math.max(max, dp[i]); + } + return max; + } +} \ No newline at end of file diff --git a/Week 08/id_611/leetcode_32_611.java b/Week 08/id_611/leetcode_32_611.java new file mode 100644 index 000000000..c2c26ae3a --- /dev/null +++ b/Week 08/id_611/leetcode_32_611.java @@ -0,0 +1,30 @@ +class Solution { + public int longestValidParentheses(String s) { + int left =0, right =0,max =0; + for(int i = 0; i < s.length(); i++){ + if(s.charAt(i) =='('){ + left++; + }else{ + right++; + } + if(left == right){ + max = Math.max(max,right*2); + }else if(right >= left){ + //当右括号数量过多,从左往右数就可以归零 + left = right =0; + } + } + left = right =0; + for(int i = s.length()-1; i >= 0; i--){ + if(s.charAt(i)=='(') + left++; + else + right++; + if(left == right) + max = Math.max(max, left *2); + else if(left >= right) + left = right =0; + } + return max; + } +} \ No newline at end of file diff --git a/Week 08/id_611/leetcode_91_611.java b/Week 08/id_611/leetcode_91_611.java new file mode 100644 index 000000000..76bb4356e --- /dev/null +++ b/Week 08/id_611/leetcode_91_611.java @@ -0,0 +1,28 @@ +class Solution { + public int numDecodings(String s) { + if(s == null || s.length() ==0){ + return 0; + } + int len = s.length(); + int[] dp = new int[len+1]; + dp[len] = 1; + if(s.charAt(len - 1) =='0'){ + dp[len - 1] = 0; + } else { + dp[len - 1] = 1; + } + for(int i = len - 2; i >=0 ; i--){ + if(s.charAt(i)=='0'){ + dp[0] = 0; + continue; + } + if ((s.charAt(i)-'0')*10 + (s.charAt(i+1)-'0') <= 26){ + dp[i] = dp[i+1] + dp[i+2]; + } else { + dp[i] = dp[i+1]; + } + + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week 08/id_616/LeetCode_387_616.cpp b/Week 08/id_616/LeetCode_387_616.cpp new file mode 100644 index 000000000..b41a1fd4a --- /dev/null +++ b/Week 08/id_616/LeetCode_387_616.cpp @@ -0,0 +1,19 @@ +class Solution { +public: + int firstUniqChar(string s) { + vector v(26); + for(int i = 0; i < s.length(); ++i) + { + v[s[i]-'a']++; + } + + for(int i = 0; i < s.length(); ++i) + { + if(v[s[i]-'a'] == 1) + { + return i; + } + } + return -1; + } +}; \ No newline at end of file diff --git a/Week 08/id_616/LeetCode_5_616.cpp b/Week 08/id_616/LeetCode_5_616.cpp new file mode 100644 index 000000000..e0d573e84 --- /dev/null +++ b/Week 08/id_616/LeetCode_5_616.cpp @@ -0,0 +1,33 @@ +class Solution { +public: + string longestPalindrome(string s) { + int len=s.size(); + if(len == 0 || len ==1) return s; + + int start = 0; + int max = 1; + vector> dp(len,vector(len)); + for(int i = 0; i < len; i++){ + dp[i][i] = 1; + if(i < len - 1 && s[i] == s[i+1]){ + dp[i][i+1] = 1; + max = 2; + start = i; + } + } + + for(int i=3;i <= len; i++){ + for(int j=0; i + j - 1 < len; j++){ + int end = i + j - 1; + if(s[j]==s[end] && dp[j+1][end-1]==1) + { + dp[j][end]=1; + start=j; + max=i; + } + } + } + + return s.substr(start,max); + } +}; \ No newline at end of file diff --git a/Week 08/id_616/LeetCode_8_616.cpp b/Week 08/id_616/LeetCode_8_616.cpp new file mode 100644 index 000000000..e40a93620 --- /dev/null +++ b/Week 08/id_616/LeetCode_8_616.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int myAtoi(string str) { + int res = 0; + int i = 0; + int flag = 1; + + while (str[i] == ' ') { i++; } + + if (str[i] == '-') { flag = -1; } + if (str[i] == '+' || str[i] == '-') { i++; } + + while (i < str.size() && isdigit(str[i])) { + int r = str[i] - '0'; + if (res > INT_MAX / 10 || (res == INT_MAX / 10 && r > 7)) { + return flag > 0 ? INT_MAX : INT_MIN; + } + res = res * 10 + r; + i++; + } + return flag > 0 ? res : -res; + } +}; \ No newline at end of file diff --git a/Week 08/id_616/NOTE.md b/Week 08/id_616/NOTE.md new file mode 100755 index 000000000..9c341b65a --- /dev/null +++ b/Week 08/id_616/NOTE.md @@ -0,0 +1,20 @@ +# 学习总结 + +## 高级DP + +复杂度来源: +状态拥有更多的维度(二维、三维、或者更多、甚至需要压缩) +状态方程更加复杂 + +## 字符串算法 + +字符串基础 +字符串操作 +异位词问题 +回文串问题 + +## 字符串匹配算法 + +- 暴力法 +- Rabin-karp 算法 +- KMP算法 diff --git a/Week 08/id_621/NOTE.md b/Week 08/id_621/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_621/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_626/NOTE.md b/Week 08/id_626/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_626/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_631/LeetCode_151_631.go b/Week 08/id_631/LeetCode_151_631.go new file mode 100644 index 000000000..d48327cdb --- /dev/null +++ b/Week 08/id_631/LeetCode_151_631.go @@ -0,0 +1,21 @@ +//once 20191208 20:19 + +func reverseWords(s string) string { + // 切分 + bytesSlice := bytes.Split([]byte(s), []byte{' '}) + + var dstBytes []byte + for i := len(bytesSlice) - 1; i >= 0; i-- { + // 剔除[]byte{''}的元素 + if len(bytesSlice[i]) == 0 { + continue + } + if len(dstBytes) > 0 { + dstBytes = append(dstBytes, byte(' ')) + } + dstBytes = append(dstBytes, bytesSlice[i]...) + + } + + return string(dstBytes) +} \ No newline at end of file diff --git a/Week 08/id_631/LeetCode_300_631.go b/Week 08/id_631/LeetCode_300_631.go new file mode 100644 index 000000000..7b4665000 --- /dev/null +++ b/Week 08/id_631/LeetCode_300_631.go @@ -0,0 +1,26 @@ + +// 100% 80.95% +func lengthOfLIS(nums []int) int { + size := 0 + length := len(nums) + tail := make([]int, length) + + for i := 0; i < length; i++ { + if size == 0 || tail[size - 1] < nums[i] { + tail[size] = nums[i] + size++ + } else { + x, y := 0, size - 1 + for x < y { + mid := (x + y) / 2 + if tail[mid] < nums[i] { + x = mid + 1 + } else { + y = mid + } + } + tail[x] = nums[i] + } + } + return size +} \ No newline at end of file diff --git a/Week 08/id_631/LeetCode_541_631.go b/Week 08/id_631/LeetCode_541_631.go new file mode 100644 index 000000000..8f2702c93 --- /dev/null +++ b/Week 08/id_631/LeetCode_541_631.go @@ -0,0 +1,31 @@ + + +//只有小写英文字母 +//长度[1, 10000] + +func reverseStr(s string, k int) string { + var strBytes = []byte(s) + var sLen = len(strBytes) + + var reverseInPlace = func(i int, j int) { + for i < j { + strBytes[i], strBytes[j] = strBytes[j], strBytes[i] + i++ + j-- + } + } + + i := 0 + for sLen >= 2 * k { + reverseInPlace(i, i + k - 1) + i += 2 * k + sLen -= 2 * k + } + + if sLen < k { + reverseInPlace(i, len(strBytes) - 1) + } else if sLen < 2 * k { + reverseInPlace(i, i + k - 1) + } + return string(strBytes) +} \ No newline at end of file diff --git a/Week 08/id_631/LeetCode_8_631.go b/Week 08/id_631/LeetCode_8_631.go new file mode 100644 index 000000000..8aaa87c8b --- /dev/null +++ b/Week 08/id_631/LeetCode_8_631.go @@ -0,0 +1,56 @@ + +//trim left space +//trim left other +// 默认为0 +//只算32位 + +const ( + int32Max = 1 << 31 - 1 + int32Min = -1 << 31 +) + +func myAtoi(str string) int { + n := len(str) + var i, j int + neg := false + + //找出最高位 + for i = 0; i < n; i++ { + if str[i] >= '0' && str[i] <= '9' { + break + } else if str[i] == '+' { + i++ + break + } else if str[i] == '-' { + neg = true + i++ + break + } else if str[i] != ' ' { + return 0 + } + } + + //找出最后一位的下一位 + for j = i; j < n; j++ { + if str[j] < '0' || str[j] > '9' { + break + } + } + + ret := 0 + for k := i; k < j; k++ { + cur := int(str[k] - '0') + if !neg { + ret = ret * 10 + cur + if ret > int32Max { + return int32Max + } + } else { + ret = ret * 10 - cur + if ret < int32Min { + return int32Min + } + } + } + return ret +} \ No newline at end of file diff --git a/Week 08/id_631/NOTE.md b/Week 08/id_631/NOTE.md new file mode 100755 index 000000000..1cf4c23db --- /dev/null +++ b/Week 08/id_631/NOTE.md @@ -0,0 +1,29 @@ +## 高级动态规划 + 1. 最近重复性的理解 + 拆解的过于小的话,程序会比较繁琐 + 最大公约数 + 2. 动态规划 Dynamic Programming + 将复杂问题分解成简单的子问题 + 分治+最优子结构 + 顺推形式:动态递推 + 3. 与分治对比 + 动态规划和递归或者分治没有根本上的区别(关键看有无最优子结构) + 拥有共性:找到重复子问题 + 差异性:最优子结构、中途可以淘汰次优解 + 4. 复杂度来源 + 状态拥有更多维度(二维,三位,更多,甚至压缩) + 状态方程更加复杂 + 5. 考的本质是,内功、罗辑思维、数学 + 6. Unique Paths II 的状态转移方程: paths[i][j] = paths[i - 1][j] + paths[i][j - 1]; +## 字符串 + 1. 字符串算法 + 1. 字符串基础 + 2. 字符串操作 + 3. 异位词问题 + 4. 回文串问题 + 2. 字符串匹配算法 + 1. 暴力法(brute force) + 2. Rabin-Karp 算法 + 3. KMP 算法 + 4. Boyer-Moore 算法 + 5. Sunday 算法 \ No newline at end of file diff --git a/Week 08/id_636/NOTE.md b/Week 08/id_636/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_636/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_641/NOTE.md b/Week 08/id_641/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_641/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_641/lesson19/LeetCode_300_641.java b/Week 08/id_641/lesson19/LeetCode_300_641.java new file mode 100644 index 000000000..569269554 --- /dev/null +++ b/Week 08/id_641/lesson19/LeetCode_300_641.java @@ -0,0 +1,21 @@ +package vip.ruoyun.week8.lesson19; + +public class LeetCode_300_641 { + + //动态规划 + public int lengthOfLIS(int[] nums) { + int[] tails = new int[nums.length]; + int res = 0; + for (int num : nums) { + int i = 0, j = res; + while (i < j) { + int m = (i + j) / 2; + if (tails[m] < num) i = m + 1; + else j = m; + } + tails[i] = num; + if (res == j) res++; + } + return res; + } +} diff --git a/Week 08/id_641/lesson19/LeetCode_91_641.java b/Week 08/id_641/lesson19/LeetCode_91_641.java new file mode 100644 index 000000000..9cd5fd569 --- /dev/null +++ b/Week 08/id_641/lesson19/LeetCode_91_641.java @@ -0,0 +1,31 @@ +package vip.ruoyun.week8.lesson19; + +public class LeetCode_91_641 { + + public int numDecodings(String s) { + return getAns(s, 0); + } + + private int getAns(String s, int start) { + //划分到了最后返回 1 + if (start == s.length()) { + return 1; + } + //开头是 0,0 不对应任何字母,直接返回 0 + if (s.charAt(start) == '0') { + return 0; + } + //得到第一种的划分的解码方式 + int ans1 = getAns(s, start + 1); + int ans2 = 0; + //判断前两个数字是不是小于等于 26 的 + if (start < s.length() - 1) { + int ten = (s.charAt(start) - '0') * 10; + int one = s.charAt(start + 1) - '0'; + if (ten + one <= 26) { + ans2 = getAns(s, start + 2); + } + } + return ans1 + ans2; + } +} diff --git a/Week 08/id_641/lesson20/LeetCode_387_641.java b/Week 08/id_641/lesson20/LeetCode_387_641.java new file mode 100644 index 000000000..e9a3b541d --- /dev/null +++ b/Week 08/id_641/lesson20/LeetCode_387_641.java @@ -0,0 +1,22 @@ +package vip.ruoyun.week8.lesson20; + +import java.util.HashMap; + +public class LeetCode_387_641 { + public int firstUniqChar(String s) { + HashMap count = new HashMap(); + int n = s.length(); + // build hash map : character and how often it appears + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + count.put(c, count.getOrDefault(c, 0) + 1); + } + + // find the index + for (int i = 0; i < n; i++) { + if (count.get(s.charAt(i)) == 1) + return i; + } + return -1; + } +} diff --git a/Week 08/id_646/NOTE.md b/Week 08/id_646/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_646/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_651/NOTE.md b/Week 08/id_651/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_651/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_656/NOTE.md b/Week 08/id_656/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_656/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_661/NOTE.md b/Week 08/id_661/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_661/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_666/LeetCode_58_666.java b/Week 08/id_666/LeetCode_58_666.java new file mode 100644 index 000000000..affba9a72 --- /dev/null +++ b/Week 08/id_666/LeetCode_58_666.java @@ -0,0 +1,11 @@ +import java.lang.String; + +class Solution { + public int lengthOfLastWord(String s) { + String[] arr = s.split(" "); + if (arr.length >=1) { + return arr[arr.length -1].length(); + } + return 0; + } +} \ No newline at end of file diff --git a/Week 08/id_666/LeetCode_709_666.java b/Week 08/id_666/LeetCode_709_666.java new file mode 100644 index 000000000..f930adab3 --- /dev/null +++ b/Week 08/id_666/LeetCode_709_666.java @@ -0,0 +1,16 @@ +import java.lang.StringBuilder; +import java.util.Map; + +class Solution { + public String toLowerCase(String str) { + String result = ""; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c >= 65 && c <= 90) { + c += 32; + } + result += c; + } + return result; + } +} \ No newline at end of file diff --git a/Week 08/id_666/LeetCode_771_666.java b/Week 08/id_666/LeetCode_771_666.java new file mode 100644 index 000000000..43917c3f8 --- /dev/null +++ b/Week 08/id_666/LeetCode_771_666.java @@ -0,0 +1,20 @@ +import java.lang.String; +import java.lang.String; + +class Solution { + public int numJewelsInstones(String J, String s) { + Set Jset = new HashSet(); + for (char j: J.toCharArray()) { + Jset.add(j); + } + + int ans = 0; + for (char s: S.toCharArray()) { + if (Jset.contains(s)) { + ans++; + } + } + + return ans; + } +} \ No newline at end of file diff --git a/Week 08/id_666/NOTE.md b/Week 08/id_666/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_666/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_671/NOTE.md b/Week 08/id_671/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_671/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_676/NOTE.md b/Week 08/id_676/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_676/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_681/LeetCode_300_681.java b/Week 08/id_681/LeetCode_300_681.java new file mode 100644 index 000000000..fe47f5418 --- /dev/null +++ b/Week 08/id_681/LeetCode_300_681.java @@ -0,0 +1,17 @@ +public class Solution { + public int lengthOfLIS(int[] nums) { + return lengthofLIS(nums, Integer.MIN_VALUE, 0); + } + + public int lengthofLIS(int[] nums, int prev, int curpos) { + if (curpos == nums.length) { + return 0; + } + int taken = 0; + if (nums[curpos] > prev) { + taken = 1 + lengthofLIS(nums, nums[curpos], curpos + 1); + } + int nottaken = lengthofLIS(nums, prev, curpos + 1); + return Math.max(taken, nottaken); + } +} diff --git a/Week 08/id_681/LeetCode_387_681.java b/Week 08/id_681/LeetCode_387_681.java new file mode 100644 index 000000000..5daabecff --- /dev/null +++ b/Week 08/id_681/LeetCode_387_681.java @@ -0,0 +1,15 @@ +class Solution { + public int firstUniqChar(String s) { + HashMap count = new HashMap(); + int n = s.length(); + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + count.put(c, count.getOrDefault(c, 0) + 1); + } + for (int i = 0; i < n; i++) { + if (count.get(s.charAt(i)) == 1) + return i; + } + return -1; + } +} diff --git a/Week 08/id_681/NOTE.md b/Week 08/id_681/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_681/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_686/LeetCode_32_686.py b/Week 08/id_686/LeetCode_32_686.py new file mode 100644 index 000000000..2fd401a6c --- /dev/null +++ b/Week 08/id_686/LeetCode_32_686.py @@ -0,0 +1,22 @@ +# +# @lc app=leetcode.cn id=32 lang=python3 +# +# [32] 最长有效括号 +# + +# @lc code=start +class Solution: + def longestValidParentheses(self, s: str) -> int: + stack = [-1] + res = 0 + for i in range(len(s)): + c = s[i] + if c == ')' and stack[-1] != -1 and s[stack[-1]] == '(': + stack.pop() + res = max(i-stack[-1], res) + else: + stack.append(i) + return res + +# @lc code=end + diff --git a/Week 08/id_686/LeetCode_85_686.py b/Week 08/id_686/LeetCode_85_686.py new file mode 100644 index 000000000..e6ab4758e --- /dev/null +++ b/Week 08/id_686/LeetCode_85_686.py @@ -0,0 +1,33 @@ +# +# @lc app=leetcode.cn id=85 lang=python3 +# +# [85] 最大矩形 +# + +# @lc code=start +class Solution: + def maximalRectangle(self, matrix: List[List[str]]) -> int: + if len(matrix)==0: + return 0 + m,n=len(matrix),len(matrix[0]) + rec=[0]*(n+1) + + max_rec=0 + for i in range(m): + stack=[-1] + for j in range(n+1): + + if jrec[j]): + h=rec[stack.pop()] + + max_rec=max(max_rec,h*(j-stack[-1]-1)) + stack.append(j) + return max_rec + + +# @lc code=end + diff --git a/Week 08/id_686/NOTE.md b/Week 08/id_686/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_686/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_691/NOTE.md b/Week 08/id_691/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_691/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_696/LeetCode_387_696.java b/Week 08/id_696/LeetCode_387_696.java new file mode 100644 index 000000000..9ac9176ab --- /dev/null +++ b/Week 08/id_696/LeetCode_387_696.java @@ -0,0 +1,16 @@ +package week08; + +class Solution { + public int firstUniqChar(String s) { + int arr [] = new int[26]; + for (int i = 0; i < s.length(); i++) { + arr[s.charAt(i) - 'a']++; + } + for (int i = 0; i < s.length(); i++) { + if (arr[s.charAt(i) - 'a'] == 1) { + return i; + } + } + return -1; + } +} diff --git a/Week 08/id_696/LeetCode_91_696.java b/Week 08/id_696/LeetCode_91_696.java new file mode 100644 index 000000000..6608e29dd --- /dev/null +++ b/Week 08/id_696/LeetCode_91_696.java @@ -0,0 +1,21 @@ +package week08; + +class Solution { + public int numDecodings(String s) { + if (s.charAt(0) == '0') { + return 0; + } + int[] dp = new int[s.length() + 1]; + dp[0] = 1; + dp[1] = 1; + for(int i = 2; i <= s.length(); i++) { + if (s.charAt(i - 1) >= '1' && s.charAt(i - 1) <= '9') { + dp[i] += dp[i - 1]; + } + if (s.charAt(i - 2) == '1' || (s.charAt(i - 2) == '2' && s.charAt(i - 1) < '7')) { + dp[i] += dp[i - 2]; + } + } + return dp[s.length()]; + } +} diff --git a/Week 08/id_696/NOTE.md b/Week 08/id_696/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_696/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_701/LeetCode_151_701.py b/Week 08/id_701/LeetCode_151_701.py new file mode 100644 index 000000000..b929f3e9e --- /dev/null +++ b/Week 08/id_701/LeetCode_151_701.py @@ -0,0 +1,3 @@ +class Solution: + def reverseWords(self, s: str) -> str: + return ' '.join(reversed(s.split())) diff --git a/Week 08/id_701/LeetCode_541_701.py b/Week 08/id_701/LeetCode_541_701.py new file mode 100644 index 000000000..7102cfaa9 --- /dev/null +++ b/Week 08/id_701/LeetCode_541_701.py @@ -0,0 +1,6 @@ +class Solution: + def reverseStr(self, s: str, k: int) -> str: + s = list(s) + for i in range(0, len(s), 2*k): + s[i:i+k] = reversed(s[i:i+k]) + return "".join(s) diff --git a/Week 08/id_701/NOTE.md b/Week 08/id_701/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_701/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_706/NOTE.md b/Week 08/id_706/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_706/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_711/NOTE.md b/Week 08/id_711/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_711/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_716/LeetCode_1143_716.java b/Week 08/id_716/LeetCode_1143_716.java new file mode 100644 index 000000000..3fd75fe40 --- /dev/null +++ b/Week 08/id_716/LeetCode_1143_716.java @@ -0,0 +1,49 @@ +public class LeetCode_1143_716 { + // dp + public int longestCommonSubsequence1(String text1, String text2) { + if (text1 == null || text2 == null) return 0; + if (text1.isEmpty() || text2.isEmpty()) return 0; + + int m = text1.length(); + int n = text2.length(); + + int[][] dp = new int[m + 1][n + 1]; + + for (int i = 1; i < m + 1; i++) { + for (int j = 1; j < n + 1; j++) { + if (text1.charAt(i - 1) == text2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + return dp[m][n]; + } + + // 2. dp opt + public int longestCommonSubsequence(String text1, String text2) { + int m = text1.length() + 1, n = text2.length() + 1; + int[] dp = new int[n]; + char[] text1Arr = ("#" + text1).toCharArray(); + char[] text2Arr = ("#" + text2).toCharArray(); + int temp, now; + for (int i = 1; i < m; i++) { + temp = 0; + for (int j = 1; j < n; j++) { + // 记录(i-1, j-1)位置的最长子序列长度 + now = dp[j]; + if (text1Arr[i] == text2Arr[j]) { + // 要去 (i-1, j-1) 位置的值 + dp[j] = temp + 1; + } else { + dp[j] = Math.max(dp[j-1], dp[j]); + } + // 记录(i-1, j-1)位置的最长子序列长度,传递到(i,j) + temp = now; + } + } + return dp[n-1]; + } +} \ No newline at end of file diff --git a/Week 08/id_716/LeetCode_300_716.java b/Week 08/id_716/LeetCode_300_716.java new file mode 100644 index 000000000..c5f20afba --- /dev/null +++ b/Week 08/id_716/LeetCode_300_716.java @@ -0,0 +1,58 @@ +import java.util.Arrays; + +public class LeetCode_300_716 { + // dp + public int lengthOfLIS1(int[] nums) { + int len = nums.length; + if (len == 0) return 0; + + int[] dp = new int[len]; + Arrays.fill(dp, 1); + + int maxLIS = 1; + + for (int i = 0; i < len; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + maxLIS = Math.max(maxLIS, dp[i]); + } + } + } + + return maxLIS; + } + + // 2. 二分搜索 + // 此解法比较巧妙,作为扩展视野即可,关键还是要理解动态规划解法 + // 将 nums 里的数据非为k堆,需要满足: + // 1. 每堆需要从大到小 + // 2. 取 nums 里的一个新元素时,在已有的堆中找合适的放置位置,有的话放最左边的堆,如果没有开一个新的堆 + public int lengthOfLIS(int[] nums) { + // 存放每个堆的堆顶元素,会构成一个有序的数组 + int[] top = new int[nums.length]; + // 堆的数量 + int piles = 0; + + for (int item : nums) { + // 在堆中找合适的放置位置 + // 在多个堆中应用二分查找:找第一个大于等于 item 的元素 + int lo = 0, hi = piles; + while (lo < hi) { + int mid = lo + (hi - lo) / 2; + if (top[mid] > item) { + hi = mid; + } else if (top[mid] < item) { + lo = mid + 1; + } else { + hi = mid; + } + } + + if (lo == piles) piles++; + top[lo] = item; + } + + return piles; + } +} \ No newline at end of file diff --git a/Week 08/id_716/LeetCode_32_716.java b/Week 08/id_716/LeetCode_32_716.java new file mode 100644 index 000000000..427ac09b3 --- /dev/null +++ b/Week 08/id_716/LeetCode_32_716.java @@ -0,0 +1,24 @@ +import java.util.Deque; +import java.util.LinkedList; + +public class LeetCode_32_716 { + public int longestValidParentheses(String s) { + int maxLen = 0; + Deque stack = new LinkedList<>(); + stack.addFirst(-1); + + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.addFirst(i); + } else { // ) + stack.removeFirst(); + if (stack.isEmpty()) { + stack.addFirst(i); + } else { + maxLen = Math.max(maxLen, i - stack.peekFirst()); + } + } + } + return maxLen; + } +} \ No newline at end of file diff --git a/Week 08/id_716/LeetCode_72_716.java b/Week 08/id_716/LeetCode_72_716.java new file mode 100644 index 000000000..311e337ba --- /dev/null +++ b/Week 08/id_716/LeetCode_72_716.java @@ -0,0 +1,26 @@ +public class LeetCode_72_716 { + // 2. DP + public int minDistance(String word1, String word2) { + int len1 = word1.length(), len2 = word2.length(); + int[][] dp = new int[len1 + 1][len2 + 1]; + // base case + for (int i = 0; i <= len1; i++) { + dp[i][0] = i; + } + for (int i = 0; i <= len2; i++) { + dp[0][i] = i; + } + + for (int i = 1; i <= len1; i++) { + for (int j = 1; j <= len2; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(dp[i - 1][j - 1] + 1, Math.min(dp[i][j - 1] + 1, dp[i - 1][j] + 1)); + } + } + } + + return dp[len1][len2]; + } +} \ No newline at end of file diff --git a/Week 08/id_716/LeetCode_818_716.java b/Week 08/id_716/LeetCode_818_716.java new file mode 100644 index 000000000..e04e256b9 --- /dev/null +++ b/Week 08/id_716/LeetCode_818_716.java @@ -0,0 +1,36 @@ +import java.util.Arrays; + +public class LeetCode_818_716 { + + public int racecar(int target) { + // dp[i] 表示到达位置i所需要的最少步数 + int[] dp = new int[target + 1]; + Arrays.fill(dp, Integer.MAX_VALUE); + + // 到达 i...target, 每个阶段都计算一次 + // 计算每个阶段时,比较未到i之前回头再回头和过了i之后再回头 + for (int i = 1; i <= target; i++) { + // DP 方程:到i之前回头两次的情况 + // 要遍历所有情况,从 1 开始,每次到 2^cnt1 - 1, 但是小于i + // 固定正向走的次数的情况下,遍历反向所能到达位置的所有情况, + // 并计算到达位置i的最小值,就是反复比较每种情况下取最小值 + int j = 1, cnt1 = 1; + for (; j < i; j = (1 << ++cnt1) - 1) { + for (int k = 0, cnt2 = 0; k < j; k = (1 << ++cnt2) - 1) { + // 正向到达j,反向距离k,总共前进 (j-k), 和i的距离是 i-(j-k) + // 然后要计算 dp[i-(j-k)] 所需要的最小步数,这个是重叠子问题,已经计算过了 + // 直接从 dp 数组中取出即可,所以最后次数为: + // cnt1 + 1 + cnt2 + 1 + dp[i- (j-k)] + dp[i] = Math.min(dp[i], cnt1 + 1 + cnt2 + 1 + dp[i - (j - k)]); + } + } + // DP 方程: 过了i之后再回头的情况 + // 如i正好是前进j步的值,那么最少步数就是 cnt1 + // 如果比i大了,就要回头(计数1次),回头的距离是 j-i,这个是重叠子问题 + // 因为 dp[j-i] 已经计算过了,直接取值即可 + dp[i] = Math.min(dp[i], cnt1 + (i == j ? 0 : 1 + dp[j - i])); + } + + return dp[target]; + } +} \ No newline at end of file diff --git a/Week 08/id_716/LeetCode_91_716.java b/Week 08/id_716/LeetCode_91_716.java new file mode 100644 index 000000000..634f19001 --- /dev/null +++ b/Week 08/id_716/LeetCode_91_716.java @@ -0,0 +1,156 @@ +public class LeetCode_91_716 { + // 1. dp,可读性好 + public int numDecodings1(String s) { + if (s == null || s.length() == 0) + return 0; + + int n = s.length(); + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + + for (int i = 2; i <= n; i++) { + int first = Integer.parseInt(s.substring(i - 1, i)); + int second = Integer.parseInt(s.substring(i - 2, i)); + // 走一步合法 + if (first >= 1 && first <= 9) { + dp[i] += dp[i - 1]; + } + // 走两步合法 + if (second >= 10 && second <= 26) { + dp[i] += dp[i - 2]; + } + // 否则,什么也不做 + } + return dp[n]; + } + + // 2. dp,可读性差 + public int numDecodings2(String s) { + int len = s.length(); + if (len == 0 || s.charAt(0) == '0') return 0; + int[] nums = new int[len]; + nums[0] = 1; + for (int i = 1; i < len; i++) { + char ch = s.charAt(i); + char pre = s.charAt(i - 1); + nums[i] = nums[i - 1]; + if (ch == '0' && (pre > '2' || pre == '0')) return 0; + if (ch > '2' && i < len - 1 && s.charAt(i + 1) == '0') return 0; + + if (pre > '0' && ch > '0' && (i == len - 1 || s.charAt(i + 1) != '0')) { + int v = ch - '0' + (pre - '0') * 10; + if (v < 27) { + if (i > 2) { + nums[i] += nums[i - 2]; + } else { + nums[i] += 1; + } + } + } + } + return nums[len - 1]; + } + + + // 3. dp + // 此问题可以理解为爬楼梯问题,但是增加了很多限制 + // 到第i个位置的解码数可以由两种途径获得:到i-1个位置增加1个数 + 到i-2个位置增加两个数 + public int numDecodings3(String s) { + if (s.startsWith("0")) { + return 0; + } + + int n = s.length(); + // dp[i] 表示到第 i 个位置能解码方法的总数 + int[] dp = new int[n + 1]; + // init base case + dp[0] = 1; + dp[1] = 1; + + for (int i = 2; i <= n; i++) { + // 如果该位置为0,且和前一个位置组合出来不再 1~26 中,说明无解 + // e.g.: 00 30 40 50 60 70 80 90 + if (isZero(s.charAt(i - 1)) && !valid(s.substring(i - 2, i))) { + return 0; + } + // 如果该位置为0,且和前一个位置组合出来合法,e.g.: 10 20, 说明只能增加两位数(走两步) + // dp[i] 只能等于 dp[i-2] + if (isZero(s.charAt(i - 1))) { + dp[i] = dp[i - 2]; + } else { + // 如果前一个位置为0 或者 当前位置和前一个位置组合出来不再 1~26 中,说明只能走一步 + // dp[i] 只能等于 dp[i-1] + if (isZero(s.charAt(i - 2)) || !valid(s.substring(i - 2, i))) { + dp[i] = dp[i - 1]; + } else { + // 这种情况就属于正常的可以走1步和两步 + // e.g.: 23 -> 在i-1的情况下添加3 + // -> 在i-2的情况下添加23 + dp[i] = dp[i - 1] + dp[i - 2]; + } + } + } + + return dp[n]; + } + + private boolean valid(String str) { + if (str.startsWith("0")) return false; + int i = Integer.parseInt(str); + return 1 <= i && i <= 26; + } + + private boolean isZero(char c) { + return c - '0' == 0; + } + + // 4. dp, 节省内存 + public int numDecodings4(String s) { + if (s.startsWith("0")) { + return 0; + } + + int n = s.length(); + + // init base case + int prev2 = 1; + int prev1 = 1; + int num = 1; + + for (int i = 2; i <= n; i++) { + // 如果该位置为0,且和前一个位置组合出来不再 1~26 中,说明无解 + // e.g.: 00 30 40 50 60 70 80 90 + if (isZero(s.charAt(i - 1)) && !valid(s.substring(i - 2, i))) { + return 0; + } + // 如果该位置为0,且和前一个位置组合出来合法,e.g.: 10 20, 说明只能增加两位数(走两步) + // dp[i] 只能等于 dp[i-2] + if (isZero(s.charAt(i - 1))) { + num = prev2; + // dp[i] = dp[i - 2]; + prev2 = prev1; + prev1 = num; + } else { + // 如果前一个位置为0 或者 当前位置和前一个位置组合出来不再 1~26 中,说明只能走一步 + // dp[i] 只能等于 dp[i-1] + if (isZero(s.charAt(i - 2)) || !valid(s.substring(i - 2, i))) { + // dp[i] = dp[i - 1]; + num = prev1; + prev2 = prev1; + prev1 = num; + } else { + // 这种情况就属于正常的可以走1步和两步 + // e.g.: 23 -> 在i-1的情况下添加3 + // -> 在i-2的情况下添加23 + // dp[i] = dp[i - 1] + dp[i - 2]; + num = prev1 + prev2; + prev2 = prev1; + prev1 = num; + } + } + } + + return num; + } +} \ No newline at end of file diff --git a/Week 08/id_716/NOTE.md b/Week 08/id_716/NOTE.md new file mode 100755 index 000000000..56cb01ecc --- /dev/null +++ b/Week 08/id_716/NOTE.md @@ -0,0 +1,7 @@ +# NOTE + +## 总结 【716-Week 08】字符串算法总结 + +这是第八周了,最后一周。本周相对字符串相关的算法做个总结. + +![字符串算法](https://note.youdao.com/yws/api/personal/file/WEBc70d6afcc0c04631ece72ef335fb5ce8?method=download&shareKey=b261bfe6a2d3dd1c18f6b29328d07531) diff --git a/Week 08/id_716/string.jpg b/Week 08/id_716/string.jpg new file mode 100644 index 000000000..940e22c92 Binary files /dev/null and b/Week 08/id_716/string.jpg differ diff --git a/Week 08/id_721/LeetCode_300_721.java b/Week 08/id_721/LeetCode_300_721.java new file mode 100644 index 000000000..d815e082e --- /dev/null +++ b/Week 08/id_721/LeetCode_300_721.java @@ -0,0 +1,22 @@ + +public class LeetCode_300_721 { + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[] dp = new int[nums.length]; + dp[0] = 1; + int maxans = 1; + for (int i = 1; i < dp.length; i++) { + int maxval = 0; + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + maxval = Math.max(maxval, dp[j]); + } + } + dp[i] = maxval + 1; + maxans = Math.max(maxans, dp[i]); + } + return maxans; + } +} \ No newline at end of file diff --git a/Week 08/id_721/LeetCode_32_721.java b/Week 08/id_721/LeetCode_32_721.java new file mode 100644 index 000000000..d9f276975 --- /dev/null +++ b/Week 08/id_721/LeetCode_32_721.java @@ -0,0 +1,17 @@ +public class LeetCode_32_721 { + public int longestValidParentheses(String s) { + int maxans = 0; + int dp[] = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} diff --git a/Week 08/id_721/NOTE.md b/Week 08/id_721/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_721/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_726/NOTE.md b/Week 08/id_726/NOTE.md new file mode 100755 index 000000000..a6321d6e2 --- /dev/null +++ b/Week 08/id_726/NOTE.md @@ -0,0 +1,4 @@ +# NOTE + + + diff --git a/Week 08/id_731/LeetCode_32_731.txt b/Week 08/id_731/LeetCode_32_731.txt new file mode 100644 index 000000000..10cb0015d --- /dev/null +++ b/Week 08/id_731/LeetCode_32_731.txt @@ -0,0 +1,28 @@ +class Solution { +public: + int longestValidParentheses(string s) { + int size = s.size(); + // һĬΪ-1ڱǵ + vector m(size, -1); + // 1 ʼ ÿַ + for (int i = 1; i < size; i++) { + // + if (s[i] == '(') { continue; } + // ǰ Ѿɶ šΪ 0 2λ + // ҵ Ϊ -1 ַΪ ŵĵطűΪ0űΪ2 + for (int j = i - 1; j >= 0; j--) { + if (m[j] < 0 && s[j] == '(') { + m[j] = 0; m[i] = 2; break; + } + } + } + // maxΪֵ tmp¼ǰƥܺ + int max = 0, tmp = 0; + // ȡ 0,2ܺͣʱµmax-1Ǵϣtmp¿ʼ³ȡ + for (auto i : m) { + if (i >= 0) { tmp += i; } else { tmp = 0; } + max = (tmp > max) ? tmp : max; + } + return max; + } +}; \ No newline at end of file diff --git a/Week 08/id_731/LeetCode_917_731.txt b/Week 08/id_731/LeetCode_917_731.txt new file mode 100644 index 000000000..f8c7fbb3f --- /dev/null +++ b/Week 08/id_731/LeetCode_917_731.txt @@ -0,0 +1,18 @@ +class Solution { +public: + bool isword(char a){ + if(a-'a'>=0&&a-'z'<=0||a-'A'>=0&&a-'Z'<=0) return true; + else return false; + } + string reverseOnlyLetters(string S) { + string t=""; + for(int i=S.size();i>=0;i--){ + if(isword(S[i])) t+=S[i]; + } + int j=0; + for(int i=0;i