diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..0569ad13d Binary files /dev/null and b/.DS_Store differ diff --git a/Summary.md b/Summary.md new file mode 100644 index 000000000..b1ec0cedf --- /dev/null +++ b/Summary.md @@ -0,0 +1,8 @@ +与我而言 训练营是一段督促自己学习的过程 +有些东西 确实我们都学过,但是就是容易忘记 +而且学了也不一定做的了题 在训练营的时间 主要就是过遍数 +五毒神掌 往往是有些基础题 我还没有做到 有些题目 看着无比熟悉 却还是没法10min解决 +目前209道题 慢慢往后做吧 刷题这件事 对于没有上岸的人 真不是一朝一夕能完成的任务 +道阻且长 我将继续前行 +另外 我总结了一些 常见的套路题 放在另外的仓库了 +[部分面试题总结](https://github.com/mqray/leetcode) \ No newline at end of file diff --git a/Week01/.DS_Store b/Week01/.DS_Store new file mode 100644 index 000000000..4eb4a7a45 Binary files /dev/null and b/Week01/.DS_Store differ diff --git a/Week01/.idea/Week01.iml b/Week01/.idea/Week01.iml new file mode 100644 index 000000000..7c9d48f0f --- /dev/null +++ b/Week01/.idea/Week01.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Week01/.idea/leetcode/editor.xml b/Week01/.idea/leetcode/editor.xml new file mode 100644 index 000000000..274582e1b --- /dev/null +++ b/Week01/.idea/leetcode/editor.xml @@ -0,0 +1,185 @@ + + + + + + \ No newline at end of file diff --git a/Week01/.idea/misc.xml b/Week01/.idea/misc.xml new file mode 100644 index 000000000..399908725 --- /dev/null +++ b/Week01/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/Week01/.idea/modules.xml b/Week01/.idea/modules.xml new file mode 100644 index 000000000..8c762a0d7 --- /dev/null +++ b/Week01/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Week01/.idea/vcs.xml b/Week01/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/Week01/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Week01/.idea/workspace.xml b/Week01/.idea/workspace.xml new file mode 100644 index 000000000..0f8fff7a4 --- /dev/null +++ b/Week01/.idea/workspace.xml @@ -0,0 +1,823 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1592220835707 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Week02/2\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.py" "b/Week02/2\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..fdd95a9bc --- /dev/null +++ "b/Week02/2\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,65 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/15 8:40 PM + +# 给定一个二叉树,返回它的中序 遍历。 +# +# 示例: +# +# 输入: [1,null,2,3] +# 1 +# \ +# 2 +# / +# 3 +# +# 输出: [1,3,2] +# +# 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +# 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 +from typing import List +class Solution(object): + #1.递归实现 击败 67% + # def inorderTraversal(self, root): + # """ + # #中序遍历 左根右 + # :type root: TreeNode + # :rtype: List[int] + # """ + # res = [] + # if root: + # self.inorder(root, res) + # return res + # def inorder(self, root, res): + # if root.left: + # self.inorder(root.left, res) + # if root: + # res.append(root.val) + # if root.right: + # self.inorder(root.right, res) + # 击败21% + def inorderTraversal(self, root: TreeNode) -> List[int]: + if not root: return [] + stack, res = [], [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + res.append(root.val) + root = root.right + return res + + + + + # leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/2\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" "b/Week02/2\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..b021f1b3f --- /dev/null +++ "b/Week02/2\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,65 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/16 8:56 PM + +# 给定一个二叉树,返回它的 前序 遍历。 +# +# 示例: +# +# 输入: [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 + + +from typing import List +class Solution(object): + # 递归方式,击败96% + # def preorderTraversal(self, root: TreeNode) -> List[int]: + # res = [] + # if root: + # self.preorder(root, res) + # return res + # + # def preorder(self, root, res): # 前序遍历 根左右 + # if root: + # res.append(root.val) + # if root.left: + # self.preorder(root.left, res) + # if root.right: + # self.preorder(root.right, res) + #非递归方式 击败86% + def preorderTraversal(self, root: TreeNode) -> List[int]: + # 前序遍历的迭代实现 + if root is None: return [] + stack = [root] + res = [] + while stack: + cur = stack.pop() + if cur is not None: + res.append(cur.val) + # 考虑到入栈的顺序,所以先右后左 + if cur.right is not None: + stack.append(cur.right) + if cur.left is not None: + stack.append(cur.left) + return res + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/2\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" "b/Week02/2\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..d236468cb --- /dev/null +++ "b/Week02/2\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,38 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/16 9:37 PM + +class Solution(object): + # def postorderTraversal(self,root): + # res = [] + # if root is not None: + # self.postorder(root, res) + # return res + # def postorder(self,root,res): + # if root.left is not None: + # self.postorder(root.left) + # if root is not None: + # res.append(root.val) + # if root.right is not None: + # self.postorder(root.right) + def postorderTraversal(self, root): + #用两个栈实现后序遍历的非递归实现 + if root is None: + return False + stack1, stack2 = [root], [] + while stack1: # 找出后序遍历的逆序,存放在 stack2中 + node = stack1.pop() + if node.left: + stack1.append(node.left) + if node.right: + stack1.append(node.right) + stack2.append(node.val) + return stack2[::-1] + + + + + + + + diff --git "a/Week02/2\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" "b/Week02/2\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..3402a8528 --- /dev/null +++ "b/Week02/2\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,32 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/16 10:54 PM + +class Solution(object): + def levelTraversal(self,root): + # if root is None: + # return False + # stack1, stack2 = [root], [] + # while stack1: # 找出后序遍历的逆序,存放在 stack2中 + # node = stack1.pop(0)#抛出第一个元素 + # if node.left: + # stack1.append(node.left) + # if node.right: + # stack1.append(node.right) + # stack2.append(node.val) + # return stack2#这里是层序遍历就不用反转了 + + if not root: return [] + res, depth = [], 0 + self.dfs(root, res, depth) + return res + + def dfs(self, root, res, depth): + if not root: return + if len(res) == depth: res.append([]) # 每当进入到一个新的depth,就创建一个[] + res[depth].append(root.val) + if root.left: + self.dfs(root.left, res, depth + 1) + if root.right: + self.dfs(root.right, res, depth + 1) + diff --git a/Week02/NOTE.md b/Week02/NOTE.md index 50de30414..fcf849569 100644 --- a/Week02/NOTE.md +++ b/Week02/NOTE.md @@ -1 +1,760 @@ -学习笔记 \ No newline at end of file +学习笔记 + +[TOC] + +#### 有效的异位词 +1.直接对两个字符串进行排序,判断排序后的结果是否一致 +``` +return sorted(s) == sorted(t) +``` +2.根据两个字符串构建hash表,判断两个hash表是否一致 +```python +dic1, dic2 = {}, {} +for item in s: + dic1[item] = dic1.get(item, 0) + 1 +for item in t: + dic2[item] = dic2.get(item, 0) + 1 +return dic1 == dic2 + +``` +3.只需要使用一个hash表,前一次遍历增加值,后一次遍历减少值 +最后判断hash表中的值是否为0 +```python +if len(s) != len(t): return False +hashmap = {} +for substr in s: + if not hashmap.get(substr): + hashmap[substr] = 1 + else: + hashmap[substr] += 1 +for substr in t: + if hashmap.get(substr): + hashmap[substr] -= 1 + else: + return False +for value in hashmap.values(): + if value != 0: + return False +return True + +``` +4.使用python内置的count函数,统计字符出现的个数 原理与方法2一致 + +```python +if len(s) != len(t): + return False +for i in set(s): + if s.count(i) != t.count(i): + return False +return True +``` +优化 +```python + +if len(s)!=len(t):return False +tmp = set(s) +if tmp == set(t):#如果两个字符串的set相同进行深入判断 + for i in tmp: + if s.count(i) != t.count(i): return False + return True +return False +``` + +#### 异位词分组 +对于给定包含多个字符串的列表,将其按照是否异位词分组输出 +1.由于异位词都是由相同字母集组成的,可以在遍历列表时,根据其字母排序是否一致,作为异位词分组的根据 +具体的 根据字母排序是否一致,构建hash表,以字母排序作为key(当然也可以使用字母的tuple序),以原字符串作为键 +由于涉及到排序 所以时间复杂度为O(NKlogK),空间复杂度为O(NK) +```python +dic = {} +for item in strs: + # key = tuple(sorted(item))#字母的键也可以用字母排序对应的tuple + key = ''.join(sorted(item))#sorted返回的是list,不能作为dict的键 + if key in dic: + dic[key].append(item) + else: + dic[key] = [item] +# return [x for x in dic.values()]#击败94% +return [dic[x] for x in dic]#击败97% +``` +这种写法很直观,但是判断当前字符是否存在hash表中,有简简洁写法 +dict.get()获取不到时,返回[] +获取到时 + [item]可以直接在原list中拼接 +```python +dic = {} +for item in strs: + key = ''.join((sorted(item))) + dic[key] = dic.get(key, []) + [item] +return [dic[x] for x in dic] +``` +当然也可以使用defaultdict实现 +```angular2html +dic = collections.defaultdict(list) +for item in strs: + dic[tuple(sorted(item))].append(item) +return [dic[item] for item in dic] +``` + +2.根据字符串中字符出现的次数作为hash表的键 +对于每次遍历到的字符串,都需要维护一个长度为26的list,并要将其转化为tuple +时间复杂度是O(NK),空间复杂度为O(NK) +```python +dic = {} +for item in strs: + count = [0] * 26 + for char in item: + count[ord(char) - ord('a')] += 1 + # res[tuple(count)].append(item) + dic[tuple(count)] = dic.get(tuple(count),[]) + [item] +return [dic[x] for x in dic] +``` +对应的defaultdict实现如下 +```python +dic = collections.defaultdict(list) +for item in strs: + count = [0] * 26 + for char in item: + count[ord(char) - ord('a')] += 1 + dic[tuple(count)].append(item) +return [dic[x] for x in dic] +``` + +### 二叉树的深度优先遍历 +递归实现都比较简单,也比较容易理解,不赘述 + +#### 二叉树的前序遍历 根左右 + +1.递归实现 +```python +def preorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + if root: + self.preorder(root, res) + return res + +def preorder(self, root, res): # 前序遍历 根左右 + if root: + res.append(root.val) + if root.left: + self.preorder(root.left, res) + if root.right: + self.preorder(root.right, res) +``` +2.非递归实现 +前序遍历的非递归实现应该是这三中遍历方式中最简单的 +首先将根节点置于stack中,在栈不为空的前提下,遍历整个二叉树 +每次先取出stack顶元素,如果栈顶元素不为None,就可以直接存入res中 +然后判断其左右子节点是否存在,并对他们进行入栈操作 +最后返回res + +```python +def preorderTraversal(self, root: TreeNode) -> List[int]: + # 前序遍历的迭代实现 + if root is None: return [] + stack = [root] + res = [] + while stack: + cur = stack.pop() + if cur is not None: + res.append(cur.val) + # 考虑到入栈的顺序,所以先右后左 + if cur.right is not None: + stack.append(cur.right) + if cur.left is not None: + stack.append(cur.left) + return res +``` + +#### 二叉树的中序遍历 左根右 +1.递归实现 +```python +def inorderTraversal(self, root): + """ + #中序遍历 左根右 + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if root: + self.inorder(root, res) + return res +def inorder(self, root, res): + if root.left: + self.inorder(root.left, res) + if root: + res.append(root.val) + if root.right: + self.inorder(root.right, res) +``` + +2.非递归实现 +中序遍历的非递归实现就复杂一些了,因为每次并不是先将根节点的值输出,而是优先的找到树的最左子树 +所以要确保能一直往最左节点找 同时入栈 如果已经找到最左节点, +那么首先应当将这个元素出栈存入res中 其次应判断当前栈顶元素是是否有右孩子 将cur指向栈顶元素的右孩子 +```python +def inorderTraversal(self, root: TreeNode) -> List[int]: + if root is None: return [] + res, stack = [], [] + cur = root + while cur is not None or stack: + while cur is not None: # 确保了能一直往左走 + stack.append(cur) + cur = cur.left + cur = stack.pop() # 相当于等到这次的根节点 + res.append(cur.val) + cur = cur.right + return res +``` + +#### 二叉树的后序遍历 左右根 +1.递归实现 +```python +def postorderTraversal(self,root): + res = [] + if root is not None: + self.postorder(root, res) + return res +def postorder(self,root,res): + if root.left is not None: + self.postorder(root.left) + if root is not None: + res.append(root.val) + if root.right is not None: + self.postorder(root.right) +``` +2.非递归实现 +后续遍历的非递归方式应该是最难的,因为在入栈过程中还需要额外的指针标识是否已经访问过左子树的右孩子节点 +这里取巧使用两个栈,根节点不用在一个单独的栈中出入并用指针记录访问元素 + +```python +def postorderTraversal(self, root): + #用两个栈实现后序遍历的非递归实现 + if root is None: + return False + stack1,stack2 = [root], [] + while stack1: # 找出后序遍历的逆序,存放在 stack2中 + node = stack1.pop()#每次取出的都是右子树节点值,进而在stack2中就相当于存储的是 + if node.left: + stack1.append(node.left) + if node.right: + stack1.append(node.right) + stack2.append(node.val) + return stack2[::-1] +``` + +#### 二叉树的层序遍历 +写着写着,才发现二叉树的层序遍历和我上面后序遍历是真的像 +```python +class Solution(object): + def levelTraversal(self,root): + if root is None: + return False + stack1, stack2 = [root], [] + while stack1: # 找出后序遍历的逆序,存放在 stack2中 + node = stack1.pop(0)#抛出第一个元素 + if node.left: + stack1.append(node.left) + if node.right: + stack1.append(node.right) + stack2.append(node.val) + return stack2#这里是层序遍历就不用反转了 +``` + + +#### N叉树的层序遍历 +刚开始是这么写的,看起来算法逻辑没什么问题,但是这里我相当于是将cur当做一个list在做 +而实际上cur只是一个Node,哪怕它是root.children它也是个Node,所以没法将其进行迭代 +```python +def levelOrder(self, root: 'Node') -> List[List[int]]: + if root is None: return [] + quene,res = [root],[] + while quene: + cur = quene.pop() + if cur is not None: + print(type(cur))#cur is Node + #tmp = [] + #for item in cur: + # tmp.append(item.val) + #res.append(tmp) + res.append([item.val for item in cur]) + for child in cur.children: + quene.append(child) + return res +``` +改进之后,这里 实际上quene每次存储的都是每一层的所有节点, +每次都将quene所有元素记录到tmp中,将所有节点合并为list之后存入res +同时,在加入的过程中,用tmp_quene记录下一层的节点值, +在遍历完上层节点后,将下层节点赋给quene +```python +def levelOrder(self,root): + #击败55% + if root is None: return [] + quene,res = [root],[] + while quene: + #将当前层的所有元素出队列,记录其值存入res中,由于输出格式的限制,要用tmp先存放 + #并且将其孩子全部记录在下一个quene中,这样保证了上层节点全部被加入到res中,而不会发生交替现象 + tmp, tmp_quene = [], []#这个tmp_quene是为了暂存下一层的所有节点 + for node in quene: + tmp.append(node.val) + for child in node.children: + tmp_quene.append(child) + res.append(tmp) + quene = tmp_quene + return res +``` + +#### N叉树的前序遍历 +```python +class Solution: + def preorder(self, root: 'Node') -> List[int]: + #dfs + # if not root: return [] + # res = [] + # self.dfs(root,res) + # return res + # def dfs(self,root,res): + # res.append(root.val) + # for node in root.children: + # self.dfs(node,res) + #bfs 根左右 + if not root: return[] + stack, res = [root], [] + while stack: + cur = stack.pop() + res.append(cur.val) + for node in cur.children[::-1]: + stack.append(node) + return res + +``` + +#### N叉树的后序遍历 +```python +class Solution: + def postorder(self, root: 'Node') -> List[int]: + # #dfs + # if not root: return [] + # stack, res = [root],[] + # while stack: + # cur = stack.pop() + # for node in cur.children: + # stack.append(node) + # res.append(cur.val) + # return res[::-1] + #dfs + if not root: return [] + res = [] + self.dfs(root,res) + return res + def dfs(self, root, res): + for node in root.children: + self.dfs(node,res) + res.append(root.val) +``` + +#### N叉树的最大深度 +```python +class Solution: + def maxDepth(self, root: 'Node') -> int: + #DFS + # if not root: return 0 + # if not root.children: return 1 + # tmp = [self.maxDepth(node) for node in root.children] + # return max(tmp) + 1 + #bfs + if not root: return 0 + # if not root.children: return 1 + stack, depth = [root], 0 + while stack: + depth += 1 + for i in range(len(stack)): + cur = stack.pop(0) + for node in cur.children: + stack.append(node) + return depth +``` + +#### 二叉树的最大深度 +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def maxDepth(self, root: TreeNode) -> int: + #bfs + if not root: return 0 + stack, depth = [root], 0 + while stack: + for i in range(len(stack)): + cur = stack.pop(0)#注意到这里和后序遍历 层序遍历一致 都是pop(0) + if cur.left: stack.append(cur.left) + if cur.right: stack.append(cur.right) + depth += 1 + return depth + #dfs + # if not root: return 0 + # return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1 + +``` + +#### 二叉树的最小深度 +```python + +``` + + +#### 数组中最小的k个数 +1.暴力解法 对数组进行排序,返回前k个 +```python +arr.sort() +return arr[:k] +``` +2.小根堆 借助python内置的heapq实现 +```angular2html +if k == 0: + return [] +heap = [-x for x in arr[:k]] # 只用维护一个大小为k的小根堆 +heapq.heapify(heap) # 这k个元素一定满足三角顶最小的原则 +for i in range(k, len(arr)): + if -heap[0] > arr[i]: + heapq.heappop(heap) # 如果堆中的元素大于入堆元素,则将原堆顶元素出堆 + heapq.heappush(heap, -arr[i]) # 将这个元素放入小根堆中,heappop中调用了siftup调整了堆 +res = [-x for x in heap] +return res +``` +3.快排思想 +```python +def partition(self, nums, left, right): + pivot = nums[left] + while left < right: + while left < right and pivot <= nums[right]: + right -= 1 + nums[left] = nums[right] + while left < right and nums[left] <= pivot: + left += 1 + nums[right] = nums[left] + nums[left] = pivot + return left + +def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: + # 快速排序法: + size = len(arr) + if size == 0 or k > size: return + if size == 1 or size == k: + return arr + left, right = 0, size - 1 + while left <= right: # 这里其实也相当于是二分法 + pivot = self.partition(arr, left, right) # left, right, split_ind 都是原始 index + if pivot == k: # 在 split_ind 左边有 k 个元素,全部不大于 pivot + break + elif pivot > k: + right = pivot - 1 # 不-1 会陷入死循环 + else: + left = pivot + 1 # 不 +1 会陷入死循环 + return arr[:k] +``` + +#### 堆排序 +堆排序的过程主要包括 建堆以及对每一个小三角形进行堆化处理,使之满足小根堆或者大根堆的情形 +建堆是指,对于给定的元素,从下往上考虑(从最后一个非叶节点开始)使之满足nums_i>(nums_2xi+1,nums_2i+2) +然后对于每一个元素 逆序遍历时 与堆的根节点进行调换 对树进行从上往下的堆化比较过程 +对于有节点值交换的情形 进一步考量它的下一层是否符合小根堆或大根堆的条件 +建堆之后 堆顶的元素应该是最大的(大根堆),此时将它与末尾元素调换就会使得最大元素到最后位置,对现今的堆顶元素进行堆化 +这个过程就完成了对一个元素的排序,目前堆中的最大元素已经到了末尾,下一次进行调整时就无须再处理此元素 +```python + +#时间复杂度为NlogN,logN为建立大根堆/小根堆的时间复杂度, +#heapify的时间复杂度是O(logN)的因为,最坏情况下,每一层都需要判断 +#N为对已经构成的堆排序反向遍历的时间复杂度 + +def heapify(self, nums, size, i):#heapify过程就是递归考量三角是否满足条件 + max_index = i + left, right = 2*i+1,2*i+2 + if left < size and nums[left] > nums[max_index]: + max_index = left + if right < size and nums[right] > nums[max_index]: + max_index = right + if max_index != i:#存在交换的情形 + nums[i], nums[max_index] = nums[max_index], nums[i] + self.heapify(nums, size, max_index) + +def heap_sort(self,nums): + size = len(nums) + for i in range(size//2-1,-1,-1): + self.heapify(nums,size,i) + print(nums) + + for i in range(size-1,0,-1):#排序需要对整个堆进行调整 + nums[i], nums[0] = nums[0], nums[i]#交换末尾元素与堆顶元素 + self.heapify(nums,i,0)#交换之后,要确定这个堆是否合乎条件,进行堆化, + #要注意到,每次堆化时,就已经把一个元素排好了,放在最末尾了,以后就不许要再考虑这个元素了 +``` + + +#### 判断是否是丑数 +如果一个数是丑数那肯定满足这种定义num = 2^i*3^j*5^k +```python +if num == 0: return False +while num % 5 == 0: num /= 5 +while num % 3 == 0: num /= 3 +while num % 2 == 0: num /= 2 +return num == 1#击败98%,省去了迭代的过程 +``` +当然也可以简化为如下,但是就要多一部分迭代过程 +```angular2html +for item in [2,3,5]: + while num%item==0:#依次除尽2,3,5 + num = num/item +# return True if num==1 else False #击败50% +# return num==1#击败87% +``` + +#### 求第n个丑数 +动态规划的题,解法分 动态转移方程和动态转移矩阵 +后面整理一套解法 +```python +# 1、2、3、5、4、6、8、9、10 +if n==0: + return 0 +res = [1]*n +p2,p3,p5 = 0,0,0#指向三个队列的指针 +for i in range(1,n): + res[i] = min(res[p2]*2,res[p3]*3,res[p5]*5) + if res[i] == res[p2]*2: p2 = p2+1 + if res[i] == res[p3]*3: p3 = p3+1 + if res[i] == res[p5]*5: p5 = p5+1 +return res[-1] +``` + +#### 验证字符串是否是回文串 +1.翻转字符串 看是否相同 击败81% +```python +tmp = "".join(char.lower() for char in s if ch.isalnum()) +return tmp == tmp[::-1] +``` +2.双指针 击败61% +```angular2html +tmp = "".join(char.lower() for char in s if ch.isalnum()) +n = len(tmp) +left, right = 0, n - 1 +while left < right: + if tmp[left] != tmp[right]: + return False + left, right = left + 1, right - 1 +return True +``` + +#### 正则表达式匹配 +1.递归解法 +是超出时间限制的,时间复杂度是O(3^N) +```python +def isMatch(self, s: str, pattern: str) -> bool: + # 特殊情况处理 + if len(s) == 0 and len(pattern) == 0: return True + if len(s) > 0 and len(pattern) == 0: return False + # 如果pattern形如 a*####,检查这个*能匹配几次 + if len(pattern) > 1 and pattern[1] == '*':#击败80% + # s和pattern首字母相同 + if len(s) > 0 and (pattern[0] == s[0] or pattern[0] == '.'): + # s能和pattern匹配的情形 + # 1.*匹配0次,则需要递归的对s和pattern[2:]进行匹配 + # 2.*匹配1次,需要递归的对s[1:]和pattern[2:]进行匹配 + # 3.*匹配n次,需要递归的对s[1:]和pattern进行匹配 + return self.isMatch(s, pattern[2:]) or self.isMatch(s, pattern[2:]) or self.isMatch(s[1:], pattern) + else: # 如果首字母不相同,就相当于*匹配0次,继续匹配s和pettern[2:] + return self.isMatch(s, pattern[2:]) + # pattern以.开头 + if len(s) > 0 and (pattern[0] == '.' or s[0] == pattern[0]): + return self.isMatch(s[1:], pattern[1:]) + return False +``` +python中有装饰器优化迭代过程@lru_cache +所以在函数前使用装饰器即可通过 +```python +@lru_cache +def isMatch(self, s: str, pattern: str) -> bool: + pass +``` +上面的代码比较复杂,可以优化代码 +```angular2html +if not pattern: return not s#这句话真的优秀 +match_first = bool(s) and (pattern[0] == s[0] or pattern[0] == '.') +if len(pattern) > 1 and pattern[1] == '*': + return (self.isMatch(s, pattern[2:]) or match_first and self.isMatch(s[1:], pattern)) +else: + return match_first and self.isMatch(s[1:], pattern[1:]) +``` +2.动态规划 +```python +pass +``` + + +#### 只出现一次的数字 时间复杂度为O(N),空间复杂度为O(N) +除一个数外,所有元素都出现了两次,求这个只出现一次的元素 +1.两次hash表 遍历list,用hash表统计每个值出现的次数,根据出现次数返回key +```python +# 1.hash表记录出现次数,以num为key,以出现次数为value 击败42% +dic = {} +for num in nums: + dic[num] = dic.get(num,0)+1 +for key, value in dic.items(): + if value == 1: + return key +``` +2.题目要求用常数级的空间复杂度实现,则不能用hash表实现 +```python +#位运算,击败97% +# 由于每个元素都出现了两次,根据异或运算可以消去这两个元素 +#最后保留的就是带求值key和初始值1的异或 +res = 0 +for num in nums: + res ^= num +return res +``` + +#### 只出现一次的数字II +1. 数学计算 +```python +tmp = set(nums) +return (3*sum(tmp) - sum(nums))//2 +``` +给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。 +1.python解法 使用count函数 但是count函数本身的时间复杂度就是O(N)的,导致算法时间复杂度是O(N^2) +```python +for num in nums: + if nums.count(num)==1: + return num +``` +对应的优化是采用collections中的Counter模块 +```python +from collections import Counter +dic = Counter(nums) +for key in dic.keys(): + if dic[key] == 1: + return key +``` +2.hash表法 通用解 +```python +dic = {} +for num in nums: + dic[num] = dic.get(num,0)+1 +for key, value in dic.items(): + if value == 1: + return key +``` +3. 借助逻辑电路,构造这样的逻辑门状态 +1x1x1->1 1->0,这个数可以出现0次、1次、2次,需要两位来表示其状态 +构造真值表 写出逻辑表达式 并化简 +参考连接[电路逻辑通俗解](https://leetcode-cn.com/problems/single-number-ii/solution/luo-ji-dian-lu-jiao-du-xiang-xi-fen-xi-gai-ti-si-l/) +```python +x,y = 0,0 +for z in nums: + tmp = ~x&(y^z) + x = (x&~y&~z)|(~x&y&z) + y = tmp +return y +``` +根据两个表达式同构的性质,可以优化更新x的逻辑表达式 +```python +x, y = 0, 0 +for num in nums:#num means input + y = ~x & (y^num) + x = ~y & (x^num) +return y +``` + +#### 只出现一次的数字III +1.使用Counter +```python +from collections import Counter #{'num':count} +dic = Counter(nums) +return [key for key in dic if dic[key]==1 ] +``` +给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 +2.hash表法 +```python +dic,res = {}, [] +for num in nums: + dic[num] = dic.get(num,0) + 1 +for key,value in dic.items(): + if value == 1: + res.append(key) +return res +``` +3.接上一题的思路,如果对这些元素进行异或,得到的结果就是待求元素的异或值,如何从结果中分离这两个元素呢? +异或得到的结果不能直接分离出待求元素,但是我们可以根据这个异或值的第一个1将原数组分类, +由于其余元素都是出现两次的,所以对这两个数组分别求异或即可得到结果。 +```python +tmp = 0 +for num in nums: + tmp ^= num +#找到第一位不相同的数字 +count = 0 +while tmp&1 !=1: + tmp>>=1#右移1位 + count += 1 +tmp1,tmp2 = [],[] +for num in nums: + if num>>count & 1 == 0:#将该数向右移动count位 + tmp1.append(num) + else: + tmp2.append(num) +res = [] +t1,t2 = 0,0 +for num in tmp1: + t1 ^= num +res.append(t1) +for num in tmp2: + t2^= num +res.append(t2) +return res + +``` +上面的方式可以优化,其一,找第一位不同,第二,不需要用数组存放元素,直接根据此位是否为1,直接进行计算 +```python +tmp= 0 +for num in nums: + tmp ^= num +# rightmost 1-bit diff between x and y +diff = tmp & (-tmp)#这个找到第一位不相同的方式厉害 +x = 0 +for num in nums: + if num & diff:#结果大于0执行,此位为1为一组,直接计算 + x ^= num +return [x, tmp^x]#tmp是两个数的异或值,一个值已经找到了 +``` + +#### 二叉树的最大路径和 +比较自然的想法是递归,计算上层节点的最大路径时,只需要考虑左右子树最大值 +路径: 左->中->再上 + 左->中 + 左->中->右 +```python +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +#路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。 +class Solution: + def __init__(self): + self.maxpath_sum = float("-inf")#节点值可能为负值 + + def maxPathSum(self, root: TreeNode) -> int: + self.maxGain(root) + return self.maxpath_sum + + def maxGain(self,node): + if not node: return 0 + left_gain = max(self.maxGain(node.left),0)#将空值、负值过滤掉了 + right_gain = max(self.maxGain(node.right),0) + path_sum = node.val + left_gain + right_gain #左根右 + self.maxpath_sum = max(path_sum, self.maxpath_sum)#更新self.maxpath_sum,过滤负值 + return node.val + max(left_gain, right_gain)#对于更上层的元素,它的最大路径值,只可能向左或向右到达此节点,所以取最大值 +``` diff --git "a/Week02/[108]\346\234\211\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.py" "b/Week02/[108]\346\234\211\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.py" new file mode 100644 index 000000000..5408328b5 --- /dev/null +++ "b/Week02/[108]\346\234\211\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/18 11:37 AM + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + def sortedArrayToBST(self, nums: List[int]) -> TreeNode: + def buildTree(left,right): + if left>right: return None + mid = left + ((right-left)>>1) + root = TreeNode(nums[mid]) + root.left = buildTree(left,mid-1) + root.right = buildTree(mid+1,right) + return root + return buildTree(0,len(nums)-1) \ No newline at end of file diff --git "a/Week02/[109]\346\234\211\345\272\217\351\223\276\350\241\250\350\275\254\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.py" "b/Week02/[109]\346\234\211\345\272\217\351\223\276\350\241\250\350\275\254\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.py" new file mode 100644 index 000000000..01d4d1680 --- /dev/null +++ "b/Week02/[109]\346\234\211\345\272\217\351\223\276\350\241\250\350\275\254\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.py" @@ -0,0 +1,35 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/18 11:13 AM + + +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right +class Solution: + # 时间复杂度O(nlogn),空间复杂度O(logn) + def sortedListToBST(self, head: ListNode) -> TreeNode: + # 找到根节点,左右子树继续找根节点 + def findroot(left,right): + fast = slow = left + while fast != right and fast.next != right: + fast = fast.next.next + slow = slow.next + return slow + + def buildBST(left,right): + if left == right: return None + node = findroot(left,right) + root = TreeNode(node.val)#产生空间开销 + root.left = buildBST(left,node)#注意这里是分治的过程,左右子树继续找根节点, + root.right = buildBST(node.next,right) + return root + return buildBST(head,None) diff --git "a/Week02/[125]\346\257\217\346\227\245\344\270\200\351\242\2306_19_\351\252\214\350\257\201\346\230\257\345\220\246\345\233\236\346\226\207\344\270\262.py" "b/Week02/[125]\346\257\217\346\227\245\344\270\200\351\242\2306_19_\351\252\214\350\257\201\346\230\257\345\220\246\345\233\236\346\226\207\344\270\262.py" new file mode 100644 index 000000000..e54994c89 --- /dev/null +++ "b/Week02/[125]\346\257\217\346\227\245\344\270\200\351\242\2306_19_\351\252\214\350\257\201\346\230\257\345\220\246\345\233\236\346\226\207\344\270\262.py" @@ -0,0 +1,42 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/20 11:03 PM + +# 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 +# +# 说明:本题中,我们将空字符串定义为有效的回文串。 +# +# 示例 1: +# +# 输入: "A man, a plan, a canal: Panama" +# 输出: true +# +# +# 示例 2: +# +# 输入: "race a car" +# 输出: false +# +# Related Topics 双指针 字符串 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + #1. 翻转字符串 看是否相同 击败81% + # tmp = "".join(ch.lower() for ch in s if ch.isalnum()) + # return tmp == tmp[::-1] + #2.双指针 击败61% + tmp = "".join(ch.lower() for ch in s if ch.isalnum()) + n = len(tmp) + left, right = 0, n - 1 + while left < right: + if tmp[left] != tmp[right]: + return False + left, right = left + 1, right - 1 + return True +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/\345\207\272\347\216\260\351\242\221\347\216\207\346\234\200\351\253\230\347\232\204k\344\270\252\346\225\260.py" "b/Week02/\345\207\272\347\216\260\351\242\221\347\216\207\346\234\200\351\253\230\347\232\204k\344\270\252\346\225\260.py" new file mode 100644 index 000000000..1778a7128 --- /dev/null +++ "b/Week02/\345\207\272\347\216\260\351\242\221\347\216\207\346\234\200\351\253\230\347\232\204k\344\270\252\346\225\260.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/19 8:41 PM +from typing import List +class Solution: + # : List[int], k: int + def topKFrequent(self, nums) -> List[int]: + dic = {} + for num in nums: + if not dic.get(num): + dic[num] = 1 + else: + dic[num] += 1 + res = sorted(dic.items(),key=lambda item:item[1]) + return res + +nums = [1,1,1,2,2,3] +s = Solution() +res = s.topKFrequent(nums) +print(res) \ No newline at end of file diff --git "a/Week02/\345\240\206\346\216\222\345\272\217.py" "b/Week02/\345\240\206\346\216\222\345\272\217.py" new file mode 100644 index 000000000..5262551bc --- /dev/null +++ "b/Week02/\345\240\206\346\216\222\345\272\217.py" @@ -0,0 +1,88 @@ +# # -*- coding:utf-8 -*- +# # Author : Ray +# # Data : 2020/6/18 7:06 PM +# +# # !/usr/bin/env python +# # -*- coding: utf-8 -*- +# #  @Time    : 2019/12/2 18:25 +# #  @Author  : mqray +# #  @File    : 选择排序之堆排序# +# +class HeapSort(): + ''' + 时间复杂度为NlogN,logN为建立大根堆/小根堆的时间复杂度, + heapify的时间复杂度是O(logN)的因为,最坏情况下,每一层都需要判断 + N为对已经构成的堆排序反向遍历的时间复杂度 + ''' + def heapify(self, nums, size, i):#heapify过程就是递归考量三角是否满足条件 + max_index = i + left, right = 2*i+1,2*i+2 + if left < size and nums[left] > nums[max_index]: + max_index = left + if right < size and nums[right] > nums[max_index]: + max_index = right + if max_index != i:#存在交换的情形 + nums[i], nums[max_index] = nums[max_index], nums[i] + self.heapify(nums, size, max_index) + + def heap_sort(self,nums): + size = len(nums) + for i in range(size//2-1,-1,-1): + self.heapify(nums,size,i) + + for i in range(size-1,0,-1):#排序需要对整个堆进行调整 + nums[i], nums[0] = nums[0], nums[i]#交换末尾元素与堆顶元素 + self.heapify(nums,i,0)#交换之后,要确定这个堆是否合乎条件,进行堆化, + #要注意到,每次堆化时,就已经把一个元素排好了,放在最末尾了,以后就不许要再考虑这个元素了 + + +# +# def heapify(self, nums, n, i): +# ''' +# 堆化操作,将数组转化为小根堆 +# :param nums: 完全二叉树对应的数组 +# :param n: 元素个数 +# :param i: 进行堆化的数组下标 +# ''' +# #取当前节点,将其与左右孩子中较大的元素进行调换 +# if i >= n: +# return +# c1, c2 = 2 * i + 1, 2 * i + 2 +# max = i # 暂存最大数对应index +# if c1 < n and nums[c1] > nums[max]: +# max = c1 +# if c2 < n and nums[c2] > nums[max]: +# max = c2 +# print(nums) +# if max != i: +# nums[i], nums[max] = nums[max], nums[i] +# self.heapify(nums, n, max) +# +# def build_heap(self, nums, n): +# last_node = n - 1 # 堆化过程只需要考虑最后一个节点的父节点及其之前的节点 +# parent = (last_node - 1) // 2 +# for i in range(parent, -1, -1): +# self.heapify(nums, n, i) +# +# def heap_sort(self, nums, n): +# self.build_heap(nums, len(nums)) +# print('build finished') +# for i in range(n-1, -1, -1): +# nums[i], nums[0] = nums[0], nums[i] # 交换堆顶与最后一个元素,将交换后得到的最大数砍断 +# self.heapify(nums, i, 0) # 后续操作一样,只不过后续的最大索引值变小了 +# +# +nums = [4, 10, 3, 5, 1, 2] +s = HeapSort() +s.heap_sort(nums) +print(nums) + + + + + + + + + + diff --git "a/Week02/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" "b/Week02/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" new file mode 100644 index 000000000..cf7ba6f87 --- /dev/null +++ "b/Week02/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" @@ -0,0 +1,69 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/15 9:40 PM + +# 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +# +# 示例: +# +# 输入: ["eat", "tea", "tan", "ate", "nat", "bat"] +# 输出: +# [ +# ["ate","eat","tea"], +# ["nat","tan"], +# ["bat"] +# ] +# +# 说明: +# +# +# 所有输入均为小写字母。 +# 不考虑答案输出的顺序。 +# +# Related Topics 哈希表 字符串 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + #击败74% + # from collections import defaultdict + # ans = defaultdict(list) + # #根据异位词分组 {('a','b','c'):['abc']} + # for s in strs: + # ans[tuple(sorted(s))].append(s) + # return list(ans.values()) + + #击败36% + # ans = collections.defaultdict(list) + # for s in strs: + # count = [0] * 26 + # for c in s: + # count[ord(c) - ord('a')] += 1 + # ans[tuple(count)].append(s) + # return list(ans.values()) + + #击败50% + + # d = {} + # for w in sorted(strs): + # key = tuple(sorted(w)) + # d[key] = d.get(key, []) + [w] + # return list(d.values()) + + dic = {} + for string in strs: + s = ''.join(sorted(string)) + if s in dic: + dic[s].append(string) + else: + dic[s] = [string] + # return [x for x in dic.values()]#击败94% + return [dic[x] for x in dic]#击败97% + + +# leetcode submit region end(Prohibit modification and deletion) \ No newline at end of file diff --git "a/Week02/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.pdf" "b/Week02/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.pdf" new file mode 100644 index 000000000..b1fde4b34 Binary files /dev/null and "b/Week02/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.pdf" differ diff --git "a/Week02/\346\234\211\346\225\210\345\255\227\346\257\215\347\232\204\345\274\202\344\275\215\350\257\215.py" "b/Week02/\346\234\211\346\225\210\345\255\227\346\257\215\347\232\204\345\274\202\344\275\215\350\257\215.py" new file mode 100644 index 000000000..53cbb817d --- /dev/null +++ "b/Week02/\346\234\211\346\225\210\345\255\227\346\257\215\347\232\204\345\274\202\344\275\215\350\257\215.py" @@ -0,0 +1,84 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/15 7:42 PM + +# 给定两个字符串 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, t): + """ + 异位词的概念是 字符串中出现的字母都是一样的且对应字母其次数也一致 + :type s: str + :type t: str + :rtype: bool + """ + #1.对这两个字符串进行排序,如果排序结果一致,说明是异位词 + #击败22% + # return sorted(s) == sorted(t) + #2.遍历两个字符串,检查生成的hash表是否一致 + #击败32% + # dic1, dic2 = {}, {} + # for item in s: + # dic1[item] = dic1.get(item, 0) + 1 + # for item in t: + # dic2[item] = dic2.get(item, 0) + 1 + # return dic1 == dic2 + #2.只需使用一个hash表 hash表记录每个字母出现的次数 + #击败58% + #hash表的key也可以使用ord(item)-ord('a') + # if len(s) != len(t): return False + # hashmap = {} + # for substr in s: + # if not hashmap.get(substr): + # hashmap[substr] = 1 + # else: + # hashmap[substr] += 1 + # for substr in t: + # if hashmap.get(substr): + # hashmap[substr] -= 1 + # else: + # return False + # for value in hashmap.values(): + # if value != 0: + # return False + # return True + #4.python中使用count函数统计出现的次数 + #击败90% + # if len(s) != len(t): + # return False + # for i in set(s): + # if s.count(i) != t.count(i): + # return False + # return True + + #击败95% + if len(s) != len(t): return False + tmp = set(s) + if tmp == set(t):#如果两个字符串的set相同进行深入判断 + for i in s: + if s.count(i) != t.count(i): return False + return True + return False + # + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_16_N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_16_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..924a129bd --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_16_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,70 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/16 11:31 PM + +# 给定一个二叉树,返回它的 前序 遍历。 +# +# 示例: +# +# 输入: [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): + #击败86% + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + # 击败95% + if not root: return [] + res = [] + res.append(root.val) + for child in root.children: + res += self.preorderTraversal(child) + return res + + #击败86% + # res = [] + # if root: + # self.Npreorder(root, res) + # return res + # def Npreorder(self, root, res): + # if root is None: + # return + # res.append(root.val)#先序遍历 先将值存入res,再依次访问子节点 + # for child in root.children: + # self.Npreorder(child, res) + + #击败69% + def traversal(self,root): + if not root: return [] + stack, res = [root], [] + while stack: + node = stack.pop() + res.append(node.val) + for item in node.children[::-1]: + stack.append(item) + return res + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_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..3150f2cba --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_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,46 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/16 9:30 PM + +# 给定一个 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=None, children=None): + self.val = val + self.children = children +""" + + +class Solution(object): + def postorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + # 击败48% + if not root: return [] + res = [] + for child in root.children: + res += self.postorder(child) + res.append(root.val) + return res + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..5edb59310 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_17_N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/17 10:27 PM + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + +class Solution: + # def levelOrder(self, root: 'Node') -> List[List[int]]: + def levelOrder(self,root): + #击败55% + if root is None: return [] + quene,res = [root],[] + while quene: + #将当前层的所有元素出队列,记录其值存入res中,由于输出格式的限制,要用tmp先存放 + #并且将其孩子全部记录在下一个quene中,这样保证了上层节点全部被加入到res中,而不会发生交替现象 + tmp, tmp_quene = [], []#这个tmp_quene是为了暂存下一层的所有节点 + for node in quene: + tmp.append(node.val) + for child in node.children: + tmp_quene.append(child) + res.append(tmp) + quene = tmp_quene + return res \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_18_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_18_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" new file mode 100644 index 000000000..113feeb8d --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_18_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" @@ -0,0 +1,91 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/17 11:06 PM + +from typing import List +import heapq +# class Solution: +# def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: +# #暴力破解 击败64% +# arr.sort() +# return arr[:k] +# # +# # #击败59% +# if k == 0: +# return [] +# heap = [-x for x in arr[:k]] # 只用维护一个大小为k的小根堆 +# heapq.heapify(heap) # 这k个元素一定满足三角顶最小的原则 +# for i in range(k, len(arr)): +# if -heap[0] > arr[i]: +# heapq.heappop(heap) # 如果堆中的元素大于入堆元素,则将原堆顶元素出堆 +# heapq.heappush(heap, -arr[i]) # 将这个元素放入小根堆中,heappop中调用了siftup调整了堆 +# res = [-x for x in heap] +# return res + +class Solution: + def partition(self, nums, left, right): + pivot = nums[left] + while left < right: + while left < right and pivot <= nums[right]: + right -= 1 + nums[left] = nums[right] + while left < right and nums[left] <= pivot: + left += 1 + nums[right] = nums[left] + nums[left] = pivot + return left + + def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: + # 快速排序法: + size = len(arr) + if size == 0 or k > size: return + if size == 1 or size == k: + return arr + left, right = 0, size - 1 + while left <= right: # 这里其实也相当于是二分法 + pivot = self.partition(arr, left, right) # left, right, split_ind 都是原始 index + if pivot == k: # 在 split_ind 左边有 k 个元素,全部不大于 pivot + break + elif pivot > k:#如果左边还有大于k个数,继续在左边找 + right = pivot - 1 # 不-1 会陷入死循环 + else: + left = pivot + 1 # 不 +1 会陷入死循环 + return arr[:k] + + + +import heapq + +class SolutionII: + #如果 是要求最小的k个数,那么应该是维护一个大小为k的大根堆,如果元素值小于堆顶元素, + # 将此元素放到数组末尾,进行heapify,那么每次就相当于将原始数组中的大数全部推出,只留下最后k个,那他就是最小值 + # 判断当前元素是否小于堆顶元素,如果小,就入堆 + + # 同理 如果要求最大的k个数,那么就需要维护小根堆,一致删除较小的元素,直到元素组只剩k个值,就是最大的k个数 + # 但是由于python中的heapq是小根堆,所以我们在维护堆之前先将符号调换一下 + # 小根堆 如果当前值大于堆顶元素 才能入堆 + def getLeastNumbers(self, nums, k): + if k == 0: return [] + my_heap = [-x for x in nums[:k]]#维护大小为k的小顶堆 + heapq.heapify(my_heap) + for i in range(k,len(nums)): + if -nums[i] > my_heap[0]:#小根堆最后留下的是最大的k个值,所以只有大于堆顶才能进 + heapq.heappop(my_heap) + heapq.heappush(my_heap,-nums[i]) + res = [-x for x in my_heap] + return res + + # heapq.heapify(my_heap)#维护大小为k的小根堆 + # for i in range(k,len(nums)): + # if nums[i] < my_heap[-1]:#如果比栈顶元素小,将当前栈顶元素 + + + + + + +s = SolutionII() +# nums = [1, 4, 2, 5, 10, 3, -1] +nums = [0,0,1,2,4,2,2,3,1,4] +res = s.getLeastNumbers(nums,8) +print(res) \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\345\210\244\346\226\255\346\230\257\345\220\246\344\270\221\346\225\260.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\345\210\244\346\226\255\346\230\257\345\220\246\344\270\221\346\225\260.py" new file mode 100644 index 000000000..5196535f3 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\345\210\244\346\226\255\346\230\257\345\220\246\344\270\221\346\225\260.py" @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/19 8:07 PM + +class Solution: + def isUgly(self, num: int) -> bool: + #如果一个数是丑数那肯定满足这种定义num = 2^i*3^j*5^k + # for item in [2,3,5]: + # while num%item==0:#依次除尽2,3,5 + # num = num/item + # # return True if num==1 else False #击败50% + # return num==1#击败87% + if num == 0: return False + while num % 5 == 0: num /= 5 + while num % 3 == 0: num /= 3 + while num % 2 == 0: num /= 2 + return num == 1#击败98%,省去了迭代的过程 + + +s = Solution() +res = s.isUgly(7) +print(res) \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\346\261\202\347\254\254n\344\270\252\344\270\221\346\225\260.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\346\261\202\347\254\254n\344\270\252\344\270\221\346\225\260.py" new file mode 100644 index 000000000..2890e1325 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_19_\346\261\202\347\254\254n\344\270\252\344\270\221\346\225\260.py" @@ -0,0 +1,17 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/19 12:33 AM + +class Solution: + def nthUglyNumber(self, n: int) -> int: + # 1、2、3、5、4、6、8、9、10 + if n==0: + return 0 + res = [1]*n + p2,p3,p5 = 0,0,0#指向三个队列的指针 + for i in range(1,n): + res[i] = min(res[p2]*2,res[p3]*3,res[p5]*5) + if res[i] == res[p2]*2: p2 = p2+1 + if res[i] == res[p3]*3: p3 = p3+1 + if res[i] == res[p5]*5: p5 = p5+1 + return res[-1] \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_20_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_20_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" new file mode 100644 index 000000000..b047e2380 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_20_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" @@ -0,0 +1,98 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/20 10:11 PM + +# 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。 +# +# '.' 匹配任意单个字符 +# '*' 匹配零个或多个前面的那一个元素 +# +# +# 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 +# +# 说明: +# +# +# s 可能为空,且只包含从 a-z 的小写字母。 +# p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 +# +# +# 示例 1: +# +# 输入: +# s = "aa" +# p = "a" +# 输出: false +# 解释: "a" 无法匹配 "aa" 整个字符串。 +# +# +# 示例 2: +# +# 输入: +# s = "aa" +# p = "a*" +# 输出: true +# 解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。 +# +# +# 示例 3: +# +# 输入: +# s = "ab" +# p = ".*" +# 输出: true +# 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。 +# +# +# 示例 4: +# +# 输入: +# s = "aab" +# p = "c*a*b" +# 输出: true +# 解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。 +# +# +# 示例 5: +# +# 输入: +# s = "mississippi" +# p = "mis*is*p*." +# 输出: false +# Related Topics 字符串 动态规划 回溯算法 + +from functools import lru_cache +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + + #1.将复杂问题进行拆解 递归 但是明显是超出时间限制的,时间复杂度是O(3^N) + # s="aaaaaaaaaaaaab" + # pattern="a*a*a*a*a*a*a*a*a*a*c" 但是python中可以使用@lru_cache装饰器优化递归过程 + @lru_cache + def isMatch(self, s: str, pattern: str) -> bool: + # # 特殊情况处理 + # if len(s) == 0 and len(pattern) == 0: return True + # if len(s) > 0 and len(pattern) == 0: return False + # # 如果pattern形如 a*####,检查这个*能匹配几次 + # if len(pattern) > 1 and pattern[1] == '*':#击败80% + # # s和pattern首字母相同 + # if len(s) > 0 and (pattern[0] == s[0] or pattern[0] == '.'): + # # s能和pattern匹配的情形 + # # 1.*匹配0次,则需要递归的对s和pattern[2:]进行匹配 + # # 2.*匹配1次,需要递归的对s[1:]和pattern[2:]进行匹配 + # # 3.*匹配n次,需要递归的对s[1:]和pattern进行匹配 + # return self.isMatch(s, pattern[2:]) or self.isMatch(s, pattern[2:]) or self.isMatch(s[1:], pattern) + # else: # 如果首字母不相同,就相当于*匹配0次,继续匹配s和pettern[2:] + # return self.isMatch(s, pattern[2:]) + # # pattern以.开头 + # if len(s) > 0 and (pattern[0] == '.' or s[0] == pattern[0]): + # return self.isMatch(s[1:], pattern[1:]) + # return False + #击败86% + if not pattern: return not s + match_first = bool(s) and (pattern[0] == s[0] or pattern[0] == '.') + if len(pattern) > 1 and pattern[1] == '*': + return (self.isMatch(s, pattern[2:]) or match_first and self.isMatch(s[1:], pattern)) + else: + return match_first and self.isMatch(s[1:], pattern[1:]) +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.py" new file mode 100644 index 000000000..39f8ec6a0 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.py" @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/21 4:23 PM + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +#路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。 +class Solution: + def __init__(self): + self.maxpath_sum = float("-inf") + + def maxPathSum(self, root: TreeNode) -> int: + self.maxGain(root) + return self.maxpath_sum + + def maxGain(self,node): + if not node: return 0 + left_gain = max(self.maxGain(node.left),0)#将空值、负值过滤掉了 + right_gain = max(self.maxGain(node.right),0) + path_sum = node.val + left_gain + right_gain #左根右 + self.maxpath_sum = max(path_sum, self.maxpath_sum)#更新self.maxpath_sum,过滤负值 + return node.val + max(left_gain, right_gain)#返回此节点的最大贡献值,方便上层节点计算 + + + diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" new file mode 100644 index 000000000..897e8b817 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/21 10:24 AM + +from typing import List +class Solution: + def singleNumber(self, nums: List[int]) -> int: + # # 1.hash表记录出现次数,以num为key,以出现次数为value 击败42% + # dic = {} + # for num in nums: + # dic[num] = dic.get(num,0)+1 + # for key, value in dic.items(): + # if value == 1: + # return key + #位运算,击败97% + # 由于每个元素都出现了两次,根据异或运算可以消去这两个元素 + res = 0 + for num in nums: + res ^= num + return res + + +s = Solution() +res = s.singleNumber([4,1,2,1,2]) +print(res) \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227II.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227II.py" new file mode 100644 index 000000000..3a40d34c2 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227II.py" @@ -0,0 +1,23 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/21 11:31 AM +from typing import List +class Solution: + def singleNumber(self, nums: List[int]) -> int: + # dic = {}#击败87% + # for num in nums: + # dic[num] = dic.get(num,0)+1 + # for key, value in dic.items(): + # if value == 1: + # return key + # x, y = 0, 0#击败74% + # for z in nums:#num means input + # y = ~x & (y^z) + # x = ~y & (x^z) + # return y + x,y = 0,0#击败57% + for z in nums: + tmp = ~x&(y^z) + x = (x&~y&~z)|(~x&y&z) + y = tmp + return y \ No newline at end of file diff --git "a/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227III.py" "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227III.py" new file mode 100644 index 000000000..d98f06879 --- /dev/null +++ "b/Week02/\346\257\217\346\227\245\344\270\200\351\242\2306_21_\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227III.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/21 11:40 AM +from typing import List +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + #击败64% + # dic,res = {}, [] + # for num in nums: + # dic[num] = dic.get(num,0) + 1 + # for key,value in dic.items(): + # if value == 1: + # res.append(key) + # return res + tmp = 0 + for num in nums: + tmp ^= num + # rightmost 1-bit diff between x and y + diff = tmp & (-tmp) # 这个找到第一位不相同的方式厉害 + x = 0 + for num in nums: + if num & diff: # 结果大于0执行,此位为1为一组,直接计算 + x ^= num + return [x, tmp ^ x] # tmp是两个数的异或值,一个值已经找到了 + diff --git a/Week03/.idea/Week03.iml b/Week03/.idea/Week03.iml new file mode 100644 index 000000000..7c9d48f0f --- /dev/null +++ b/Week03/.idea/Week03.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Week03/.idea/leetcode/editor.xml b/Week03/.idea/leetcode/editor.xml new file mode 100644 index 000000000..20fc4c471 --- /dev/null +++ b/Week03/.idea/leetcode/editor.xml @@ -0,0 +1,81 @@ + + + + + + \ No newline at end of file diff --git a/Week03/.idea/misc.xml b/Week03/.idea/misc.xml new file mode 100644 index 000000000..399908725 --- /dev/null +++ b/Week03/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/Week03/.idea/modules.xml b/Week03/.idea/modules.xml new file mode 100644 index 000000000..1191ab715 --- /dev/null +++ b/Week03/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Week03/.idea/vcs.xml b/Week03/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/Week03/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Week03/.idea/workspace.xml b/Week03/.idea/workspace.xml new file mode 100644 index 000000000..b8da57564 --- /dev/null +++ b/Week03/.idea/workspace.xml @@ -0,0 +1,968 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1593440885794 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 62 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 61 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 63 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 66 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 67 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 68 + + + file://$PROJECT_DIR$/每日一题7_1_单词接龙.py + 69 + + + file://$PROJECT_DIR$/每日一题7_2_买卖股票的最佳时机.py + 20 + + + file://$PROJECT_DIR$/每日一题7_2_买卖股票的最佳时机.py + 21 + + + file://$PROJECT_DIR$/每日一题7_2_买卖股票的最佳时机.py + 22 + + + file://$PROJECT_DIR$/每日一题7_2_买卖股票的最佳时机.py + 29 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 4 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 5 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 7 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 8 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 9 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 11 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 10 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 14 + + + file://$PROJECT_DIR$/每日一题7_2_零钱兑换.py + 32 + + + file://$PROJECT_DIR$/每日一题7_6_不同路径II.py + 15 + + + file://$PROJECT_DIR$/每日一题7_6_不同路径II.py + 16 + + + file://$PROJECT_DIR$/每日一题7_6_不同路径II.py + 17 + + + file://$PROJECT_DIR$/每日一题7_6_不同路径II.py + 18 + + + file://$PROJECT_DIR$/每日一题7_6_不同路径II.py + 28 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Week04/NOTE.md b/Week04/NOTE.md index 50de30414..907cacf8c 100644 --- a/Week04/NOTE.md +++ b/Week04/NOTE.md @@ -1 +1,251 @@ -学习笔记 \ No newline at end of file +学习笔记 + +#### 二叉树的层序遍历 +1.BFS 与一般的层序遍历相比 只是要求同一层的元素放在同一个[]中 需要对之前的模板进行改造 +```python +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + # 由于题目限制了最后打印输出格式每一层节点放在[]中,所以需要对普通的层序遍历进行调整 + # 在while quene循环中加入一个cur_layer记录当前层的节点以确保每次都能将该层的元素加入 + def levelOrder(self, root: TreeNode) -> List[List[int]]: + if not root: return [] + quene,res = [root],[] + while quene: + cur_layer = [] + for _ in range(len(quene)):#确保将每一层的元素都加入cur_layer + cur = quene.pop(0) + if cur.left: quene.append(cur.left) + if cur.right: quene.append(cur.right) + cur_layer.append(cur.val) + res.append(cur_layer) + return res +``` +2.DFS既然能够遍历整树的所有节点,如果需要按模板输出,需要在递归过程中记录当前树的深度,然后将该节点加入到res的对应部分 +```python +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + #如果用DFS做,当然也可以得到想要的结果,只是要注意的是,遍历过程中,需要记录该节点的深度 + # 以便将它加入到res对应下标的位置 + res = [] + self.dfs(root, 0, res) + return res + + def dfs(self, root, level, res): + # recursion terminator + if not root: return + #process current level + if len(res) == level: res.append([])#在开始遍历时,生成一个[]位置,4接收参数 + res[level].append(root.val) + #drill down + if root.left: self.dfs(root.left, level + 1, res) + if root.right: self.dfs(root.right, level + 1, res) +``` + +#### 最小基因变化 +1.BFS +```python +# 1.BFS 所谓BFS就是类似二叉树BFS我们使用deque的非递归实现 +import collections +def isChangeOnce(cur,next): + changes = 0 + for i in range(len(next)): + if next[i]==cur[i]: + changes = changes + 1 + return changes == 1#但是可以不必要全部遍历完,大于1的时候就可以直接返回 + +class Solution(object): + def minMutation(self, start, end, bank): + """ + :type start: str + :type end: str + :type bank: List[str] + :rtype: int + """ + quene = collections.deque() + quene.append((start,start,0))#cur,pre,steps + while quene: + cur,pre,steps = quene.popleft() + if cur == end: + return steps + for gene in bank: + if isChangeOnce(cur,gene) and gene != pre: + quene.append((gene,cur,steps+1)) + return -1 +``` + +2.DFS 回溯法 +从bank中挑选出于cur只有一个bit差异且之前没有访问过的元素,先将其加入visited,继续判断此时的cur是否与target相同 +```python +rom typing import List +class SolutionI: + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + visited = set() + self.res = float('inf') + if end not in bank: return -1 + def dfs(cur, step): + # recursion terminator + if cur == end: + self.res = min(self.res, step) + return + #current level process + for next in bank: + if next not in visited and isChangeOnce(cur, next): + visited.add(next) + # drill down + dfs(next, step+1) + # reverse state + visited.remove(next) + visited.add(start) + dfs(start, 0) + return self.res if self.res < float('inf') else -1 +``` + +#### 每个树行的最大值 +```python +class Solution(object): + def largestValues(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + # 1. 思想比较简单 在二叉树的层序遍历的基础上 对每一列表求最大值后返回 + # 2. 当然也可以在遍历过程中记录每一层的最大值 + if not root: return [] + quene, res = [root], [] + while quene: + cur_layer = [] + # layer_max = float('-inf') + for _ in range(len(quene)): + cur = quene.pop(0) + if cur.left: quene.append(cur.left) + if cur.right: quene.append(cur.right) + # layer_max = max(layer_max, cur.val) + cur_layer.append(cur.val) + res.append(cur_layer) + # res.append(layer_max) + return [max(item) for item in res] + # return res +``` +其中,如果以后再遇到这样的判别 +`if not root: return []`后面接`while`循环,就直接使用如下形式 +```python +class Solution: + def largestValues(self, root: TreeNode) -> List[int]: + # if not root: return [] + quene, res = [root], [] + while any(quene): + # cur_layer = [] + layer_max = float('-inf') + for _ in range(len(quene)): + cur = quene.pop(0) + if cur.left: quene.append(cur.left) + if cur.right: quene.append(cur.right) + layer_max = max(layer_max,cur.val) + # cur_layer.append(cur.val) + # res.append(cur_layer) + res.append(layer_max) + # return [max(item) for item in res] + return res +``` +最后给一段极简python代码 +```python +class Solution: + def largestValues(self, root: TreeNode) -> List[int]: + maxes = [] + row = [root] + while any(row): + maxes.append(max(node.val for node in row)) + row = [kid for node in row for kid in (node.left, node.right) if kid] + return maxes +``` + + +#### 两个栈实现队列 +主要是要考虑从队首删除元素的情形 +```python +class CQueue(object): + def __init__(self): + self.in_stack, self.out_stack = [],[] + + def appendTail(self, value): + self.in_stack.append(value) + + def deleteHead(self): + """ + 删除的时候有几点要考虑, + 1.如果out_stack中有元素,说明是上一次删除没有删除完的,最优先删除 + 2.如果out_stack中元素全部删除后,in_stack中没有元素,则无法删除返回-1 + 3.如果in_stack中有元素,将其全部转移到out_stack中,返回pop()值 + """ + if self.out_stack: return self.out_stack.pop() + if not self.in_stack: return -1 + while self.in_stack: + self.out_stack.append(self.in_stack.pop()) + return self.out_stack.pop() +``` + + +#### 单词接龙 + +#### 岛屿数量 + +#### 岛屿最大面积 + +#### 岛屿周长 + +#### 买卖股票的最佳时机I + +#### 买卖股票的最佳时机II + +#### 有序矩阵中的第K小的值 +1.暴力法 时间复杂度O(N^2),空间复杂度O(N^2) +```python +def kthSmallestI(self, matrix: List[List[int]], k: int) -> int: + # 1.暴力法 时间复杂度O(N^2) 空间复杂度为O(N^2) + tmp = [x for item in matrix for x in item] + tmp.sort() + return tmp[-(len(tmp) - k + 1)] +``` +2.借助小根堆 时间复杂度O(klogN),空间复杂度O(N) +```python +def kthSmallest(self, matrix: List[List[int]], k: int) -> int: + size = len(matrix) + pq = [(matrix[i][0],i,0) for i in range(size)]# 维护一个最小元素队列 (i,0) means location + heapq.heapify(pq) + for i in range(k-1):#第k次pop的元素直接返回 + num, row, col = heapq.heappop(pq) + if col != size - 1: + heapq.heappush(pq,(matrix[row][col+1],row,col+1))#如果某行没有全部删除,将当前值右边的元素如堆 + # now time = k + return heapq.heappop(pq)[0] +``` +3.双指针 时间复杂度O(Nlog(max-min)),空间复杂度O(1) +```python +def kthSmallestII(self, matrix: List[List[int]], k: int) -> int: + #双指针 时间复杂度O(Nlog(max-min)) + # n次双指针,每次判断矩阵左侧小于num的数的个数,大于k个则右指针已动到mid + rows, cols = len(matrix), len(matrix[0]) + def check(num): + i, j, count = rows - 1, 0, 0 + while i >= 0 and j < cols: + if matrix[i][j] <= num: + count = count + i + 1 # 一竖行都小于 + j = j + 1 + else: # 如果大于num,这一层没有比num小的了 + i = i - 1 + return count >= k + + left_up, right_down = matrix[0][0], matrix[rows - 1][cols - 1] + while left_up < right_down: + mid = (left_up + right_down) // 2 + if check(mid): + right_down = mid # 左边有大于k个数,那么第k小的数肯定在左边 + else: # 左边没有k个数 + left_up = mid + 1 + return left_up +``` diff --git "a/Week04/[367]\346\257\217\346\227\245\344\270\200\351\242\2307_5_\346\234\211\346\225\210\347\232\204\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.py" "b/Week04/[367]\346\257\217\346\227\245\344\270\200\351\242\2307_5_\346\234\211\346\225\210\347\232\204\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.py" new file mode 100644 index 000000000..9459cba12 --- /dev/null +++ "b/Week04/[367]\346\257\217\346\227\245\344\270\200\351\242\2307_5_\346\234\211\346\225\210\347\232\204\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/5 10:44 PM + +class Solution: + def isPerfectSquare(self, num: int) -> bool: + # 二分法 + # left, right, res = 0, num//2+1, 0 + # while left <= right: + # mid = (left+right)//2 + # if mid*mid < num: + # left = mid + 1 + # elif mid*mid >num: + # right = mid - 1 + # else: + # res = mid + # break + # return res**2 == num + # 拟牛顿法 + if num < 2: return True + x = num // 2 + while x * x > num: + x = (x + num // x) // 2 + return x * x == num + diff --git "a/Week04/[69]\346\257\217\346\227\245\344\270\200\351\242\2307_5_x\347\232\204\345\271\263\346\226\271\346\240\271.py" "b/Week04/[69]\346\257\217\346\227\245\344\270\200\351\242\2307_5_x\347\232\204\345\271\263\346\226\271\346\240\271.py" new file mode 100644 index 000000000..208f0d783 --- /dev/null +++ "b/Week04/[69]\346\257\217\346\227\245\344\270\200\351\242\2307_5_x\347\232\204\345\271\263\346\226\271\346\240\271.py" @@ -0,0 +1,28 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/5 10:27 PM + +class Solution: + def mySqrt(self, x: int) -> int: + #1.换底公式求解 + # if x == 0: return 0 + # res = int(math.exp(0.5 * math.log(x))) + # return res + 1 if (res + 1) ** 2 <= x else res + #2.二分法 + # left, right, = 0, x + # while left <= right: + # mid = (left + right) // 2 + # if mid ** 2 <= x: # x的整数部分的平方<=x + # res, left = mid, mid + 1 + # else: + # right = mid - 1 + # return res + #3.牛顿法迭代求解 + if x == 0: return 0 + x0 = A = float(x) + while True: + x1 = (x0 + A/x0)//2 + if abs(x1-x0)<1e-6: + break + x0 = x1 + return int(x0) \ No newline at end of file diff --git "a/Week04/\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252.py" "b/Week04/\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252.py" new file mode 100644 index 000000000..547b71514 --- /dev/null +++ "b/Week04/\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252.py" @@ -0,0 +1,66 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/30 3:08 AM + +from typing import List +class Solution: + def searchRangeI(self, nums: List[int], target: int) -> List[int]: + if not nums: return [-1, -1] + def search(left, right, bound): + while left <= right: + mid = left + ((right - left) >> 1) + if nums[mid] == target: + if bound == 0: + if mid == bound or nums[mid - 1] != target: + return mid + else: right = mid - 1 + else: + if mid == bound or nums[mid+1] != target: + return mid + else: left = mid + 1 + elif nums[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return -1 + + size = len(nums) + p1 = search(0, size - 1, 0) + p2 = search(0, size - 1, size - 1) + return [p1,p2] + def searchRange(self, nums: List[int], target: int) -> List[int]: + # 1.要考虑到如果该数字不存在的情形 + if not nums: return [-1, -1] + def search_left(left,right): + while left <= right: + mid = left + ((right - left) >> 1) + if nums[mid] == target: + if mid == 0 or nums[mid-1] != target: + return mid + else: right = mid - 1 + elif nums[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return -1 + def search_right(left,right): + while left <= right: + mid = left + ((right - left) >> 1) + if nums[mid] == target: + if mid == size-1 or nums[mid+1] != target: + return mid + else: left = mid + 1 + elif nums[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return -1 + size = len(nums) + p1 = search_left(0,size-1) + p2 = search_right(0,size-1) + return [p1,p2] +s = Solution() +nums = [5,7,7,8,8,10] +# nums = [1] +res = s.searchRangeI(nums,8) +print(res) \ No newline at end of file diff --git "a/Week04/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" "b/Week04/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" new file mode 100644 index 000000000..f86509328 --- /dev/null +++ "b/Week04/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" @@ -0,0 +1,23 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/1 10:06 PM + +from typing import List +class Solution: + def findLength(self, A: List[int], B: List[int]) -> int: + res = 0 + for i in range(len(A)): + for j in range(len(B)): + k = 0 + while i+k < len(a) and j+k < len(B) and A[i+k] == B[j+k]: + k = k + 1 + res = max(res,k) + return res + +s = Solution() +a = [1,2,3,2,1] +b = [3,2,1,4,7] +res = s.findLength(a,b) +print(res) + + diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_29_\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_29_\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 000000000..b776bf03a --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_29_\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/29 10:29 PM +from typing import List +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + # 由于题目限制了最后打印输出格式每一层节点放在[]中,所以需要对普通的层序遍历进行调整 + # 在while quene循环中加入一个cur_layer记录当前层的节点以确保每次都能将该层的元素加入 + def levelOrder(self, root: TreeNode) -> List[List[int]]: + # if not root: return [] + # quene,res = [root],[] + # while quene: + # cur_layer = [] + # for _ in range(len(quene)): + # cur = quene.pop(0) + # if cur.left: quene.append(cur.left) + # if cur.right: quene.append(cur.right) + # cur_layer.append(cur.val) + # res.append(cur_layer) + # return res + + #如果用DFS做,当然也可以得到想要的结果,只是要注意的是,遍历过程中,需要记录该节点的深度 + # 以便将它加入到res对应下标的位置 + res = [] + self.dfs(root, 0, res) + return res + + def dfs(self, root, level, res): + if not root: return + if len(res) == level: res.append([])#在开始遍历时,生成一个[]位置,4接收参数 + res[level].append(root.val) + if root.left: self.dfs(root.left, level + 1, res) + if root.right: self.dfs(root.right, level + 1, res) \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.py" new file mode 100644 index 000000000..c1aeb9eb4 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.py" @@ -0,0 +1,55 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/30 1:06 AM + +# 您需要在二叉树的每一行中找到最大的值。 +# +# 示例: +# +# +# 输入: +# +# 1 +# / \ +# 3 2 +# / \ \ +# 5 3 9 +# +# 输出: [1, 3, 9] +# +# 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 largestValues(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + # 1. 思想比较简单 在二叉树的层序遍历的基础上 对每一列表求最大值后返回 + # 2. 当然也可以在遍历过程中记录每一层的最大值 + if not root: return [] + quene, res = [root], [] + while quene: + cur_layer = [] + # layer_max = float('-inf') + for _ in range(len(quene)): + cur = quene.pop(0) + if cur.left: quene.append(cur.left) + if cur.right: quene.append(cur.right) + # layer_max = max(layer_max, cur.val) + cur_layer.append(cur.val) + res.append(cur_layer) + # res.append(layer_max) + return [max(item) for item in res] + # return res + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.py" new file mode 100644 index 000000000..4301aafbc --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.py" @@ -0,0 +1,130 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/30 12:19 AM + +# 一条基因序列由一个带有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 +# +# + + +# leetcode submit region begin(Prohibit modification and deletion) + + +# 1.BFS 所谓BFS就是类似二叉树BFS我们使用deque的非递归实现 +import collections +def isChangeOnce(cur,next):#时间复杂度是O(K),K是bank中字符的长度 + changes = 0 + for i in range(len(next)): + if next[i]==cur[i]: + changes = changes + 1 + return changes == 1#但是可以不必要全部遍历完,大于1的时候就可以直接返回 + +class Solution(object): + def minMutation(self, start, end, bank): + """ + 对于每一个节点都要去找与它只相差一个的元素list,然后与这个list中所有元素进行比较,然后继续去找相差1的元素 + 时间复杂度是O(N)*O(N)*O(K)* + :type start: str + :type end: str + :type bank: List[str] + :rtype: int + """ + # quene = collections.deque() + # quene.append((start,start,0))#cur,pre,steps + # while quene: + # cur,pre,steps = quene.popleft() + # if cur == end: + # return steps + # for gene in bank:#bank长度 + # if isChangeOnce(cur,gene) and gene != pre: + # quene.append((gene,cur,steps+1)) + # return -1 + queue = [] + queue.append((start, 0)) + visited = set(bank) + while queue: + cur, step = queue.pop(0) + if cur == end: + return step + for i in range(len(cur)): + for c in "AGCT": # + mutation = cur[:i] + c + cur[i + 1:] # 列举出所有可能的变化为1的基因串 + if mutation in visited: + visited.remove(mutation) + queue.append((mutation, step + 1)) + return -1 + + + +# 2.DFS 回溯 +from typing import List +class SolutionI: + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + visited = set() + self.res = float('inf') + if end not in bank: return -1 + def dfs(cur, step): + # recursion terminator + if cur == end: + self.res = min(self.res, step) + return + #current level process + for next in bank: + if next not in visited and isChangeOnce(cur, next): + visited.add(next) + # drill down + dfs(next, step+1) + # reverse state + visited.remove(next) + visited.add(start) + dfs(start, 0) + return self.res if self.res < float('inf') else -1 + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" new file mode 100644 index 000000000..b1e2a4351 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2306_30_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" @@ -0,0 +1,63 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/30 7:14 PM + +# 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的 +# 功能。(若队列中没有元素,deleteHead 操作返回 -1 ) +# +# +# +# 示例 1: +# +# 输入: +# ["CQueue","appendTail","deleteHead","deleteHead"] +# [[],[3],[],[]] +# 输出:[null,null,3,-1] +# +# +# 示例 2: +# +# 输入: +# ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"] +# [[],[],[5],[2],[],[]] +# 输出:[null,-1,null,null,5,2] +# +# +# 提示: +# +# +# 1 <= values <= 10000 +# 最多会对 appendTail、deleteHead 进行 10000 次调用 +# +# Related Topics 栈 设计 + + +# leetcode submit region begin(Prohibit modification and deletion) +class CQueue(object): + + def __init__(self): + self.in_stack, self.out_stack = [],[] + + def appendTail(self, value): + self.in_stack.append(value) + + def deleteHead(self): + """ + 删除的时候有几点要考虑, + 1.如果out_stack中有元素,说明是上一次删除没有删除完的,最优先删除 + 2.如果out_stack中元素全部删除后,in_stack中没有元素,则无法删除返回-1 + 3.如果in_stack中有元素,将其全部转移到out_stack中,返回pop()值 + """ + if self.out_stack: return self.out_stack.pop() + if not self.in_stack: return -1 + while self.in_stack: + self.out_stack.append(self.in_stack.pop()) + return self.out_stack.pop() + + + +# Your CQueue object will be instantiated and called as such: +# obj = CQueue() +# obj.appendTail(value) +# param_2 = obj.deleteHead() +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\215\225\350\257\215\346\216\245\351\276\231.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\215\225\350\257\215\346\216\245\351\276\231.py" new file mode 100644 index 000000000..49ea3a051 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\215\225\350\257\215\346\216\245\351\276\231.py" @@ -0,0 +1,179 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/6/30 1:18 AM + +# 给定两个单词(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) +def isChangeOnce(cur, pre): + changes = 0 + for i in range(len(cur)): + if cur[i] != pre[i]: + changes += 1 + if changes > 1: return False + return True + +from typing import List +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + # bfs,用deque实现,就不用递归 + quene = [(beginWord, beginWord, 0, [beginWord])] # cur,pre,steps,path + while quene: + cur, pre, steps,path = quene.pop(0) + if cur == endWord: + return len(path) + for word in wordList: + if isChangeOnce(word, cur) and word != pre: + quene.append((word, cur, steps + 1, path+[word])) + return 0 # 不存在这样的转换序列 + +# leetcode submit region end(Prohibit modification and deletion) + + +from collections import defaultdict +class SolutionI(object): + def ladderLength(self, beginWord, endWord, wordList): + if endWord not in wordList or not endWord or not beginWord or not wordList: + return 0 + size = len(beginWord) + all_combo_dict = defaultdict(list) + for word in wordList:#M + for i in range(size):#N + #'*ot': ['hot', 'dot', 'lot'] + 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(size):#遍历当前节点可能的one_differ类型 + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + #确定one_differ类型,并查探可能的下一个节点 + 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)) + #将已经访问过的'*ot': ['hot', 'dot', 'lot']这种构型 删除掉 + all_combo_dict[intermediate_word] = [] + return 0 + +# from collections import defaultdict +class SolutionII(object): + def __init__(self): + self.size = 0 + # Dictionary to hold combination of words that can be formed, + # from any given word. By changing one letter at a time. + self.all_combo_dict = defaultdict(list) + + def visitWordNode(self, queue, visited, others_visited): + current_word, level = queue.pop(0) + for i in range(self.size): + intermediate_word = current_word[:i] + "*" + current_word[i+1:] + for word in self.all_combo_dict[intermediate_word]: + # If the intermediate state/word has already been visited from the + # other parallel traversal this means we have found the answer. + if word in others_visited: + return level + others_visited[word] + if word not in visited: + # Save the level as the value of the dictionary, to save number of hops. + 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.size = len(beginWord) + for word in wordList: + for i in range(self.size): + #'*ot': ['hot', 'dot', 'lot'] + self.all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + # Queues for birdirectional BFS + queue_begin = [(beginWord, 1)] # BFS starting from beginWord + queue_end = [(endWord, 1)] # BFS starting from endWord + # Visited to make sure we don't repeat processing same word + visited_begin = {beginWord: 1} + visited_end = {endWord: 1} + res = None + # We do a birdirectional search starting one pointer from begin + # word and one pointer from end word. Hopping one by one. + while queue_begin and queue_end: + # One hop from begin word + res = self.visitWordNode(queue_begin, visited_begin, visited_end) + if res: + return res + # One hop from end word + res = self.visitWordNode(queue_end, visited_end, visited_begin) + if res: + return res + + return 0 + + + + +# beginWord = "hot" +beginWord = "hit" +# endWord = "dog" +endWord = "cog" +wordList = ["hot","dot","dog","lot","log","cog"] +# wordList = ["hot","dog","dot"] + +# s = Solution() +# res = s.ladderLength(beginWord,endWord,wordList) +# print(res) + +from collections import defaultdict +ddict = defaultdict(list) +for word in wordList:#M + for i in range(3):#N + # Key is the generic word + # Value is a list of words which have the same intermediate generic word. + ddict[word[:i] + "*" + word[i+1:]].append(word) + +print(ddict) \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\262\233\345\261\277\346\225\260\351\207\217.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\262\233\345\261\277\346\225\260\351\207\217.py" new file mode 100644 index 000000000..b635c639c --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_1_\345\262\233\345\261\277\346\225\260\351\207\217.py" @@ -0,0 +1,64 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/1 9:26 PM + +from typing import List +class Solution: + ''' + 将二维网格视作一个无向图,竖直或水平相邻的'1'右边 + 遍历这个二维网格,如果某点='1',则以该点做深度优先搜索 + 在深度优先搜索过程中,将已经访问过的节点标记为'0' 最后的岛屿数量就是待求值 + 深度优先过程中,我们考察该点十字型结构有没有等于1的,进而深度遍历 + 时间复杂度是O(MN),最坏情况下的空间复杂度为O(MN),此时整个二维网格全为1 + ''' + #深度优先搜索 + def numIslands(self, grid: List[List[str]]) -> int: + rows = len(grid) + if rows == 0: return 0 + cols = len(grid[0]) + islands = 0 + for i in range(rows): + for j in range(cols): + if grid[i][j] == '1': + self.dfs(grid, i, j) + islands += 1 + return islands + + 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] = '0' + self.dfs(grid, i + 1, j) + self.dfs(grid, i - 1, j) + self.dfs(grid, i, j + 1) + self.dfs(grid, i, j - 1) + #广度优先搜索 + # 维护一个队列,做广度优先搜索,搜索其十字型中是否为'1',是则加入队列中 + # 最后返回的结果就是我们广度搜索的次数 + def numIslandsI(self, grid: List[List[str]]) -> int: + rows = len(grid) + if rows == 0: return 0 + cols = len(grid[0]) + count = 0 + quene = [] + for i in range(rows): + for j in range(cols): + if grid[i][j] == '1': + count = count + 1 + quene.append((i, j)) + while quene: + row, col = quene.pop() + if col + 1 < cols and grid[row][col + 1] == '1': + quene.append((row, col + 1)) + grid[row][col + 1] = 0 + if col - 1 >= 0 and grid[row][col - 1] == '1': + quene.append((row, col - 1)) + grid[row][col - 1] = 0 + if row - 1 >= 0 and grid[row - 1][col] == '1': + quene.append((row - 1, col)) + grid[row - 1][col] = 0 + if row + 1 < rows and grid[row + 1][col] == '1': + quene.append((row + 1, col)) + grid[row + 1][col] = 0 + return count + diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.py" new file mode 100644 index 000000000..96761882e --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.py" @@ -0,0 +1,31 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/1 11:50 PM + +from typing import List +class Solution: + def maxProfit(self, prices: List[int]) -> int: + #1.暴力法 超出时间限制O(N^2) + res = 0 + for i in range(len(prices)-1,0,-1): + for j in range(i-1,-1,-1): + diff = prices[i]-prices[j]#计算差值 + if diff > 0: + res = max(res,diff) + return res + + def maxProfitI(self, prices: List[int]) -> int: + inf = int(1e9) + minprice = inf + maxprofit = 0 + for price in prices: + maxprofit = max(price - minprice, maxprofit) + minprice = min(price, minprice) + return maxprofit + + + +s = Solution() +nums = [7,1,5,3,6,4] +res = s.maxProfitI(nums) +print(res) \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\347\254\254k\345\260\217\347\232\204\345\200\274.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\347\254\254k\345\260\217\347\232\204\345\200\274.py" new file mode 100644 index 000000000..51d98f99e --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\347\254\254k\345\260\217\347\232\204\345\200\274.py" @@ -0,0 +1,49 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/2 7:25 PM +import heapq +from typing import List +class Solution: + #优秀的解释 时间复杂度是 O(KlogN)空间复杂度O(N) + # https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/solution/shi-yong-dui-heapde-si-lu-xiang-jie-ling-fu-python/ + def kthSmallest(self, matrix: List[List[int]], k: int) -> int: + size = len(matrix) + pq = [(matrix[i][0],i,0) for i in range(size)]# 维护一个最小元素队列 (i,0) means location + heapq.heapify(pq) + for i in range(k-1):#第k次pop的元素直接返回 + num, row, col = heapq.heappop(pq) + if col != size - 1: + heapq.heappush(pq,(matrix[row][col+1],row,col+1))#如果某行没有全部删除,将当前值右边的元素如堆 + # now time = k + return heapq.heappop(pq)[0] + + def kthSmallestI(self, matrix: List[List[int]], k: int) -> int: + # 1.暴力法 时间复杂度O(N^2) 空间复杂度为O(N^2) + tmp = [x for item in matrix for x in item] + tmp.sort() + return tmp[-(len(tmp) - k + 1)] + + def kthSmallestII(self, matrix: List[List[int]], k: int) -> int: + #双指针 时间复杂度O(Nlog(max-min)) + # n次双指针,每次判断矩阵左侧小于num的数的个数,大于k个则右指针已动到mid + rows, cols = len(matrix), len(matrix[0]) + def check(num): + i, j, count = rows - 1, 0, 0 + while i >= 0 and j < cols: + if matrix[i][j] <= num: + count = count + i + 1 # 一竖行都小于 + j = j + 1 + else: # 如果大于num,这一层没有比num小的了 + i = i - 1 + return count >= k + + left_up, right_down = matrix[0][0], matrix[rows - 1][cols - 1] + while left_up < right_down: + mid = (left_up + right_down) // 2 + if check(mid): + right_down = mid # 左边有大于k个数,那么第k小的数肯定在左边 + else: # 左边没有k个数 + left_up = mid + 1 + return left_up + + diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\351\233\266\351\222\261\345\205\221\346\215\242.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\351\233\266\351\222\261\345\205\221\346\215\242.py" new file mode 100644 index 000000000..cd16c55b0 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_2_\351\233\266\351\222\261\345\205\221\346\215\242.py" @@ -0,0 +1,34 @@ +class Solution: + from typing import List + def coinChange(self, coins: List[int], amount: int) -> int: + def dfs(coins, amount, i, count, res): # 如果当前coin用完了,就换面值更小的 + if amount == 0: return min(count, res) + if i == -1: return res#已经遍历完所有coin + #current layer + multiple = amount//coins[i] + while multiple >= 0 and multiple + count < res:#这里往往是一个循环要么是for,要么是while + res = dfs(coins,amount-multiple*coins[i], i-1, count+multiple, res)#count用来记录上一层的组合数 + multiple -= 1 + return res # 回溯结束 + if amount == 0: return 0 + coins.sort() + result = dfs(coins, amount, len(coins)-1, 0, float('inf')) + return result if result != float('inf') else -1 + + #动态规划 + def coinChangeI(self, coins: List[int], amount: int) -> int: + dp = [float('inf')] * (amount + 1) + dp[0] = 0 + for cur in range(amount + 1): + for coin in coins: # 往当前位置的前[coins]个位置看,取最小的+1 + if cur >= coin: # 如果cur bool: + if not bills: return True + five, ten = 0, 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if five == 0: return False + five, ten = five - 1, ten + 1 + else:#change 15 + if five and ten: + five, ten = five - 1, ten - 1 + elif five >= 3: + five = five - 3 + else: + return False + return True diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_3_\351\245\274\345\271\262\345\210\206\345\217\221.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_3_\351\245\274\345\271\262\345\210\206\345\217\221.py" new file mode 100644 index 000000000..4c82ebcb2 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_3_\351\245\274\345\271\262\345\210\206\345\217\221.py" @@ -0,0 +1,18 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/3 10:08 PM + +class Solution: + #1.贪心法 + def findContentChildren(self, A: List[int], B: List[int]) -> int: + A.sort()#胃口 + B.sort()#饼干value + #优先满足胃口小的孩子 + res = 0 + i, j = 0, 0 + while j < len(B) and i < len(A): + if B[j]>=A[i]:#如果当前值大于胃口值 + res = res + 1 + i = i + 1 + j = j + 1 + return res \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_4_\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/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_4_\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..cbee7ff2b --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_4_\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,21 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/6 12:12 AM + +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: return -1 + left, right = 0, len(nums)-1 + while left <= right: + mid = (left + right)>>1 + if target == nums[mid]: + return mid + if nums[mid] >= nums[left]: + if nums[left] <= target <= nums[mid]:#用两个点夹住target + right = mid - 1 + else: left = mid + 1 + else: + if nums[mid] <= target <= nums[right]:#用两个点夹住target + left = mid + 1 + else: right = mid - 1 + return -1 \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204.py" new file mode 100644 index 000000000..d1881d66d --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204.py" @@ -0,0 +1,23 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/6 6:57 PM +import math +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + #排列组合Cm-1,m+n-2 + # return int(math.factorial(m + n - 2) / math.factorial(m - 1) / math.factorial(n - 1)) + #动态规划 + dp = [[0] * n for _ in range(m)] + for i in range(n): + dp[0][i] = 1 + for j in range(m): + dp[j][0] = 1 + 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[m - 1][n - 1] + +m, n = 3, 7 +s = Solution() +res = s.uniquePaths(m,n) +print(res) diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204II.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204II.py" new file mode 100644 index 000000000..28e273166 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\270\215\345\220\214\350\267\257\345\276\204II.py" @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/6 7:36 PM +from typing import List +class Solution: + def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: + if not obstacleGrid or len(obstacleGrid)==0: return 0 + m, n = len(obstacleGrid),len(obstacleGrid[0]) + dp = [[0] * n for _ in range(m)] + for i in range(n): + if obstacleGrid[0][i]==0: + dp[0][i] = 1 + for j in range(m): + if obstacleGrid[j][0]==0: + dp[j][0] = 1 + for i in range(1,m): + for j in range(1,n): + if obstacleGrid[i][j]==0: + dp[i][j] = dp[i-1][j] + dp[i][j-1] + return dp[m - 1][n - 1] + +nums = [ + [0,0,0,0,0,0], + [0,1,0,0,0,0], + [0,0,0,0,0,0] +] +nums1 = [[1,0]] +s =Solution() +res = s.uniquePathsWithObstacles(nums1) +print(res) \ No newline at end of file diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\272\214\345\217\211\346\240\221\350\267\257\345\276\204\346\200\273\345\222\214.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\272\214\345\217\211\346\240\221\350\267\257\345\276\204\346\200\273\345\222\214.py" new file mode 100644 index 000000000..e47e0f71b --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\344\272\214\345\217\211\346\240\221\350\267\257\345\276\204\346\200\273\345\222\214.py" @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/7 10:11 PM + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +from collections import deque +class Solution: + def hasPathSum(self, root: TreeNode, num: int) -> bool: + #层序遍历 + if not root: return False + node_quene = deque([root]) + val_quene = deque([root.val]) + while node_quene: + cur_node = node_quene.popleft() + cur_val = val_quene.popleft() + if not cur_node.left and not cur_node.right: + if num == cur_val: + return True + continue#如果已经是叶节点,但sum和target相同,无需执行后面的判断语句 + if cur_node.left: + node_quene.append(cur_node.left) + val_quene.append(cur_val + cur_node.left.val) + if cur_node.right: + node_quene.append(cur_node.right) + val_quene.append(cur_val + cur_node.right.val) + return False + #DFS深度优先遍历 递归 + def hasPathSumI(self, root: TreeNode, num: int) -> bool: + if not root: return False + if not root.left and not root.right: + return root.val == num + return self.hasPathSumI(root.left, num - root.val) or self.hasPathSumI(root.right, num - root.val) diff --git "a/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.py" "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.py" new file mode 100644 index 000000000..4f69ef606 --- /dev/null +++ "b/Week04/\346\257\217\346\227\245\344\270\200\351\242\2307_6_\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.py" @@ -0,0 +1,67 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/6 12:25 AM + +from typing import List +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix: return False + raws = len(matrix) + cols = len(matrix[0]) + if raws == 0 or cols == 0: + return False + raw, col = 0, cols - 1 + # 方法一:从右上角开始搜索,时间复杂度为O(N+M)) + while raw < raws and col >=0: + if matrix[raw][col] == target: + return True + elif matrix[raw][col] < target: + raw += 1 + else: + col -= 1 + return False + # 方法二:二分查找 + def searchMatrixI(self, matrix: List[List[int]], target: int) -> bool: + if not matrix: return False + raws = len(matrix) + if len(matrix[0]) == 0: return False + cols = len(matrix[0]) + if not matrix: return False + raws, cols = len(matrix), len(matrix[0]) + up, bottom = 0, raws - 1 + while up <= bottom: + row = (up + bottom) >> 1 + if matrix[row][0] == target: + return True + elif matrix[row][0] < target: + up = row + 1 + else: + bottom = row - 1 + raw = bottom + left, right = 0, cols - 1 + while left <= right: + mid = (left + right) >> 1 + if matrix[raw][mid] == target: + return True + elif matrix[raw][mid] < target: + left = mid + 1 + else: + right = mid - 1 + return False + #代码简化版 二分查找 + def searchMatrixII(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/Week06/.idea/Week06.iml b/Week06/.idea/Week06.iml new file mode 100644 index 000000000..7c9d48f0f --- /dev/null +++ b/Week06/.idea/Week06.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Week06/.idea/misc.xml b/Week06/.idea/misc.xml new file mode 100644 index 000000000..399908725 --- /dev/null +++ b/Week06/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/Week06/.idea/modules.xml b/Week06/.idea/modules.xml new file mode 100644 index 000000000..c96c2708b --- /dev/null +++ b/Week06/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Week06/.idea/vcs.xml b/Week06/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/Week06/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Week06/.idea/workspace.xml b/Week06/.idea/workspace.xml new file mode 100644 index 000000000..bae57ca93 --- /dev/null +++ b/Week06/.idea/workspace.xml @@ -0,0 +1,748 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1595247635043 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Week07/NOTE.md b/Week07/NOTE.md index 50de30414..6be75b82b 100644 --- a/Week07/NOTE.md +++ b/Week07/NOTE.md @@ -1 +1,135 @@ -学习笔记 \ No newline at end of file +学习笔记 + +#### Trie树 +Trie树每个节点只存单一字符,每条路径存相对应的单词 +要实现三个方法insert、search、startwith +```python +from collections import defaultdict +class TrieNode: + def __init__(self): + self.children = defaultdict(TrieNode) + self.is_word = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for ch in word: + node = node.children[ch] + node.is_word = True + + def search(self, word): + node = self.root + for ch in word: + if ch in node.children: + node = node.children[ch] + else: + return False + return node.is_word + + def startsWith(self, prefix): + node = self.root + for ch in prefix: + if ch in node.children: + node = node.children[ch] + else: + return False + return True +``` + +#### 单词搜索I +判断单词是否在矩阵中 +从矩阵的任意位置出发,开始寻找 +DFS+回溯 时间复杂度为O(4MNMN) +```python +from typing import List +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + if not board: return False + m, n = len(board), len(board[0]) + for i in range(m): + for j in range(n): + if self.dfs(i, j, board, word): + return True + return False + + def dfs(self, i, j, board, word): + if len(word) == 0: return True + if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or board[i][j] != word[0]: + return # 回溯 + tmp = board[i][j] + board[i][j] = '#' # 标志着已经选用过,到下一层哪怕选了 也是!=word[0],会回溯 + res = self.dfs(i + 1, j, board, word[1:]) or self.dfs(i - 1, j, board, word[1:]) \ + or self.dfs(i, j + 1, board,word[1:]) or self.dfs(i,j - 1,board,word[1:]) + board[i][j] = tmp + return res +``` + +#### 单词搜索II +和上一题意思差不多,只不过这次是判断字典中的字符串是否在矩阵中,输出在矩阵中的字符串 +可以还是照上面的思路 但是又要加一层循环,所以是O(K4MNMN),k是字典中字符串的个数 +在回溯的过程中,我们是对一个节点的四个兄弟节点判断完都不符合之后才能回溯,然后继续这样向上回溯 +但是在某个时刻 如果当前路径不是待求字符串的前缀,我们可以不用向下走了 +此时的时间复杂度是O(MN4*3^(L-1)) +从一个单元格开始,最初我们最多可以探索4个方向。 +假设每个方向都是有效的(即最坏情况),在接下来的探索中,我们最多有 3 个相邻的单元 +```python +from typing import List +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + if not board or not board[0] or not words: return [] + root = {} + for word in words: + node = root + for ch in word: + node = node.setdefault(ch,{}) + node['end'] = 0 #将所有word构建为tree树 + rows, cols = len(board), len(board[0]) + res = set() + def dfs(i,j,root,s): + cur = board[i][j] + if cur not in root: return#剪枝 + root = root[cur]#下探 + if 'end' in root and root['end'] == 0: + res.add(s+cur)#到达叶节点,加入到结果集 + board[i][j] = '@'# + for x,y in [[-1,0],[1,0],[0,1],[0,-1]]: + tmp_i,tmp_j = x + i, y + j + if 0 <= tmp_i < rows and 0 <= tmp_j < cols and board[tmp_i][tmp_j]!='@': + dfs(tmp_i,tmp_j,root,s + cur) + board[i][j] = cur#reverse state + for i in range(rows): + for j in range(cols): + dfs(i,j,root,'') + return list(res) +``` + +#### 并查集 +并查集是用来判断图中是否有环的算法 +需要实现两个函数 find 和 union +```python +SIZE = 7 +parent =[-1] * SIZE#-1代表指向自己,自己成环 +rank = [0] * SIZE#记录当前的深度 +def find(x, parent):#找到老大 + node = x + while parent[node] != -1: + node = parent[node] + return node + +def union(x, y):#合并两个节点 + x_root = find(x, parent) + y_root = find(y, parent) + if x_root == y_root:#如果老大是同一人 + return + # parent[y_root] = x_root + if rank[x_root] > rank[y_root]: + parent[y_root] = x_root + elif rank[y_root] > rank[x_root]: + parent[x_root] = y_root + else: + parent[x_root] = y_root + rank[y_root] += 1 +``` \ No newline at end of file diff --git "a/Week07/N\347\232\207\345\220\216.py" "b/Week07/N\347\232\207\345\220\216.py" new file mode 100644 index 000000000..29ed99186 --- /dev/null +++ "b/Week07/N\347\232\207\345\220\216.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/21 9:15 PM + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + # 皇后放置问题,八个数的全排列N! 所以时间复杂度就是N!,空间复杂度O(N) + # record记录皇后的放置情况 + def dfs(row,record): + if row == n: + res.append(record) + return + for col in range(n): + if isvalid(row,col,record): + dfs(row+1,record+[col]) + def isvalid(row,col,record): + if col in record:#这一行肯定不能被其他皇后占据 + return False + for i in range(row):#判断是否在可攻击范围 + # if row + col == i + record[i] or row - col == i - record[i]: + if i + record[i] == row + col or i - record[i] == row - col: + return False + return True + res = [] + dfs(0,[]) + return [['.' * i + 'Q' +'.'*(n-i-1) for i in row]for row in res] \ No newline at end of file diff --git "a/Week07/Trie\346\240\221.py" "b/Week07/Trie\346\240\221.py" new file mode 100644 index 000000000..ede9976c8 --- /dev/null +++ "b/Week07/Trie\346\240\221.py" @@ -0,0 +1,50 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/20 8:20 PM + + +# 节点不存完整单词 +# 从根节点到某一节点,路径上的字符连接起来为该节点的字符串 +# 每个节点的所有子节点路径代表不同的字符串 +# 需要实现三个方法1.insert、search、startwith +from collections import defaultdict +class TrieNode: + def __init__(self): + self.children = defaultdict(TrieNode) + self.is_word = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for ch in word: + node = node.children[ch] + node.is_word = True + + def search(self, word): + node = self.root + for ch in word: + if ch in node.children: + node = node.children[ch] + else: + return False + return node.is_word + + def startsWith(self, prefix): + node = self.root + for ch in prefix: + if ch in node.children: + node = node.children[ch] + else: + return False + 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/Week07/\345\215\225\350\257\215\346\220\234\347\264\242I.py" "b/Week07/\345\215\225\350\257\215\346\220\234\347\264\242I.py" new file mode 100644 index 000000000..2767cf5ce --- /dev/null +++ "b/Week07/\345\215\225\350\257\215\346\220\234\347\264\242I.py" @@ -0,0 +1,58 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/24 10:17 PM + + +# 给定一个二维网格和一个单词,找出该单词是否存在于网格中。 +# +# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 +# +# +# +# 示例: +# +# board = +# [ +# ['A','B','C','E'], +# ['S','F','C','S'], +# ['A','D','E','E'] +# ] +# +# 给定 word = "ABCCED", 返回 true +# 给定 word = "SEE", 返回 true +# 给定 word = "ABCB", 返回 false +# +# +# +# 提示: +# +# +# board 和 word 中只包含大写和小写英文字母。 +# 1 <= board.length <= 200 +# 1 <= board[i].length <= 200 +# 1 <= word.length <= 10^3 +# +# Related Topics 数组 回溯算法 + +from typing import List +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + if not board: return False + m, n = len(board), len(board[0]) + for i in range(m): + for j in range(n): + if self.dfs(i, j, board, word): + return True + return False + + def dfs(self, i, j, board, word): + if len(word) == 0: return True + if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or board[i][j] != word[0]: + return # 回溯 + tmp = board[i][j] + board[i][j] = '#' # 标志着已经选用过,到下一层哪怕选了 也是!=word[0],会回溯 + res = self.dfs(i + 1, j, board, word[1:]) or self.dfs(i - 1, j, board, word[1:]) \ + or self.dfs(i, j + 1, board,word[1:]) or self.dfs(i,j - 1,board,word[1:]) + board[i][j] = tmp + return res + diff --git "a/Week07/\345\215\225\350\257\215\346\220\234\347\264\242II.py" "b/Week07/\345\215\225\350\257\215\346\220\234\347\264\242II.py" new file mode 100644 index 000000000..215e708fe --- /dev/null +++ "b/Week07/\345\215\225\350\257\215\346\220\234\347\264\242II.py" @@ -0,0 +1,62 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/20 9:40 PM + +# 给定一个二维网格 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 字典树 回溯算法 +from typing import List +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + if not board or not board[0] or not words: return [] + root = {} + for word in words: + node = root + for ch in word: + node = node.setdefault(ch,{}) + node['end'] = 0 #将所有word构建为tree树 + rows, cols = len(board), len(board[0]) + res = set() + def dfs(i,j,root,s): + cur = board[i][j] + if cur not in root: return#剪枝 + root = root[cur]#下探 + if 'end' in root and root['end'] == 0: + res.add(s+cur)#到达叶节点,加入到结果集 + board[i][j] = '@'# + for x,y in [[-1,0],[1,0],[0,1],[0,-1]]: + tmp_i,tmp_j = x + i, y + j + if 0 <= tmp_i < rows and 0 <= tmp_j < cols and board[tmp_i][tmp_j]!='@': + dfs(tmp_i,tmp_j,root,s + cur) + board[i][j] = cur#reverse state + for i in range(rows): + for j in range(cols): + dfs(i,j,root,'') + return list(res) + diff --git "a/Week07/\345\271\266\346\237\245\351\233\206\346\250\241\346\235\277.py" "b/Week07/\345\271\266\346\237\245\351\233\206\346\250\241\346\235\277.py" new file mode 100644 index 000000000..55d1cfd97 --- /dev/null +++ "b/Week07/\345\271\266\346\237\245\351\233\206\346\250\241\346\235\277.py" @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/20 11:12 PM + + + +SIZE = 7 +parent =[-1] * SIZE +rank = [0] * SIZE +# 并查集就是实现了两个方法 一个find一个union +def find(x, parent): + node = x + while parent[node] != -1: + node = parent[node] + return node + +def union(x, y): + x_root = find(x, parent) + y_root = find(y, parent) + if x_root == y_root: + return + # parent[y_root] = x_root + if rank[x_root] > rank[y_root]: + parent[y_root] = x_root + elif rank[y_root] > rank[x_root]: + parent[x_root] = y_root + else: + parent[x_root] = y_root + rank[y_root] += 1 \ No newline at end of file diff --git "a/Week07/\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.py" "b/Week07/\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.py" new file mode 100644 index 000000000..4a500f369 --- /dev/null +++ "b/Week07/\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.py" @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/21 9:15 PM + +from typing import List +class Solution: + def isValidSudoku(self, board: List[List[str]]) -> bool: + rows = [{} for i in range(9)] + cols = [{} for i in range(9)] + boxs = [{} 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 = (i // 3) * 3 + j // 3 + + rows[i][num] = rows[i].get(num, 0) + 1 + cols[j][num] = cols[j].get(num, 0) + 1 + boxs[box][num] = boxs[box].get(num, 0) + 1 + + if rows[i][num] > 1 or cols[j][num] > 1 or boxs[box][num] > 1: + return False + return True + + # rows = [set() for _ in range(9)] + # cols = [set() for _ in range(9)] + # boxs = [set() for _ in range(9)] + # for i in range(9): + # for j in range(9): + # box_index, num = i // 3 * 3 + j // 3, board[i][j] + # if num != '.': + # if num in rows[i] or num in cols[j] or num in boxs[box_index]: + # return False + # else: + # rows[i].add(num) + # cols[j].add(num) + # boxs[box_index].add(num) + # return True \ No newline at end of file diff --git "a/Week07/\346\234\213\345\217\213\345\234\210.py" "b/Week07/\346\234\213\345\217\213\345\234\210.py" new file mode 100644 index 000000000..4faec387b --- /dev/null +++ "b/Week07/\346\234\213\345\217\213\345\234\210.py" @@ -0,0 +1,45 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/20 10:58 PM + +from typing import List + + +class Solution: + def findCircleNum(self, nums: List[List[int]]) -> int: + if not nums: return 0 + def find(x): + node = x + while parent[node] != -1: + node = parent[node] + return node + def union(x, y): + x_root = find(x) + y_root = find(y) + if x_root == y_root:#如果根节点一致,结束此次 + return + # parent[y_root] = x_root + if rank[x_root] > rank[y_root]: parent[y_root] = x_root + elif rank[y_root] > rank[x_root]: parent[x_root] = y_root + else: + parent[x_root] = y_root + rank[y_root] += 1 + size = len(nums) + parent = [-1] * size + rank = [0] * size + for i in range(size): + for j in range(size): + if i != j and nums[i][j] == 1: + union(i, j) + count = 0 + for i in parent: + if i < 0: + count += 1 + return count + +nums = [[1,1,0], + [1,1,0], + [0,0,1]] +s = Solution() +res = s.findCircleNum(nums) +print(res) \ No newline at end of file diff --git "a/Week07/\347\273\204\345\220\210\346\200\273\345\222\214IV.py" "b/Week07/\347\273\204\345\220\210\346\200\273\345\222\214IV.py" new file mode 100644 index 000000000..92a70a98d --- /dev/null +++ "b/Week07/\347\273\204\345\220\210\346\200\273\345\222\214IV.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/25 2:22 AM + +from typing import List +class Solution: + def combinationSum4(self, nums: List[int], target: int) -> int: + # def dfs(cur,tmp): + # if cur > target: return + # if cur == target: res.append(tmp) + # for i in range(len(nums)): + # dfs(cur+nums[i],tmp+[nums[i]]) + # res = [] + # dfs(0,[]) + # return len(res) + dp = [0]*(target+1) + dp[0] = 1 + for i in range(target+1): + for j in range(len(nums)): + if i >= nums[j]: + dp[i] += dp[i-nums[j]]#这句话是有可能访问越界的 + return dp[-1] + +s = Solution() +res = s.combinationSum4([1,2,4],7) +print(res) \ No newline at end of file diff --git "a/Week07/\350\247\243\346\225\260\347\213\254.py" "b/Week07/\350\247\243\346\225\260\347\213\254.py" new file mode 100644 index 000000000..63da90af5 --- /dev/null +++ "b/Week07/\350\247\243\346\225\260\347\213\254.py" @@ -0,0 +1,51 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/21 9:15 PM + +from typing import List +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + cols = [set() for _ in range(9)] + rows = [set() for _ in range(9)] + boxs = [set() for _ in range(9)] + #预先扫描一次 + for i in range(9): + for j in range(9): + if board[i][j] != '.': + cols[i].add(board[i][j]) + rows[i].add(board[i][j]) + boxs[i//3*3+j//3].add(board[i][j]) + + def dfs(i, j): + if board[i][j] != '.': + if i == 8 and j == 8: + self.flag = True + return + if j < 8: + dfs(i, j + 1) + else: + dfs(i + 1, 0) + return + for ch in range(1, 10):#对于每一个位置,用1-9试探 + ch = str(ch) + if ch not in cols[j] and ch not in rows[i] and ch not in boxs[i // 3 * 3 + j // 3]: + #如果可以放置,更新三个set(),并将此刻的位置修改 + cols[j].add(ch) + rows[i].add(ch) + boxs[i // 3][j // 3].add(ch) + board[i][j] = ch + if i == 8 and j == 8: + self.flag = True + return + if j < 8: + dfs(i, j + 1) + else: + dfs(i + 1, 0) + if self.flag: return + board[i][j] = '.' + cols[j].remove(ch) + rows[i].remove(ch) + boxs[i // 3][j // 3].remove(ch) + + self.flag = False + dfs(0, 0) diff --git "a/Week08/2\347\232\204\345\271\202.py" "b/Week08/2\347\232\204\345\271\202.py" new file mode 100644 index 000000000..66eee7df2 --- /dev/null +++ "b/Week08/2\347\232\204\345\271\202.py" @@ -0,0 +1,16 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 9:00 PM + +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + # if n==0: return False#与面试官沟通边界 + # if n==1: return True + # while n!=1: + # if n%2!=0: return False + # else: n = n//2 + # return True + # 该数的二进制位有且仅有一个1 + if n==0: return False + while n!=0: + return (n&(n-1))==0 #打掉最后一个1看是否为0 以此检查是否只有一个1 \ No newline at end of file diff --git a/Week08/LRUcache.py b/Week08/LRUcache.py new file mode 100644 index 000000000..1fb601d00 --- /dev/null +++ b/Week08/LRUcache.py @@ -0,0 +1,121 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 11:21 PM + +# hashmap+double-linklist + +class ListNode: + def __init__(self,key,val): + self.key = key + self.val = val + self.next = None + self.prev = None + +class LRUCache: + def __init__(self, capacity: int): + self.dic = {} + self.head = ListNode(None,None) + self.tail = ListNode(None,None) + self.head.next = self.tail + self.tail.prev = self.head + self.capacity = capacity + + def get(self, key: int) -> int: + if not key in self.dic: + return -1 + node = self.dic[key] + self.delete(node)#访问过后要将它放到链表头部 + self.insert(node) + return node.val + + def insert(self,node): + node.next, node.prev = self.head.next, self.head + temp = self.head.next + self.head.next = node + temp.prev = node + + def delete(self,node): + node.prev.next, node.next.prev = node.next, node.prev + + def put(self, key: int, value: int) -> None: + if key in self.dic:#如果相同key值出现过,更新dic和链表 + node = self.dic[key] + node.val = value + self.delete(node) + self.insert(node) + return + if len(self.dic) == self.capacity: + node=self.tail.prev#删除第一个元素 + self.delete(node) + del self.dic[node.key] + self.capacity -= 1 + node = ListNode(key,value)#将此元素加入到第一个元素 + self.dic[key] = node + self.insert(node) + self.capacity += 1 + + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) + +class ListNode: + def __init__(self, key, val): + self.key = key + self.val = val + self.next = None + self.pre = None + + +class LRUCache: + def __init__(self, capacity): + self.dic = {} + self.capacity = capacity + self.head = ListNode(None, None) + self.tail = ListNode(None, None) + self.head.next = self.tail + self.tail.pre = self.head + + def put(self, key, value): + # 先判断要放进去的元素是否在hashmap里面 + if key not in self.dic: # 如果不在里面 + if self.capacity != 0: # 如果不在里面且还有额外的空间,就往里加 + self.insert(key, value) + else: # 没有额外的空间了,就应当删除双向链表中的最后一个元素 + last = self.tail.pre + self.delete(last) + self.insert(key, value) + else: # 如果在里面 + # 应当先删除这个元素/更新 + cur = self.dic[key] + self.delete(cur) # 删除这一个 + self.insert(key, value) + + def get(self, key): + if key not in self.dic: + return -1 + else: + # 将该元素放到head之后 + cur = self.dic[key] + value = cur.val + self.delete(cur) + self.insert(key, value) + return value + + def delete(self, node): + node.pre.next = node.next + node.next.pre = node.pre + del self.dic[node.key] + self.capacity += 1 + + def insert(self, key, value): + cur = ListNode(key, value) + cur.next = self.head.next + cur.pre = self.head + tmp = self.head.next + tmp.pre = cur + self.head.next = cur + self.capacity -= 1 + self.dic[key] = cur \ No newline at end of file diff --git a/Week08/NOTE.md b/Week08/NOTE.md index 50de30414..b391dd469 100644 --- a/Week08/NOTE.md +++ b/Week08/NOTE.md @@ -1 +1,339 @@ -学习笔记 \ No newline at end of file +学习笔记 +判断奇偶 +x&1 == 1 if odd else even +x = x & (x-1) 清除最右的1 +x = x & (-x) 得到最右的1 + +#### 位为1的个数 +给一个无符号整数,返回其二进制表示中1的个数 +1. 先转二进制,匹配二进制字符串中1的个数,最后返回 +```python +class Solution: + def hammingWeight(self, n: int) -> int: + tmp = bin(n)[2:] + count = 0 + for i in range(len(tmp)): + if tmp[i] == '1': + count += 1 + return count +``` +2.判断最低位是否为1,然后右移一位,继续判断 +```python +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n!=0: + if n & 1 == 1:#判断最低位是否为1 + count += 1 + n = n >>1 + return count +``` +3.直接找到最低位的1,看能找几次 +```python +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n!=0: + n = n & (n-1)#清除最低位的1 + count += 1 + return count +``` + +#### 二的幂 +判断是否是2的幂次 +1.辗转相除法,直到结果为1为止 +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n==0: return False#与面试官沟通边界 + if n==1: return True + while n!=1: + if n%2!=0: return False + else: n = n//2 + return True +``` +2.如果是2的幂次,那么其二进制位应该有且仅有一个1. +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n==0: return False + while n!=0: + return (n&(n-1))==0 #打掉最后一个1看是否为0 以此检查是否只有一个1 +``` + +#### 颠倒二进制位 +想法是将二进制位里面的第i为调换到31-i位上,然后用加法累计所有位的调换 +从右向左遍历,然后将数左移以调换 + +```python +class Solution: + def reverseBits(self, n: int) -> int: + res,power= 0,31 + while n: + res += (n&1)<>1#以取得新的最后一位 + power -= 1 + return res +``` + +#### 布隆过滤器 +布隆过滤器常用作 防止缓存击穿情况的出现 预先判断数据是否存在数据库中,可以缓解对数据库的压力 +布隆过滤器的思想是,利用一个二进制数组,对于任何一个value,我们都给他它分配一个定长的k位二进制数,可以不连续 +每次有元素进来,就使用特定的hash函数生成k个01,代表它的二进制描述, +在查找的时候,如果待查元素不在布隆过滤器中,说明一定不存在,反之说明可能存在 +```python +from bitarray import bitarray +import mmh3 +class BooleanFilter: + def __init__(self,size,hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray + self.bit_array.setall(0) + def get(self,x): + for seed in range(self.hash_num): + result = mmh3.hash(x,seed)%self.size#用k位二进制表示是否存在 + self.bit_array[result] = 1 + def lookup(self,x): + for seed in range(self.hash_num):#检查x的每一位的0,1,只要不是1,就不在 + result = mmh3.hash(x,seed)%self.size + if self.bit_array[result] != 1: + return 'not in' + return 'probably in' +``` + +#### LRUcache +最近最久未使用算法,例如手机后台切换的时候看到的算法 +实现起来是利用hash表+双向链表 +注意到这个双向链表维护了两个节点并不存值,是head和tail +每次有新的元素进来,如果capicity还有容量,就加入到双向链表**首部** +如果没有容量了,就从双向链表末尾删除一个元素 +如果新进来的元素在双向链表中[这就是为什么要使用hash表的原因,查在不在hash表中O(1)] +就先拿出来,修改值,再插入到双向链表**首部** +>实现的时候就是要实现两个函数insert和delete + +```python +class ListNode: + def __init__(self,key,val): + self.key = key + self.val = val + self.next = None + self.prev = None + +class LRUCache: + def __init__(self, capacity: int): + self.dic = {} + self.head = ListNode(None,None) + self.tail = ListNode(None,None) + self.head.next = self.tail + self.tail.prev = self.head + self.capacity = capacity + + def get(self, key: int) -> int: + if not key in self.dic: + return -1 + node = self.dic[key] + self.delete(node)#访问过后要将它放到链表头部 + self.insert(node) + return node.val + + def insert(self,node): + node.next, node.prev = self.head.next, self.head + temp = self.head.next + self.head.next = node + temp.prev = node + + def delete(self,node): + node.prev.next, node.next.prev = node.next, node.prev + + def put(self, key: int, value: int) -> None: + if key in self.dic:#如果相同key值出现过,更新dic和链表 + node = self.dic[key] + node.val = value + self.delete(node) + self.insert(node) + return + if len(self.dic) == self.capacity: + node=self.tail.prev#删除第一个元素 + self.delete(node) + del self.dic[node.key] + node = ListNode(key,value)#将此元素加入到第一个元素 + self.dic[key] = node + self.insert(node) +``` + +#### 归并排序 +归并排序的思想就是分治到单个元素,然后回头 治理 回头的时候就有左右两个子数组已经有序了 +主要就是实现的时候需要用额外的空间 +```python +class Solution: + def merge_sort(self, nums): + if len(nums)<2: + return nums + mid = len(nums)//2 + nums1 = nums[:mid] + nums2 = nums[mid:] + return self.merge(self.merge_sort(nums1), self.merge_sort(nums2)) + + def merge(self, nums1, nums2): + res = [] + while nums1 and nums2: + if nums1[0] <= nums2[0]: + res.append(nums1.pop(0)) + else: + res.append(nums2.pop(0)) + while nums1: + res.append(nums1.pop(0)) + while nums2: + res.append(nums2.pop(0)) + return res +``` +#### 快速排序 +快速排序的思想是界定一个pivot,找到左边比pivot大的找到右边比pivot小的,交换 +使得每一轮排序后,左右数组符合左数组= right: + return + ind = left + ((right-left) >> 1) + pivot = self.partition(nums, left, right, nums[ind]) + self.quick_sort(nums, left, pivot-1) #左 + self.quick_sort(nums, pivot, right) #右 + + def partition(self, nums, left, right, pivot): + while left <= right: + while nums[left] < pivot: + left += 1 + while nums[right] > pivot: + right -= 1 + if left <= right: + nums[left], nums[right] = nums[right], nums[left] + left, right = left + 1, right - 1 + return left +``` + +#### 堆排序 +首先从右往左遍历,使得每个小三角的顶最大,这是建堆 +前边建堆nums[0]最大,我们把最大的元素与末尾交换,然后调整堆[只用调整除末尾元素外的] +```python +class Solution: + def heap_sort(self, nums): + self.build_heap(nums) + for i in range(len(nums)-1,-1,-1):#调整堆的时候将最大的元素nums[0]放到最后面, + nums[i],nums[0] = nums[0],nums[i] + self.heapify(nums,i,0) + + def build_heap(self, nums):#使得每个小三角形都是顶最大 + for i in range(len(nums)-1//2,-1,-1): + self.heapify(nums,len(nums), i) + + def heapify(self, nums, n, i): + if i >= n: return + c1, c2 = i*2+1, i*2+2 + ind = i + if c1 < n and nums[c1] > nums[ind]: + ind = c1 + if c2 < n and nums[c2] > nums[ind]: + ind = c2 + if ind != i: + nums[i], nums[ind] = nums[ind], nums[i] + self.heapify(nums,n,ind) #调整堆之后要继续保持堆的特性 +``` + + +#### 数组的相对排序 +就是把arr1的元素按这样的规律排序:如果arr1[i]在arr2中,就将其在arr2中的相对位置排序 +如果不在,则按大小排序 +思路就是,将arr1元素记录在hashmap中,遍历arr2,修改arr1,这样必然可以满足在arr2中的元素,按其在arr2中的顺序排序 +对于不在的,拿出来排序再赋值到arr1中 +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + hashmap = {} + for i, num in enumerate(arr1): + hashmap[num] = hashmap.get(num,0) + 1 + ind = 0 + for i in range(len(arr2)): + cur = arr2[i] + while hashmap.get(cur) > 0: + arr1[ind] = cur + hashmap[cur] -= 1 + ind += 1 + # 将不在arr2中的元素升序排列,但由于不是有序字典 + tmp = [] + for key, val in hashmap.items(): + while val > 0: + tmp.append(key) + hashmap[key] -= 1 + val -= 1 + tmp.sort() + arr1[ind:] = tmp + # return arr1[:ind] + tmp + return arr1 +``` + +#### 区间合并 +给定一个区间集合,合并所有重叠的区间 +这一题如果没做过,真不简单 +秒解是 **先按照左区间排好序** 这样有两个好处 +1所有可以合并的区间必然相连 2合并时只用看前边的区间右值与当前区间的左值的大小 +```python +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + #按区间左端点值进行排序,那么能合并的区间必然相连 + intervals.sort(key=lambda x:x[0]) + res = [] + for interval in intervals: + if not res or res[-1][1] < interval[0]:#res[-1]区间右值小于起始值 + res.append(interval) + else:#否则更新右值 + res[-1][1] = max(res[-1][1],interval[1]) + return res +``` + +#### 493 翻转对 + +#### 315 计算右侧小于当前元素的个数 + +#### 剑指offer51 数组中的逆序数对 +```python +class Solution: + def reversePairs(self, nums: List[int]) -> int: + size = len(nums) + if size < 2: + return 0 + temp = [0 for _ in range(size)] + return self.reverse_pairs(nums, 0, size - 1, temp) + + def reverse_pairs(self, nums, left, right, temp):#在数组 nums 的区间 [l,r] 统计逆序对 + if left == right: + return 0 + mid = left + ((right-left) >> 1) + lpairs = self.reverse_pairs(nums, left, mid, temp) + rpairs = self.reverse_pairs(nums, mid + 1, right, temp) + cross_pairs = self.merge_and_count(nums, left, mid, right, temp) + return lpairs + rpairs + cross_pairs + + def merge_and_count(self, nums, left, mid, right, temp): + for i in range(left, right + 1): + temp[i] = nums[i] + i,j,count = left, mid+1,0 + for k in range(left, right + 1): + if i == mid + 1:#左侧处理完之后 + nums[k] = temp[j] + j += 1 + elif j == right + 1:#右侧处理完之后 + nums[k] = temp[i] + i += 1 + elif temp[i] <= temp[j]:#前边的小,不用计数,将前边的值归并到temp中 + nums[k] = temp[i] + i += 1 + else: + nums[k] = temp[j]#后边的小,将后边的值归并到tmp中,累计计数值 + j += 1 + count += (mid - i + 1)# + return count + +``` + diff --git a/Week08/selftest.py b/Week08/selftest.py new file mode 100644 index 000000000..793f6795a --- /dev/null +++ b/Week08/selftest.py @@ -0,0 +1,135 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/31 7:03 PM + +class SolutionI: + + def merge_sort(self,nums): + # 递归终止条件 左右子数组长度为1的时候返回该数组 + if len(nums) <2: return nums + #归并排序 左右都已经排好序合并两个 + mid = len(nums)//2 + # nums1 = nums[:mid] + # nums2 = nums[mid:] + return self.merge(self.merge_sort(nums[:mid]),self.merge_sort(nums[mid:])) + + + def merge(self,nums1,nums2): + res = [] + while nums1 and nums2: + if nums1[0] > nums2[0]: + res.append(nums2.pop(0)) + else: + res.append(nums1.pop(0)) + + while nums1: + res.append(nums1.pop(0)) + while nums2: + res.append(nums2.pop(0)) + return res + + +class SolutionII: + + def quicksort(self,nums,left,right): + #快速排序,partition返回下标 + # left,right = 0, len(nums) + if left >= right: return + # pivot = nums[mid] + mid = left + ((right-left)>>1) + pivot = self.partition(nums,left,right,nums[mid]) + self.quicksort(nums,left,pivot-1)#左 + self.quicksort(nums,pivot,right)#右 + return nums + + def partition(self,nums,left,right,pivot): + while left <= right: + while nums[left] < pivot: + left += 1 + while nums[right] > pivot: + right -= 1 + if left <= right: + nums[left],nums[right] = nums[right],nums[left] + left,right = left+1,right-1 + return left + + +class SolutionIII: + def heapsort(self,nums): + self.build_heap(nums) + for i in range(len(nums)-1,-1,-1):#从后往前遍历,把最大的放到最后 + #这里要交换! + nums[i],nums[0] = nums[0],nums[i] + self.heapify(nums,i,0) + + def build_heap(self,nums): + for i in range(len(nums)//2):#建堆错了没??,应该是从后往前建堆,因为后面的堆调整后要继续向前 + self.heapify(nums,len(nums),i) + + def heapify(self,nums,n,i): + #少了递归终止条件 + if i >= n: return + c1,c2 = i*2+1,i*2+2 + max_ind = i + #堆排序内部,是没有for循环的只有递归 + if c1 < n and nums[c1] > nums[max_ind]: + max_ind = c1 + if c2 < n and nums[c2] > nums[max_ind]: + max_ind = c2 + if i != max_ind:#这里的条件记清楚了! + nums[max_ind], nums[i] = nums[i], nums[max_ind] + self.heapify(nums, n, max_ind)#调整后继续维持堆 + + +s = SolutionI() +nums = [2, 3, 1, 4, 2, 5, 6, 8, 6, 5, 7] +res = s.merge_sort(nums) +print(res) + + +# 1.想办法合并这几个数组,合并的规则是 +# merge =[0,...,max_n] +# [a1...a2] [b1...b2] +def maxK(nums,n): + #但是这种方法不能解决 15 23 15 24 的情形,所以要动态的创建set,依次判断是否在set中 + # 即使是 15 23 15 24 + # 求出所有课程中耗时最长的,构建一个数组存放,记录课程起止时间出现的次数,返回数组中的最大计数 + size = max(max(nums)) + tmp = [0]*(size+1) + for num in nums: + for cur in num: + tmp[cur] += 1 + return max(tmp) + + +# 2.最终奖励值 等于自己选的 加上 从剩余的中选的最大值 |或者干脆就不选,如果不选,其他人的奖励值就只由取到的奖券面额决定 +# f[n] = f[n-1]+nums[n] f[n]代表第n-1个同学能拿到的最大面值 +# 动态规划方程出来了 + + +size = 40 +a = 30 +b = 10 + +def tickets(size,a,b):#a,b分指50 和 100 + count = 0 + start = 1 + + return count + + +def dfs(size, a, b, cur, count, start): + if cur < 0: return + if start == size: return count + cur += 50 + while start < size: + dfs(size,a - 1,b,cur,count) + + + + + + + + + diff --git "a/Week08/\344\271\260\347\245\250\346\246\202\347\216\207\351\227\256\351\242\230.py" "b/Week08/\344\271\260\347\245\250\346\246\202\347\216\207\351\227\256\351\242\230.py" new file mode 100644 index 000000000..31c4ce3ca --- /dev/null +++ "b/Week08/\344\271\260\347\245\250\346\246\202\347\216\207\351\227\256\351\242\230.py" @@ -0,0 +1,36 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/1 9:39 PM + +from functools import lru_cache +class Solution: + # @lru_cache + def buy_tickets(self, m, n):# m,n 分别代表50,100 + # 假设第m+n个人手持100,则他前面有m个手持50,n-1个手持100 则f(m,n) = f(m,n-1) + # m+n手持50.他前面m-1个手持50,n个手持100 f(m,n) = f(m-1,n) + # m 0; n=0 -> 1 + res = 0 + if n == 0: + return 1 + elif m < n: + return 0 + else: + res = self.buy_tickets(m,n-1) + self.buy_tickets(m-1,n) + return res + def buy_ticketsI(self,m,n): + dp = [[0]*(n+1) for _ in range(m+1)] + for col in range(n+1): + dp[0][col] = 0 + for row in range(m+1): + dp[row][0] = 1 + for i in range(1,m+1): + for j in range(1,n+1): + if i < j: dp[i][j] = 0 + else: + dp[i][j] = dp[i-1][j] + dp[i][j-1] + return dp[-1][-1] + + +s = Solution() +res = s.buy_ticketsI(20,10) +print(res) diff --git "a/Week08/\344\275\2151\347\232\204\344\270\252\346\225\260.py" "b/Week08/\344\275\2151\347\232\204\344\270\252\346\225\260.py" new file mode 100644 index 000000000..5e689827f --- /dev/null +++ "b/Week08/\344\275\2151\347\232\204\344\270\252\346\225\260.py" @@ -0,0 +1,23 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 8:59 PM +class Solution: + def hammingWeight(self, n: int) -> int: + # 笨方法 + # tmp = bin(n)[2:] + # count = 0 + # for i in range(len(tmp)): + # if tmp[i] == '1': + # count += 1 + # return count + # count = 0 + # while n!=0: + # if n & 1 == 1:#判断最低位是否为1 + # count += 1 + # n = n >>1 + # return count + count = 0 + while n!=0: + n = n & (n-1)#清除最低位的1 + count += 1 + return count \ No newline at end of file diff --git "a/Week08/\345\206\222\346\263\241\346\216\222\345\272\217.py" "b/Week08/\345\206\222\346\263\241\346\216\222\345\272\217.py" new file mode 100644 index 000000000..df9e51763 --- /dev/null +++ "b/Week08/\345\206\222\346\263\241\346\216\222\345\272\217.py" @@ -0,0 +1,17 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/28 8:08 PM + +# 冒泡排序是稳定的 +class Solution: + def bubblesort(self,nums): + for i in range(len(nums)): + for j in range(i,len(nums)): + if nums[i]>nums[j]: + nums[i],nums[j] = nums[j],nums[i] + + +s = Solution() +nums = [2,3,1,4,2,5,6,8,6,5,7] +s.bubblesort(nums) +print(nums) \ No newline at end of file diff --git "a/Week08/\345\220\210\345\271\266\345\214\272\351\227\264.py" "b/Week08/\345\220\210\345\271\266\345\214\272\351\227\264.py" new file mode 100644 index 000000000..2e8d854d8 --- /dev/null +++ "b/Week08/\345\220\210\345\271\266\345\214\272\351\227\264.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/2 11:55 AM + +from typing import List +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + #按区间左端点值进行排序,那么能合并的区间必然相连 + intervals.sort(key=lambda x:x[0]) + print(intervals) + res = [] + for interval in intervals: + if not res or res[-1][1] < interval[0]:#区间右值小于起始值 + res.append(interval) + else:#否则更新右值 + res[-1][1] = max(res[-1][1],interval[1]) + print(res) + return res + + +s = Solution() +nums = [[1,3],[2,6],[8,10],[15,18]] +res = s.merge(nums) +print(res) \ No newline at end of file diff --git "a/Week08/\345\240\206\346\216\222\345\272\217.py" "b/Week08/\345\240\206\346\216\222\345\272\217.py" new file mode 100644 index 000000000..4336c79fe --- /dev/null +++ "b/Week08/\345\240\206\346\216\222\345\272\217.py" @@ -0,0 +1,33 @@ +# # -*- coding:utf-8 -*- +# # Author : Ray +# # Data : 2020/7/28 9:04 PM +# +# 不稳定 +class Solution: + def heap_sort(self, nums): + self.build_heap(nums) + for i in range(len(nums)-1,-1,-1):#调整堆的时候将最大的元素nums[0]放到最后面, + nums[i],nums[0] = nums[0],nums[i] + self.heapify(nums,i,0) + + def build_heap(self, nums):#使得每个小三角形都是顶最大 + for i in range(len(nums)-1//2,-1,-1): + self.heapify(nums,len(nums), i) + + def heapify(self, nums, n, i): + if i >= n: return + c1, c2 = i*2+1, i*2+2 + ind = i + if c1 < n and nums[c1] > nums[ind]: + ind = c1 + if c2 < n and nums[c2] > nums[ind]: + ind = c2 + if ind != i: + nums[i], nums[ind] = nums[ind], nums[i] + self.heapify(nums,n,ind) #调整堆之后要继续保持堆的特性 + + +s = Solution() +nums = [2,3,1,4,2,5,6,8,6,5,7] +s.heap_sort(nums) +print(nums) diff --git "a/Week08/\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.py" "b/Week08/\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.py" new file mode 100644 index 000000000..69de1aa6b --- /dev/null +++ "b/Week08/\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.py" @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 11:11 PM + +from bitarray import bitarray +import mmh3 +class BooleanFilter: + def __init__(self,size,hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray + self.bit_array.setall(0) + def get(self,x): + for seed in range(self.hash_num): + result = mmh3.hash(x,seed)%self.size#用k位二进制表示是否存在 + self.bit_array[result] = 1 + def lookup(self,x): + for seed in range(self.hash_num): + result = mmh3.hash(x,seed)%self.size + if self.bit_array[result] != 1: + return 'not in' + return 'probably in' \ No newline at end of file diff --git "a/Week08/\345\275\222\345\271\266\346\216\222\345\272\217.py" "b/Week08/\345\275\222\345\271\266\346\216\222\345\272\217.py" new file mode 100644 index 000000000..74075efd2 --- /dev/null +++ "b/Week08/\345\275\222\345\271\266\346\216\222\345\272\217.py" @@ -0,0 +1,35 @@ +# # -*- coding:utf-8 -*- +# # Author : Ray +# # Data : 2020/7/28 8:44 PM +# +# 归并排序的思想是将数组分作AB两区,AB两区都区内有序之后,合并这两个区 +# 如果归并的时候 有相同的值,将左侧的放到tmp中就是稳定的 +class Solution: + def merge_sort(self, nums): + if len(nums)<2: + return nums + mid = len(nums)//2 + nums1 = nums[:mid] + nums2 = nums[mid:] + return self.merge(self.merge_sort(nums1), self.merge_sort(nums2)) + + def merge(self, nums1, nums2): + res = [] + while nums1 and nums2: + if nums1[0] <= nums2[0]: + res.append(nums1.pop(0)) + else: + res.append(nums2.pop(0)) + while nums1: + res.append(nums1.pop(0)) + while nums2: + res.append(nums2.pop(0)) + return res + + +s = Solution() +nums = [2,3,1,4,2,5,6,8,6,5,7] +res = s.merge_sort(nums) +print(res) + + diff --git "a/Week08/\345\277\253\351\200\237\346\216\222\345\272\217.py" "b/Week08/\345\277\253\351\200\237\346\216\222\345\272\217.py" new file mode 100644 index 000000000..993fbbe03 --- /dev/null +++ "b/Week08/\345\277\253\351\200\237\346\216\222\345\272\217.py" @@ -0,0 +1,33 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/28 8:31 PM + + +# 快速排序的思想是在数组中找一个pivot使得左边比pivot小,右边比pivot大,然后对左右两侧元素同逻辑处理 +# 也是不稳定的 +class Solution: + def quick_sort(self, nums, left, right): + if left >= right: + return + ind = left + ((right-left) >> 1) + pivot = self.partition(nums, left, right, nums[ind]) + self.quick_sort(nums, left, pivot-1) #左 + self.quick_sort(nums, pivot, right) #右 + + def partition(self, nums, left, right, pivot): + while left <= right: + while nums[left] < pivot: + left += 1 + while nums[right] > pivot: + right -= 1 + if left <= right: + nums[left], nums[right] = nums[right], nums[left] + left, right = left + 1, right - 1 + return left + + + +s = Solution() +nums = [2,3,1,4,2,5,6,8,6,5,7] +s.quick_sort(nums,0,len(nums)-1) +print(nums) \ No newline at end of file diff --git "a/Week08/\346\217\222\345\205\245\346\216\222\345\272\217.py" "b/Week08/\346\217\222\345\205\245\346\216\222\345\272\217.py" new file mode 100644 index 000000000..f2a84d983 --- /dev/null +++ "b/Week08/\346\217\222\345\205\245\346\216\222\345\272\217.py" @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/28 8:15 PM + + +# 插入排序的思想是,假设数组分作两区,A区一直有序,每次从B区中取出元素,插入A区的合适位置 +# 所以是不稳定的 +class Solution: + def insertsort(self, nums): + for i in range(1,len(nums)): + tmp, j = nums[i], i - 1#j要在A区中找到合适位置【往前找】,同时还要挪动其他元素 + while j >= 0 and nums[j] > tmp: + nums[j+1] = nums[j] + j -= 1 + nums[j+1] = tmp + + + +s = Solution() +nums = [2, 3, 1, 4, 2, 5, 6, 8, 6, 5, 7] +s.insertsort(nums) +print(nums) diff --git "a/Week08/\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" "b/Week08/\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" new file mode 100644 index 000000000..918496501 --- /dev/null +++ "b/Week08/\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" @@ -0,0 +1,51 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/2 8:07 PM + +from typing import List +# 前有序数组中元素出列的时候,计算逆序个数 + +from typing import List + + +class Solution: + def reversePairs(self, nums: List[int]) -> int: + size = len(nums) + if size < 2: + return 0 + temp = [0 for _ in range(size)] + return self.reverse_pairs(nums, 0, size - 1, temp) + + def reverse_pairs(self, nums, left, right, temp):#在数组 nums 的区间 [l,r] 统计逆序对 + if left == right: + return 0 + mid = left + ((right-left) >> 1) + lpairs = self.reverse_pairs(nums, left, mid, temp) + rpairs = self.reverse_pairs(nums, mid + 1, right, temp) + cross_pairs = self.merge_and_count(nums, left, mid, right, temp) + return lpairs + rpairs + cross_pairs + + def merge_and_count(self, nums, left, mid, right, temp): + for i in range(left, right + 1): + temp[i] = nums[i] + i,j,count = left, mid+1,0 + for k in range(left, right + 1): + if i == mid + 1:#左侧处理完之后 + nums[k] = temp[j] + j += 1 + elif j == right + 1:#右侧处理完之后 + nums[k] = temp[i] + i += 1 + elif temp[i] <= temp[j]:#前边的小,不用计数,将前边的值归并到temp中 + nums[k] = temp[i] + i += 1 + else: + nums[k] = temp[j]#后边的小,将后边的值归并到tmp中,累计计数值 + j += 1 + count += (mid - i + 1)# + return count + + +s = Solution() +res = s.reversePairs(nums=[5,2,6,1]) +print(res) \ No newline at end of file diff --git "a/Week08/\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.py" "b/Week08/\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.py" new file mode 100644 index 000000000..3ee814bba --- /dev/null +++ "b/Week08/\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.py" @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/2 11:00 AM + +from typing import List +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + # 双指针,左指针向后找不在arr2中的元素,右指针向前找到在arr2中的元素,交换left++right + hashmap = {} + for i, num in enumerate(arr1): + hashmap[num] = hashmap.get(num,0) + 1 + ind = 0 + for i in range(len(arr2)): + cur = arr2[i] + while hashmap.get(cur) > 0: + arr1[ind] = cur + hashmap[cur] -= 1 + ind += 1 + # 将不在arr2中的元素升序排列,如何保证升序??? + print(hashmap) + tmp = [] + for key, val in hashmap.items(): + # if val > 0: + while val > 0 : + tmp.append(key) + hashmap[key] -= 1 + val -= 1 + tmp.sort() + print('tmp',tmp) + return arr1[:ind] + tmp + # +s = Solution() +# nums1 = [2,3,1,3,2,4,6,7,9,2,19] +# nums2 = [2,1,4,3,9,6] +# [2,42,38,0,43,21,5,7,12,12,13,23,24,24,27,29,30,31,33,48] +nums1 = [2,21,43,38,0,42,33,7,24,13,12,27,12,24,5,23,29,48,30,31] +nums2 = [2,42,38,0,43,21] +res = s.relativeSortArray(nums1,nums2) +print(res) \ No newline at end of file diff --git "a/Week08/\346\225\264\346\225\260\346\213\206\345\210\206.py" "b/Week08/\346\225\264\346\225\260\346\213\206\345\210\206.py" new file mode 100644 index 000000000..8b4e9624a --- /dev/null +++ "b/Week08/\346\225\264\346\225\260\346\213\206\345\210\206.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/30 7:58 PM + +from functools import lru_cache +class Solution: + @lru_cache + def integerBreak(self, n: int) -> int: + # 怎么感觉又是零钱兑换、背包问题 + res = 0 + for i in range(1, n-1): + res = max(res, (n-i)*i, i * self.integerBreak(n-i)) + return res + # f(n) = f(n-1,1) f(n-2,2) f(n-3,3) + # dp = [1] * (n + 1) + # for i in range(3, n + 1): + # for j in range(1, i): + # dp[i] = max(dp[i], max(dp[j], j) * (i - j)) + # return dp[-1] + + + +s = Solution() +res = s.integerBreak(10) +print(res) \ No newline at end of file diff --git "a/Week08/\346\235\250\350\276\211\344\270\211\350\247\222.py" "b/Week08/\346\235\250\350\276\211\344\270\211\350\247\222.py" new file mode 100644 index 000000000..bb2eadc3f --- /dev/null +++ "b/Week08/\346\235\250\350\276\211\344\270\211\350\247\222.py" @@ -0,0 +1,28 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/1 11:30 PM + +from typing import List + + +class Solution: + + def generate(self, rows: int) -> List[List[int]]: + dp = [[0]* rows for _ in range(rows)] + for row in range(rows): + dp[row][0] = 1 + for i in range(1,rows): + for j in range(rows): + if i-1 >= 0: + dp[i][j] = dp[i-1][j-1] + dp[i-1][j] + + for i in range(rows): + #第0行pop四个,第1行pop3个、2 2 、3 1 4,0 + tmp = rows-i-1 + for i in range(tmp): + dp[i].pop() + return dp + +s = Solution() +res = s.generate(5) +print(res,'\n') \ No newline at end of file diff --git "a/Week08/\346\235\250\350\276\211\344\270\211\350\247\222II.py" "b/Week08/\346\235\250\350\276\211\344\270\211\350\247\222II.py" new file mode 100644 index 000000000..be4352ff4 --- /dev/null +++ "b/Week08/\346\235\250\350\276\211\344\270\211\350\247\222II.py" @@ -0,0 +1,55 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/1 11:47 PM + +from typing import List + + +class Solution: + + def generate(self, rows: int) -> List[List[int]]: + # dp = [[0]* rows for _ in range(rows)] + # for row in range(rows): + # dp[row][0] = 1 + # for i in range(1,rows): + # for j in range(rows): + # if i-1 >= 0: + # dp[i][j] = dp[i-1][j-1] + dp[i-1][j] + # + # for i in range(rows): + # #第0行pop四个,第1行pop3个、2 2 、3 1 4,0 + # tmp = rows-i-1 + # for i in range(tmp): + # dp[i].pop() + # return dp + #这里只用返回第k行 想办法优化到O(K),每次在dp上覆盖修改 + # [1] + # [1, 1] + # [1, 2, 1] + # [1, 3, 3, 1] + # [1, 5, 10, 10, 5, 1] + # dp = [0] * (rows+1) + # dp[0] = 1 + # print(dp) + # for i in range(1, rows+1): + # for j in range(1, i):#2 + # dp[j] = dp[j]+dp[j-1]# + # print(dp) + # dp[i] = 1 + # return dp + dp = [1] * (rows + 1) + for i in range(2, rows + 1): + for j in range(i - 1, 0, -1):#首尾的1,不用更新 + dp[j] += dp[j - 1] + return dp + # dp =[1] + # for i in range(1, rows + 1): + # dp.append(0) + # for j in range(1, i + 1): + # dp[-j] = dp[-j] + dp[-j - 1] + # print(dp) + # return dp + +s = Solution() +res = s.generate(3) +# print(res) \ No newline at end of file diff --git "a/Week08/\346\257\224\347\211\271\344\275\215\350\256\241\346\225\260.py" "b/Week08/\346\257\224\347\211\271\344\275\215\350\256\241\346\225\260.py" new file mode 100644 index 000000000..34ab42395 --- /dev/null +++ "b/Week08/\346\257\224\347\211\271\344\275\215\350\256\241\346\225\260.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 9:46 PM + +class Solution: + def countBits(self, num: int) -> List[int]: + # res = [] + # for i in range(num+1): + # count = 0 + # while i!=0: + # i = i &(i-1)#消除末尾1 + # count += 1 + # res.append(count) + # return res + #动态规划 dp[n] = dp[n//2] + 1 if odd else + 0 + dp = [0] * (num + 1) + for i in range(1, num + 1): # 0不用处理 + dp[i] = dp[i >> 1] + (i & 1) + return dp \ No newline at end of file diff --git "a/Week08/\347\277\273\350\275\254\345\257\271.py" "b/Week08/\347\277\273\350\275\254\345\257\271.py" new file mode 100644 index 000000000..74788bddd --- /dev/null +++ "b/Week08/\347\277\273\350\275\254\345\257\271.py" @@ -0,0 +1,34 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/2 12:32 PM + + +# from typing import List +# +# +# class Solution: +# +# def reversePairs(self, nums: List[int]) -> int: +# return self.mergeSort(nums, 0, len(nums) - 1) +# +# def mergeSort(self, nums, l, r): +# if l >= r: +# return 0 +# mid = l + ((r - l) >> 1) +# left = self.mergeSort(nums, l, mid) +# right = self.mergeSort(nums, mid + 1, r) +# return self.merge(nums, l, mid, r) + left + right +# +# def merge(self, nums, l, mid, r): +# # 找翻转对的代码 +# ans = 0 +# i, j = l, mid + 1 +# while i <= mid and j <= r: +# if (nums[i] + 1) >> 1 > nums[j]: +# ans += (mid - i + 1) +# j += 1 +# else: +# i += 1 +# nums[l:r + 1] = sorted(nums[l:r + 1]) +# return ans + diff --git "a/Week08/\350\256\241\347\256\227\345\217\263\344\276\247\345\260\217\344\272\216\345\275\223\345\211\215\345\205\203\347\264\240\347\232\204\344\270\252\346\225\260.py" "b/Week08/\350\256\241\347\256\227\345\217\263\344\276\247\345\260\217\344\272\216\345\275\223\345\211\215\345\205\203\347\264\240\347\232\204\344\270\252\346\225\260.py" new file mode 100644 index 000000000..89ccc5e09 --- /dev/null +++ "b/Week08/\350\256\241\347\256\227\345\217\263\344\276\247\345\260\217\344\272\216\345\275\223\345\211\215\345\205\203\347\264\240\347\232\204\344\270\252\346\225\260.py" @@ -0,0 +1,75 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/2 10:13 PM + + +from typing import List +from typing import List + + +class Solution: + + def countSmaller(self, nums: List[int]) -> List[int]: + size = len(nums) + if size == 0: return [] + if size == 1: return [0] + + tmp = [None for _ in range(size)] + res = [0 for _ in range(size)] + # 索引数组,作用:归并回去的时候,方便知道是哪个下标的元素 + indexes = [i for i in range(size)] + + self.__merge_and_count_smaller(nums, 0, size - 1, tmp, indexes, res) + return res + + def __merge_and_count_smaller(self, nums, left, right, temp, indexes, res): + if left == right: + return + mid = left + (right - left) // 2 + self.__merge_and_count_smaller(nums, left, mid, temp, indexes, res) + self.__merge_and_count_smaller(nums, mid + 1, right, temp, indexes, res) + + if nums[indexes[mid]] <= nums[indexes[mid + 1]]: + return + self.__sort_and_count_smaller(nums, left, mid, right, temp, indexes, res) + + def __sort_and_count_smaller(self, nums, left, mid, right, temp, indexes, res): + # [left,mid] 前有序数组 + # [mid+1,right] 后有序数组 + + # 先拷贝,再合并 + for i in range(left, right + 1): + temp[i] = indexes[i] + + i = left + j = mid + 1 + for k in range(left, right + 1): + if i > mid: + indexes[k] = temp[j] + j += 1 + elif j > right: + indexes[k] = temp[i] + i += 1 + res[indexes[k]] += (right - mid) + elif nums[temp[i]] <= nums[temp[j]]: + indexes[k] = temp[i] + i += 1 + res[indexes[k]] += (j - mid - 1) + else: + indexes[k] = temp[j] + j += 1 + + +if __name__ == '__main__': + nums = [5, 2, 6, 1] + solution = Solution() + result = solution.countSmaller(nums) + print(result) + +s = Solution() +res = s.reversePairs(nums=[5,2,6,1]) +print(res) + + + + diff --git "a/Week08/\351\200\211\346\213\251\346\216\222\345\272\217.py" "b/Week08/\351\200\211\346\213\251\346\216\222\345\272\217.py" new file mode 100644 index 000000000..1f0e8cc09 --- /dev/null +++ "b/Week08/\351\200\211\346\213\251\346\216\222\345\272\217.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/28 8:17 PM + + +# 选择排序的思想是分作AB两区,A一直有序,每次从B中取出最小的元素,放在A区 +class Solution: + def insertsort(self,nums): + for i in range(len(nums)-1): + min_loc = i + for j in range(i+1,len(nums)):#找到B区最小的元素 + if nums[min_loc] > nums[j]: + min_loc = j + nums[i],nums[min_loc] = nums[min_loc],nums[i] + +s = Solution() +nums = [2,3,1,4,2,5,6,8,6,5,7] +s.insertsort(nums) +print(nums) \ No newline at end of file diff --git "a/Week08/\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.py" "b/Week08/\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.py" new file mode 100644 index 000000000..1a1a32529 --- /dev/null +++ "b/Week08/\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.py" @@ -0,0 +1,16 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/27 9:13 PM + +class Solution: + def reverseBits(self, n: int) -> int: + # 脱裤子放屁 + # tmp = bin(n)[2:].zfill(32) + # return int(tmp[::-1],2) + # 逐位颠倒 + res, bits = 0, 31 + while n!=0: + res += (n&1)<>1 + bits -= 1 + return res diff --git "a/Week09/[100]\347\233\270\345\220\214\347\232\204\346\240\221.py" "b/Week09/[100]\347\233\270\345\220\214\347\232\204\346\240\221.py" new file mode 100644 index 000000000..d5be784b5 --- /dev/null +++ "b/Week09/[100]\347\233\270\345\220\214\347\232\204\346\240\221.py" @@ -0,0 +1,18 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/7 10:47 PM + + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: + if not p and not q: return True + if not p or not q: return False + if p.val!=q.val: return False + else: + return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right) \ No newline at end of file diff --git "a/Week09/[1114]\345\244\232\347\272\277\347\250\213\344\271\213\346\214\211\345\272\217\346\211\223\345\215\260.py" "b/Week09/[1114]\345\244\232\347\272\277\347\250\213\344\271\213\346\214\211\345\272\217\346\211\223\345\215\260.py" new file mode 100644 index 000000000..391cde6cf --- /dev/null +++ "b/Week09/[1114]\345\244\232\347\272\277\347\250\213\344\271\213\346\214\211\345\272\217\346\211\223\345\215\260.py" @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/18 11:08 PM + +from threading import Lock +class Foo: + def __init__(self): + self.firstJob = Lock() + self.secondJob = Lock() + self.firstJob.acquire() + self.secondJob.acquire() + + def first(self, printFirst: 'Callable[[], None]') -> None: + # printFirst() outputs "first". Do not change or remove this line. + printFirst() + self.firstJob.release() + + def second(self, printSecond: 'Callable[[], None]') -> None: + with self.firstJob:#请求锁 + # printSecond() outputs "second". Do not change or remove this line. + printSecond() + self.secondJob.release() + + def third(self, printThird: 'Callable[[], None]') -> None: + with self.secondJob: + # printThird() outputs "third". Do not change or remove this line. + printThird() \ No newline at end of file diff --git "a/Week09/[1116]\345\244\232\347\272\277\347\250\213\344\271\213\344\272\244\345\217\211\346\211\223\345\215\260\345\245\207\345\201\266\345\200\274.py" "b/Week09/[1116]\345\244\232\347\272\277\347\250\213\344\271\213\344\272\244\345\217\211\346\211\223\345\215\260\345\245\207\345\201\266\345\200\274.py" new file mode 100644 index 000000000..150b80024 --- /dev/null +++ "b/Week09/[1116]\345\244\232\347\272\277\347\250\213\344\271\213\344\272\244\345\217\211\346\211\223\345\215\260\345\245\207\345\201\266\345\200\274.py" @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/18 11:24 PM + + +from threading import Lock + + +class ZeroEvenOdd: + def __init__(self, n): + self.n = n + self.zero_lock = Lock() + self.even_lock = Lock() + self.odd_lock = Lock() + self.even_lock.acquire() + self.odd_lock.acquire() + + # printNumber(x) outputs "x", where x is an integer. + def zero(self, printNumber: 'Callable[[int], None]') -> None: + for i in range(1, self.n + 1): + self.zero_lock.acquire() + printNumber(0) + if i & 1: + self.odd_lock.release() + else: + self.even_lock.release() + + def even(self, printNumber: 'Callable[[int], None]') -> None: + for i in range(1, self.n + 1): + if i & 1 == 0: + self.even_lock.acquire() + printNumber(i) + self.zero_lock.release() + + def odd(self, printNumber: 'Callable[[int], None]') -> None: + for i in range(1, self.n + 1): + if i & 1: + self.odd_lock.acquire() + printNumber(i) + self.zero_lock.release() \ No newline at end of file diff --git "a/Week09/[1143]\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.py" "b/Week09/[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..64ec31564 --- /dev/null +++ "b/Week09/[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,19 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 5:16 PM + +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + # 看题目和之前那道最长公共回文串,很类似,这里用动态规划做, + # 但是要注意 这里是最长公共子序列,是可以间断的 + if not text1 and not text2: return 0 + m, n = len(text1), len(text2) + dp = [[0]*(n+1) for _ in range(m+1)] + for i in range(1,m+1): + for j in range(1,n+1): + if text1[i-1] == text2[j-1]: + dp[i][j] = dp[i-1][j-1] + 1 + else: + dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + return dp[-1][-1] + diff --git "a/Week09/[120]\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" "b/Week09/[120]\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" new file mode 100644 index 000000000..4f03a9f9f --- /dev/null +++ "b/Week09/[120]\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" @@ -0,0 +1,36 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/3 1:57 AM + +from typing import List +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + # 分治 递归模板 + # from functools import lru_cache + # @lru_cache(None) + # def dfs(i, j): + # #terminator + # if i == size-1: return triangle[i][j] + # left = dfs(i+1,j)#加左边的值 + # right = dfs(i+1,j+1) + # min_val = min(left, right) + triangle[i][j] + # return min_val + # size = len(triangle) + # return dfs(0,0) + # 2.top-down + # if not triangle: return + # dp = triangle + # for i in range(1, len(triangle)): + # for j in range(len(triangle[i])): + # if j == 0: + # dp[i][j] += triangle[i-1][j] + # elif j == len(triangle[i])-1: + # dp[i][j] += triangle[i-1][j-1] + # else: + # dp[i][j] += min(triangle[i-1][j-1], triangle[i-1][j]) + # return min(dp[-1]) + # 3.bottom-up + for i in range(len(triangle) - 2, -1, -1): + for j in range(len(triangle[i])): + triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]) + return triangle[0][0] diff --git "a/Week09/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" "b/Week09/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" new file mode 100644 index 000000000..eb6b16f9c --- /dev/null +++ "b/Week09/[125]\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 1:31 PM + +class Solution: + def isPalindrome(self, s: str) -> bool: + # tmp = ''.join(ch.lower() for ch in s if ch.isalnum()) + # return tmp == tmp[::-1] + tmp = ''.join(ch.lower() for ch in s if ch.isalnum()) + # print(tmp) + left, right = 0, len(tmp)-1 + while left <= right: + if tmp[left] != tmp[right]: + return False + left, right = left + 1, right - 1 + return True +s = Solution() +strs = "A man, a plan, a canal: Panama" +res = s.isPalindrome(strs) +print(res) \ No newline at end of file diff --git "a/Week09/[151]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.py" "b/Week09/[151]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.py" new file mode 100644 index 000000000..79efa2e56 --- /dev/null +++ "b/Week09/[151]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.py" @@ -0,0 +1,16 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 10:27 AM + + +class Solution: + def reverseWords(self, s: str) -> str: + # #要注意到原字符串两边的空格以及 单词之间多余1的空格 + # tmp = s.split(' ') + # #删除多余的空格 + # tmp = [] + [item for item in tmp if item!=''] + # # tmp = s.strip().split(' ') + # tmp = list(reversed(tmp)) + # res = ' '.join(tmp ) + # return res + return " ".join(reversed(s.split()))#split()不加参数会把结果中的' '删除 \ No newline at end of file diff --git "a/Week09/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" "b/Week09/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" new file mode 100644 index 000000000..6de4822bb --- /dev/null +++ "b/Week09/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" @@ -0,0 +1,14 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 11:10 AM + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + hashmap = {} + for ch in s: + hashmap[ch] = hashmap.get(ch,0) + 1 + for ch in t: + hashmap[ch] = hashmap.get(ch,0) - 1 + for key,val in hashmap.items(): + if val != 0: return False + return True \ No newline at end of file diff --git "a/Week09/[300]\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.py" "b/Week09/[300]\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.py" new file mode 100644 index 000000000..6a20204ab --- /dev/null +++ "b/Week09/[300]\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.py" @@ -0,0 +1,54 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/4 1:39 AM + +from typing import List + + +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + # dp + # if not nums: return 0 + # dp = [1]*len(nums) + # 其实说白了就是暴力法的另外一种写法 + # 枚举起始点,看以它为终点的位置 上升子序列长度是多少,只不过比平常的暴力解法还是稍微简单一些 + # 以nums[i]为尾元素的最大子序列长度 + # for i in range(len(nums)): + # for j in range(i): + # if nums[i] > nums[j]: + # dp[i] = max(dp[i],dp[j]+1) + # return max(dp) + size = len(nums) + if size < 2: return size + tmp = [nums[0]] # 维护一个单调栈 + # 遍历数组,如果比末尾元素大,加入,如果小于等于 找到第一个比他大的数,替换掉 + for num in nums[1:]: + if num > tmp[-1]: + tmp.append(num) + # [2,2,4] 3 + else: # 在有序数组中找到第一个比num大的位置 + left, right = 0,len(tmp)-1 + while left <= right: + mid = left + ((right-left)//2) + if tmp[mid] >= num: + if mid == 0 or tmp[mid-1] < num: + tmp[mid] = num + break + else: right = mid - 1 + else: + left = mid + 1 + + # for i in range(len(tmp)): + # if tmp[i] == num: + # break + # elif tmp[i] > num: + # tmp[i] = num + # break + print(tmp) + return len(tmp) + +s = Solution() +# nums = [10,9,2,5,3,7,101,18] +nums = [4,10,4,3,8,9] +res = s.lengthOfLIS(nums) +print(res) \ No newline at end of file diff --git "a/Week09/[344]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.py" "b/Week09/[344]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.py" new file mode 100644 index 000000000..2e3e92836 --- /dev/null +++ "b/Week09/[344]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1,15 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/7 10:44 PM + +class Solution: + def reverseString(self, strs: List[str]) -> None: + """ + Do not return anything, modify s in-place instead. + """ + size = len(strs) + left, right = 0, size-1 + while left < right: + strs[left],strs[right] = strs[right],strs[left] + left, right = left + 1, right - 1 + return strs \ No newline at end of file diff --git "a/Week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.py" "b/Week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.py" new file mode 100644 index 000000000..df5d2c9d2 --- /dev/null +++ "b/Week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/5 12:31 AM + +class Solution: + def firstUniqChar(self, s: str) -> int: + hashmap = {} + for ch in s: + hashmap[ch] = hashmap.get(ch, 0) + 1 + for i in range(len(s)): + if hashmap.get(s[i]) == 1: + return i + return -1 + # 这里我是用hashmap中times=1的ch反向查找字符串 这里的时间复杂度就是O(MN)了 + # tmp = '' + # for ch, times in hashmap.items(): + # if times == 1: + # tmp = ch + # break + # if not tmp: + # return -1 + # else: + # return s.index(ch) + # 更好的做法应该是再遍历字符串,检查其times是否为1即可 + + diff --git "a/Week09/[41]\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260.py" "b/Week09/[41]\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260.py" new file mode 100644 index 000000000..8341d12bc --- /dev/null +++ "b/Week09/[41]\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260.py" @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/6 7:44 PM + +from typing import List +class Solution: + def firstMissingPositive(self, nums: List[int]) -> int: + # if not nums: return 1 + # hashmap = {} + # max_val = float('-inf') + # for num in nums: + # if num > 0: + # hashmap[num] = hashmap.get(num,0)+1 + # if num > max_val: + # max_val = num + # if not hashmap: return 1 + # for num in range(1,max_val): + # if not hashmap.get(num): + # return num + # return max_val + 1 + + size = len(nums) + for i in range(size):#将所有负值赋值为N+1 + if nums[i] <= 0: + nums[i] = size + 1#后面不需要管这些显然大于数组长度的数值 + for i in range(size): + ind = abs(nums[i]) + if ind <= size: + nums[ind - 1] = -abs(nums[ind - 1]) + for i in range(size): + if nums[i] > 0: + return i + 1 + + return size + 1 + + # print(nums) +s = Solution() +nums = [-1,2,1,4,6,7] +print(nums) +s.firstMissingPositive(nums) diff --git "a/Week09/[438]\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" "b/Week09/[438]\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" new file mode 100644 index 000000000..0413be58f --- /dev/null +++ "b/Week09/[438]\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.py" @@ -0,0 +1,63 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 11:37 AM + +from typing import List +class Solution: + def findAnagrams(self, s: str, p: str) -> List[int]: + #n个a,a 超时,这个过程不断的取一截,就很费操作 + # 用滑动窗口试一下 + m, n = len(s), len(p) + res = [] + for i in range(m-n+1): + cur = s[i:i+n] + #判断此时的cur和p是否是异位词 + if self.isAngrams(cur,p): res.append(i) + return res + def isAngrams(self,s,p): + hashmap = {} + for ch in s: + hashmap[ch] = hashmap.get(ch,0) + 1 + for ch in p: + hashmap[ch] = hashmap.get(ch,0) - 1 + for key,value in hashmap.items(): + if value !=0 : return False + return True + + def findAnagramsI(self, s: str, p: str) -> List[int]: + from collections import deque + m, n = len(s), len(p) + hashmap = {} + for ch in p: + hashmap[ch] = hashmap.get(ch,0) + 1 + quene = deque()# 滑动窗口 + hashmap1 = {} + res = [] + # s: "cbaebabacd" + # p: "abc" + for i in range(m+1): + if len(quene) == n: + if hashmap == hashmap1: + res.append(i-n) + left = quene[0] + if hashmap1[left] > 1: + hashmap1[left] -= 1 + else: + del hashmap1[left] + quene.popleft() + if i < m: + ch = s[i] + quene.append(ch) + hashmap1[ch] = hashmap1.get(ch, 0) + 1 + return res +s = Solution() +# s1 = "cbaebabacdc" +# s2 = "abc" +s1 = "abab" +s2 = "ab" +res = s.findAnagramsI(s1,s2) +print(res) + + + + diff --git "a/Week09/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" "b/Week09/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" new file mode 100644 index 000000000..06aecf8e1 --- /dev/null +++ "b/Week09/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" @@ -0,0 +1,12 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 11:21 AM + +class Solution(object): + def groupAnagrams(self, strs): + hashmap = {} + for ch in strs: + cur = ''.join(sorted(ch)) + hashmap[cur] = hashmap.get(cur,[]) + [ch] + # print(hashmap) + return [hashmap[item] for item in hashmap] \ No newline at end of file diff --git "a/Week09/[518]\351\233\266\351\222\261\345\205\221\346\215\242II.py" "b/Week09/[518]\351\233\266\351\222\261\345\205\221\346\215\242II.py" new file mode 100644 index 000000000..4dc54a142 --- /dev/null +++ "b/Week09/[518]\351\233\266\351\222\261\345\205\221\346\215\242II.py" @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/5 9:11 PM + + +from typing import List +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + dp = [[0] * (amount + 1) for i in range(len(coins) + 1)] + #进行初始化 + for i in range(len(coins) + 1): + dp[i][0] = 1 + for i in range(1,len(coins) + 1): + for j in range(1, amount + 1): + if j >= coins[i-1]: + dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i-1]] + else: + dp[i][j] = dp[i - 1][j] + return dp[-1][-1] + # dp = [0] * (amount+1) + # dp[0] = 1 + # for coin in coins:#[1,2,5] + # for i in range(coin,amount+1): + # dp[i] += dp[i-coin] + # return dp[-1] + +s = Solution() +coins = [1,101,102,103] +res = s.change(100,coins) +print(res) diff --git "a/Week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.py" "b/Week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.py" new file mode 100644 index 000000000..97171234d --- /dev/null +++ "b/Week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.py" @@ -0,0 +1,12 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 10:27 AM + + +class Solution: + def reverseStr(self, s: str, k: int) -> str: + #每隔2k个元素就将前k个元素逆序存到res中 + a = list(s) + for i in range(0, len(a), 2*k):#将步长设置为2k即可 + a[i:i+k] = reversed(a[i:i+k]) + return "".join(a) \ No newline at end of file diff --git "a/Week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215III.py" "b/Week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215III.py" new file mode 100644 index 000000000..15c6926a7 --- /dev/null +++ "b/Week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215III.py" @@ -0,0 +1,11 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 10:52 AM + +# 组内翻转单词 + +class Solution: + def reverseWords(self, s: str) -> str: + s = s.split() + res= [''.join(reversed(item)) for item in s] + return ' '.join(res) \ No newline at end of file diff --git "a/Week09/[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/Week09/[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..c7c4e1b40 --- /dev/null +++ "b/Week09/[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,22 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/4 11:52 PM + +class Solution: + def lengthOfLastWord(self, s: str) -> int: + # s = s.split() + # if not s: return 0 #去除全部是空格 + # return len(s[-1]) + p1 = len(s)-1 + while p1 >= 0 and s[p1] == ' ':#先略过末尾的空格 + p1 -= 1 + if p1 == -1: return 0#全部为空格 + p2 = p1 + while p2 >= 0 and s[p2] != ' ':#从后向前找到第一个不为空格的字符 + p2 -= 1 + return p1 - p2 + +s = Solution() +strs = "Hello World " +res = s.lengthOfLastWord(strs) +print(res) \ No newline at end of file diff --git "a/Week09/[647]\345\233\236\346\226\207\345\255\220\344\270\262.py" "b/Week09/[647]\345\233\236\346\226\207\345\255\220\344\270\262.py" new file mode 100644 index 000000000..93068c6ae --- /dev/null +++ "b/Week09/[647]\345\233\236\346\226\207\345\255\220\344\270\262.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/19 12:52 AM + +class Solution: + def countSubstrings(self, s: str) -> int: + if not s: return 0 + size = len(s) + dp = [[True]*size for i in range(size)] + count = 0 + for l in range(size): + for i in range(size): + j = i + l + if j >= size: break + if l == 0: dp[i][j] = True + elif l == 1: dp[i][j] = (s[i]==s[j]) + else: + dp[i][j] = (dp[i+1][j-1] and s[i] == s[j]) + if dp[i][j]: + count += 1 + return count \ No newline at end of file diff --git "a/Week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262II.py" "b/Week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262II.py" new file mode 100644 index 000000000..7843133c3 --- /dev/null +++ "b/Week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262II.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 1:37 PM + +class Solution: + def validPalindrome(self, s: str) -> bool: + # pass + # 左右指针对撞, 如果 相同就向中心靠拢 + # 如果不等,就left++ 或者right--,判断是否是回文 + def check(left, right): + while left <= right: + if s[left] != s[right]: + return False + left, right = left + 1, right - 1 + return True + + left, right = 0, len(s) - 1 + while left <= right: + if s[left] == s[right]: + left, right = left + 1, right - 1 + else: + return check(left + 1, right) or check(left, right - 1) + return True + diff --git "a/Week09/[696]\350\256\241\346\225\260\344\272\214\350\277\233\345\210\266\345\255\220\344\270\262.py" "b/Week09/[696]\350\256\241\346\225\260\344\272\214\350\277\233\345\210\266\345\255\220\344\270\262.py" new file mode 100644 index 000000000..fdae3aadd --- /dev/null +++ "b/Week09/[696]\350\256\241\346\225\260\344\272\214\350\277\233\345\210\266\345\255\220\344\270\262.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/10 11:01 PM + +class Solution: + def countBinarySubstrings(self, s: str) -> int: + count = [1] + j = 0 + for i in range(1, len(s)): # 统计连续的频数 + if s[i] == s[i - 1]: + count[j] += 1 + else: + count.append(1) + j += 1 + res = 0 + for k in range(1, len(count)): + res += min(count[k], count[k - 1]) # 取相邻频数的最小值 + return res + +s = Solution() +strs = "001110011" +res = s.countBinarySubstrings(strs) +print(res) + diff --git "a/Week09/[709]\350\275\254\346\215\242\346\210\220\345\260\217\345\206\231\345\255\227\346\257\215.py" "b/Week09/[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..e4d0b2463 --- /dev/null +++ "b/Week09/[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,17 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/4 11:26 PM + +class Solution: + def toLowerCase(self, str: str) -> str: + # return str.lower() + # A 65 a 97 差32 '0'的ascii 为48 + # ord('x')-->ascii值 + # chr(ascii值)-->str + res = '' + for i in range(len(str)): + if 65<= ord(str[i]) < 97: + res += chr(ord(str[i])+32) + else: + res += str[i] + return res \ No newline at end of file diff --git "a/Week09/[718]\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" "b/Week09/[718]\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" new file mode 100644 index 000000000..4f725a0a0 --- /dev/null +++ "b/Week09/[718]\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204.py" @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 6:42 PM + + +from typing import List +class Solution: + def findLength(self, A: List[int], B: List[int]) -> int: + def maxLength(addA: int, addB: int, length: int) -> int: + ret = k = 0 + for i in range(length): + if A[addA + i] == B[addB + i]: + k += 1 + ret = max(ret, k) + else: + k = 0 + return ret + + n, m = len(A), len(B) + ret = 0 + for i in range(n): + length = min(m, n - i) + ret = max(ret, maxLength(i, 0, length)) + for i in range(m): + length = min(n, m - i) + ret = max(ret, maxLength(0, i, length)) + return ret diff --git "a/Week09/[72]\347\274\226\350\276\221\350\267\235\347\246\273.py" "b/Week09/[72]\347\274\226\350\276\221\350\267\235\347\246\273.py" new file mode 100644 index 000000000..103787dca --- /dev/null +++ "b/Week09/[72]\347\274\226\350\276\221\350\267\235\347\246\273.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/3 1:20 AM + + +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + m, n = len(word1), len(word2) + dp = [[0]*(n+1) for _ in range(m+1)] + #dp[i][j]表示word1[:i]到word2[:j]的编辑距离 + for i in range(1,m+1): + dp[i][0] = i + for j in range(1,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] = min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])+1 + return dp[-1][-1] \ No newline at end of file diff --git "a/Week09/[746]\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.py" "b/Week09/[746]\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.py" new file mode 100644 index 000000000..f57ab371c --- /dev/null +++ "b/Week09/[746]\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.py" @@ -0,0 +1,16 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/4 1:02 AM + +class Solution: + def minCostClimbingStairs(self, cost: List[int]) -> int: + size = len(cost) + # if size <= 2: return min(cost) + # dp = [0] * size + # dp[0], dp[1] = cost[0], cost[1] + # for i in range(2,size):#要想到达最后一位,只可能是从i-1和i-2来的,所以总共的开销如下 + # dp[i] = min(dp[i-1],dp[i-2])+cost[i]#到达i处花费的最少开销 + # return min(dp[-1],dp[-2]) + for i in range(2,size): + cost[i] = min(cost[i-1],cost[i-2]) + cost[i] + return min(cost[-1],cost[-2]) \ No newline at end of file diff --git "a/Week09/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" "b/Week09/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" new file mode 100644 index 000000000..b922f32e0 --- /dev/null +++ "b/Week09/[771]\345\256\235\347\237\263\344\270\216\347\237\263\345\244\264.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/5 12:14 AM + + +class Solution: + def numJewelsInStones(self, J: str, S: str) -> int: + # 暴力法 + # count = 0 + # for ch in J: + # count += S.count(ch) + # return count + # hash表记录宝石 遍历待查字符串 这种题hash表解法一定不能忘!!!!!!!!! + hashmap = set() + count = 0 + for ch in J: + hashmap.add(ch) + for ch in S: + if ch in hashmap: + count += 1 + return count \ No newline at end of file diff --git "a/Week09/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\225\264\346\225\260.py" "b/Week09/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\225\264\346\225\260.py" new file mode 100644 index 000000000..18e58dc89 --- /dev/null +++ "b/Week09/[8]\345\255\227\347\254\246\344\270\262\350\275\254\346\225\264\346\225\260.py" @@ -0,0 +1,18 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/5 12:37 AM + +class Solution: + def myAtoi(self, strs: str) -> int: + res, sign = 0, 1 + strs = strs.strip() + for i in range(len(strs)): + ch = strs[i] + if i == 0 and (ch == '-' or ch == '+'): + if ch == '-': sign = -1 + if ch == '+': sign = 1 + continue # 应对-123,是+-号之后就不用判断是否数字了 + if not ch.isdigit(): break # 如果不是数字 + res = 10 * res + ord(ch) - ord('0') + # 如果下越界 就返回-2**31 如果上越界返回2**31-1 + return max(-2 ** 31, -1 * res) if sign == -1 else min(2 ** 31 - 1, res) diff --git "a/Week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.py" "b/Week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.py" new file mode 100644 index 000000000..b85e6707c --- /dev/null +++ "b/Week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.py" @@ -0,0 +1,17 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/8 11:08 AM + + +class Solution: + def reverseOnlyLetters(self, strs: str) -> str: + tmp = list(strs) + left, right = 0, len(strs) - 1 + while left < right: + while left < right and not tmp[left].isalpha(): + left = left + 1 + while left < right and not tmp[right].isalpha(): + right = right - 1 + tmp[left], tmp[right] = tmp[right], tmp[left] + left, right = left + 1, right - 1 + return ''.join(tmp) \ No newline at end of file diff --git "a/Week09/[93]\345\244\215\345\216\237IP\345\234\260\345\235\200.py" "b/Week09/[93]\345\244\215\345\216\237IP\345\234\260\345\235\200.py" new file mode 100644 index 000000000..e8176065f --- /dev/null +++ "b/Week09/[93]\345\244\215\345\216\237IP\345\234\260\345\235\200.py" @@ -0,0 +1,78 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/14 10:28 PM + +from typing import List + + +class Solution: + def restoreIpAddresses(self, s: str) -> List[str]: + size = len(s) + if size < 4 or size > 12: + return [] + path = [] + res = [] + self.__dfs(s, size, 0, 0, path, res) + return res + + def __dfs(self, s, size, split_times, begin, path, res): + if begin == size: + if split_times == 4: + res.append('.'.join(path)) + return + # 如果剩余长度不够划分、如果剩余长度太长 + if size - begin < (4 - split_times) or size - begin > 3 * (4 - split_times): + return + for i in range(3): + if begin + i >= size: + break + ip_segment = self.__judge_if_ip_segment(s, begin, begin + i) + if ip_segment != -1: + path.append(str(ip_segment)) + self.__dfs(s, size, split_times + 1, begin + i + 1, path, res) + path.pop() + + def __judge_if_ip_segment(self, s, left, right): + size = right - left + 1 + if size > 1 and s[left] == '0': + return -1 + res = int(s[left:right + 1]) + if res > 255: + return - 1 + return res + + +class SolutionI: + def restoreIpAddresses(self, s: str) -> List[str]: + # 定义查找符合条件的数字个数 + def _dfs(start, path): + # recursion terminator + # 如果ip地址已4位,但字符串没用尽,不符合题目意思 + if len(path) == 4 and start < len(s)-1: + return + # 什么时候加入到res中??? 当整个字符串已经遍历完成的时候 + if start>=len(s): + if len(path) == 4: + res.append('.'.join(path)) + return + # 如果当前位为0,不能扩展 + # 下面的层数返回结果,此时0不能向右扩展,只能向上return + if s[start] == '0': + path.append(s[start]) + _dfs(start+1, path) + path.pop() + return + for i in range(start,len(s)): + if 0 <= int(s[start:i+1]) <= 255: + path.append(s[start:i+1]) + _dfs(i+1,path) + path.pop() + else: + break #后面的不用再继续判断 + res = [] + _dfs(0,[]) + return res + +s = Solution() +res = s.restoreIpAddresses("25525511135") +print(res) diff --git "a/Week09/\344\272\214\345\210\206\346\237\245\346\211\276\347\273\217\345\205\270\351\242\230\347\233\256.md" "b/Week09/\344\272\214\345\210\206\346\237\245\346\211\276\347\273\217\345\205\270\351\242\230\347\233\256.md" new file mode 100644 index 000000000..a0f12007f --- /dev/null +++ "b/Week09/\344\272\214\345\210\206\346\237\245\346\211\276\347\273\217\345\205\270\351\242\230\347\233\256.md" @@ -0,0 +1,10 @@ + +#### 二分查找模板 + +#### 查找第一个值等于给定值的元素 + +#### 查找最后一个值等于给定值的元素 + +#### 查找第一个大于等于给定值的元素 + +#### 查找最后一个小于等于给定值的元素 diff --git "a/Week09/\345\212\250\346\200\201\350\247\204\345\210\222.md" "b/Week09/\345\212\250\346\200\201\350\247\204\345\210\222.md" new file mode 100644 index 000000000..3a2da7120 --- /dev/null +++ "b/Week09/\345\212\250\346\200\201\350\247\204\345\210\222.md" @@ -0,0 +1,141 @@ +### 最长系列 +#### 最长公共自序列 +``` +dp[i][i] = dp[i-1][j-1]+1 if word1[i-1]==word2[j-1] +dp[i][j] = max(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) +``` +#### 最长公共子串 +``` +dp[i][j] = dp[i-1][j-1]+1 if word1[i-1]==word2[j-1] +dp[i][j] = 0 +return max(dp) +``` +#### 最长回文串 +``` +枚举起点和长度,得到终点j +dp[i][j] = dp[i+1][j-1] if word[i]==word[j] +更新res长度为len(res,s[i:j+1]) +``` +#### 最长有效括号 +``` +if i-dp[i-1]-1>=0 and s[i-dp[i-1]-1] == '(' and s[i]==')' +dp[i][j] = 2+dp[i-1]+dp[i-dp[i-1]-2] +return max(dp) +``` + +#### 无重复最长子串 +``` +滑动窗口,a不在队列里 就入并更新最大长度,如果在,队列出元素,直到a不在, +可以用set()优化 +``` +#### 最长上升子序列 +``` +维护单调栈,入栈,如果a比栈顶大,继续入,如果小于栈顶元素,则找到它该在的位置(可以用二分优化)-->可以输出最长的子序列 +也可以 +for i in range(size): for j in range(i):i表示终点、j表示起点 +dp[i] = max(d[i],dp[j]+1) if nums[i]>nums[j] +``` +#### 最长重复子数组 没做 + +#### 编辑距离 +``` +dp[i][j] = dp[i-1][j-1] if word1[i-1] == word2[j-1] +dp[i][j = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1 +``` + +#### 不同的子序列 +``` +dp[0][j] = 1 +dp[i][j] = dp[i-1][j-1]+dp[i][j-1] if word1[i-1] == word2[j-1] +dp[i][j] = dp[i][j-1] +``` + + + +#### 62 不同路径 +一个机器人位于一个 m x n 网格的左上角 只能像右或向下走 +```python +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + # return int(math.factorial(m+n-2)/math.factorial(m-1)/math.factorial(n-1)) + dp = [[1]*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[m-1][n-1] +``` +#### 不同路径II +```python +class Solution: + def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: + m, n = len(obstacleGrid), len(obstacleGrid[0]) + if obstacleGrid[0][0] == 1 or obstacleGrid[m-1][n-1] == 1: + return 0 + dp = [[0]*n for _ in range(m)] + dp[0][0] = 1 + for j in range(1,n): + dp[0][j] = dp[0][j-1] if obstacleGrid[0][j] == 0 else 0 + for i in range(1,m): + dp[i][0] = dp[i-1][0] if obstacleGrid[i][0] == 0 else 0 + for i in range(1,m): + for j in range(1,n): + 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] +``` + +#### 不同的二叉搜索树 +假设有i个节点,自动分配到左右子树 dp[i] = dp[j]*dp[i-j] +```python +class Solution: + def numTrees(self, n: int) -> int: + dp = [0]*(n+1) + dp[0], dp[1] = 1, 1 + for i in range(2,n+1): + for j in range(1,i+1):#左边为0右边也可能为0 + dp[i] += dp[j-1]*dp[i-j] + return dp[-1] +``` + +#### 不同的二叉搜索树 +求n个节点,生成所有不同的二叉搜索树 +那这只能用回溯法来做了 +```python +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right +class Solution: + def generateTrees(self, n): + def generate_trees(start,end): + if start > end: return [None]#空树 + trees = [] + for i in range(start, end+1): + ltree = generate_trees(start,i-1) + rtree = generate_trees(i+1,end) + for lnode in ltree:#选出左子树 + for rnode in rtree:#选出右子树 + cur = TreeNode(i) + cur.left = lnode + cur.right = rnode + trees.append(cur) + return trees + return generate_trees(1,n) if n else [] + +``` + +#### 三角形最小路径和 + +#### 72 编辑距离 +一条包含字母 A-Z 的消息通过以下方式进行了编码A-1 Z-26 +求解可行解 +明显的s[i] = s[i-1]+s[i-2],每次可以通过1位或两位得到s[i] +什么情形dp[i] = dp[i+1]呢? +s[i] + + + + +#### 518 零钱兑换II diff --git "a/Week09/\345\233\236\346\272\257\347\256\227\346\263\225\344\271\240\351\242\230\351\233\206.md" "b/Week09/\345\233\236\346\272\257\347\256\227\346\263\225\344\271\240\351\242\230\351\233\206.md" new file mode 100644 index 000000000..b1310c11f --- /dev/null +++ "b/Week09/\345\233\236\346\272\257\347\256\227\346\263\225\344\271\240\351\242\230\351\233\206.md" @@ -0,0 +1,226 @@ +### DFS/回溯算法习题集 + +#### 78 子集 +给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集[幂集] 解集不能包含重复的子集 +对于给定的例题,就能看出这个题明显的回溯痕迹,子集的长度从0-len(nums),对于每一个长度,都有不同的取值 +就能联想到多叉树的不同深度对应的路径 每一层,都可以取原始list中的其他元素,所以需要回溯 在长度等于这一层的值时 加入res中 +时间复杂度是O(Nx2^N) +```python +from typing import List +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + def backtrace(first=0,tmp=[]): + res.append(tmp[:]) + for i in range(first,size): + tmp.append(nums[i]) + backtrace(i+1,tmp)#恰好这里的i+1可以当做边界条件,加入到res中 + tmp.pop() + res, size = [], len(nums) + backtrace() + return res +``` + +#### 77 组合 +给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合 +[1,2,3,4]-2 -->[1,2],[1,3],[1,4],[2,3],[2,4],[3,4] +观察 所有子集长度都为k,且这个组合的构型是left List[List[int]]: + def backtrace(first=1,tmp=[]): + if len(tmp) == k: + res.append(tmp[:]) + for i in range(first, n+1): + tmp.append(i) + backtrace(i+1,tmp) + tmp.pop() + res = [] + backtrace() + return res +``` + +#### 46 全排列 +给定一个**没有重复**数字的序列,返回其所有可能的全排列。 +[1,2,3]--> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] +观察得到,第一层选择时,可以选择任何一个元素 这里的限定也是不包含这一层选的参数 +所以 可以在递归时,只传入还可选择的元素 +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def backtrace(nums,tmp): + # if len(nums) == len(tmp): + if not nums: + res.append(tmp[:]) + for i in range(len(nums)):#这里的nums会变化的 + backtrace(nums[:i]+nums[i+1:],tmp+[nums[i]]) + # tmp.append(nums[i]) + # backtrace(nums,tmp) + # tmp.pop() + res, size = [], len(nums) + backtrace(nums,[]) + return res +``` + +#### 47 全排列II +给定一个可包含重复数字的序列,返回所有不重复的全排列 +[1,1,2]--> [[1,1,2],[1,2,1],[2,1,1]] +这一题主要考的是剪枝 很明显的 这里在第一层取值的时候就只取到了1,2两个值 另外重复的1在这一层不能被选取 +也即是 同一层不能选取重复的元素 **同层去重** +刚开始的想法比较淳朴,就是全部结果生成之后,在加入到res时去重,多了一个for循环 +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + # def backtrace(nums,tmp): + # if len(tmp) == size: + # if tmp not in res: #这个时间复杂度有点高,因为需要在程序里逻辑判重 + # res.append(tmp[:]) + # for i in range(len(nums)): + # backtrace(nums[:i]+nums[i+1:],tmp+[nums[i]]) + # res, size = [], len(nums) + # backtrace(nums,[]) + # return res +``` +后面改进,前剪枝 利用set来做,但是逻辑不够清楚 【个人觉得,虽然这种方法在其他剪枝类的题目中也有效】 +但是不用提前排序 +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + def backtrace(nums,tmp): + if not nums: + res.append(tmp[:]) + visited = set() + for i in range(len(nums)): + if nums[i] in visited: continue + visited.add(nums[i]) + backtrace(nums[:i]+nums[i+1:],tmp+[nums[i]]) + res, size = [], len(nums) + backtrace(nums,[]) + return res +``` +还看到一种专门解决同层去重的,但是需要先对已知序列进行排序 +```python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + def backtrace(nums,tmp): + if not nums: + res.append(tmp[:]) + for i in range(len(nums)): + if i>0 and nums[i-1] == nums[i]: continue + backtrace(nums[:i]+nums[i+1:],tmp+[nums[i]]) + res, size = [], len(nums) + nums.sort() + backtrace(nums,[]) + return res +``` + + + +#### 31 下一个排列 + + +#### 60 第k个排列 + +#### 39 组合总和I +给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 +candidates 中的数字可以无限制重复被选取 但解集不能包含重复的组合 [candidates全是正整数] +由于可以重复使用元素,所以递归时传入的数组无需调整 +很明显,还是树的深度优先遍历 由于是输出组合,肯定也涉及到回溯 +看个例子吧 看有哪些地方要优化 +```python +# [1,3,2,7] 5 +# [[1,1,1,1,1],[1,1,1,2],[1,1,3],[1,1,2,1],[1,3,1],[1,2,1,1],[1,2,2],[3,1,1],[3,2],[2,1,1,1],[2,1,2],[2,3],[2,2,1]] +# [[1,1,1,1,1],[1,1,1,2],[1,1,3],[1,2,2],[2,3]] +``` +可以看到,解集的差异在于 对于[1,1,1,2]有不同的组合顺序,对于这一种 重复 剪枝方式通常是 在遍历可选择项的时候,加一个start +```python +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + def dfs(candidates, target, tmp, start): + if target<0: return + if target == 0: + res.append(tmp) + for i in range(start, len(candidates)): + dfs(candidates, target-candidates[i], tmp+[candidates[i]], i) + res = [] + dfs(candidates, target, [],0) + return res +``` + +#### 40 组合总和II +在39的基础上,每个元素只能用一次 +这里有可能对于一组数[1,2,3,4,5] - 6,在递归过程中可能会产生[2,4]和[4,2]两种解 --> 遍历时加一个start +对于同一层 可能的重复值选取 使用`if i>0 and nums[i-1] == nums[i]: continue`消除 +```python +class Solution: + def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]: + def dfs(candidates,target,tmp,start): + if target < 0: return + if target == 0: res.append(tmp) + # visited = set() + for i in range(start, len(candidates)): + if i>0 and candidates[i-1] == candidates[i]: continue + # if cur in visited: continue + # visited.add(cur) + dfs(candidates[:i]+candidates[i+1:],target-candidates[i],tmp+[candidates[i]], i) + res = [] + candidates.sort() + dfs(candidates,target,[],0) + return res +``` + +#### 216 组合总和III +这里只要去除同一组解的重复排列即可 所以加上start即可 +```python +class Solution: + def combinationSum3(self, k: int, target: int) -> List[List[int]]: + def dfs(cur, k, tmp, start): + if k < 0: return + if cur == target and k==0 : res.append(tmp) + # visited = set() + for i in range(start, 10): + # if i in visited: continue + # visited.add(i) + dfs(cur+i,k-1,tmp+[i],i+1) + res = [] + dfs(0,k,[],1) + return res +``` + +#### 377 组合总和IV +给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数 +顺序不同的序列被视作不同的组合 +```python +class Solution: + def combinationSum4(self, nums: List[int], target: int) -> int: + def dfs(cur,tmp): + if cur > target: return + if cur == target: res.append(tmp) + for i in range(len(nums)): + dfs(cur+nums[i],tmp+[nums[i]]) + res = [] + dfs(0,[]) + return len(res) +``` +但是很不幸的 超时了 所以 要引入更高级的做法 动态规划! +```python +class Solution: + def combinationSum4(self, nums: List[int], target: int) -> int: + dp = [0]*(target+1) + dp[0] = 1 + for i in range(target+1): + for j in range(len(nums)): + if i >= nums[j]: + dp[i] += dp[i-nums[j]] + return dp[-1] +``` + +这里总结一下 +给定[1,1,2,3,4] 求 target=6 +如果1,1在同一层中不能使用,那么就要使用set或者先sort然后在for循环里面判断nums[i-1]==nums[i] +或者 对于不同路径产生的结果 [2,4]和[4,2]不能相容 则 在for循环中加入起始位置 + +最后分一下回溯算法的时间复杂度 + + diff --git "a/Week09/\345\244\232\347\272\277\347\250\213\346\211\223\345\215\2600-100.py" "b/Week09/\345\244\232\347\272\277\347\250\213\346\211\223\345\215\2600-100.py" new file mode 100644 index 000000000..e0fde158b --- /dev/null +++ "b/Week09/\345\244\232\347\272\277\347\250\213\346\211\223\345\215\2600-100.py" @@ -0,0 +1,31 @@ +import threading +import time + + +# 第一个线程,打印奇数 +def threada(n): + for i in range(1, n + 1): + if i & 1: + lockb.acquire()#先请求b锁,保证不会打印偶数 + print(i) + locka.release() + +# 第二个线程,打印偶数 +def threadb(n): + for i in range(2, n + 1): + if i & 1 == 0: + locka.acquire()#先请求a锁,使得打印偶数过程不会打印奇数 + print(i), + lockb.release() + +if __name__ == "__main__": + locka = threading.Lock() + lockb = threading.Lock() + + ta = threading.Thread(target=threada,args=(100,)) + tb = threading.Thread(target=threadb,args=(100,)) + + locka.acquire() # 保证a先执行 + + ta.start() + tb.start() diff --git "a/Week09/\346\225\260\347\273\204\343\200\201\351\223\276\350\241\250\343\200\201\345\255\227\347\254\246\344\270\262\351\242\230\347\233\256.md" "b/Week09/\346\225\260\347\273\204\343\200\201\351\223\276\350\241\250\343\200\201\345\255\227\347\254\246\344\270\262\351\242\230\347\233\256.md" new file mode 100644 index 000000000..de176458c --- /dev/null +++ "b/Week09/\346\225\260\347\273\204\343\200\201\351\223\276\350\241\250\343\200\201\345\255\227\347\254\246\344\270\262\351\242\230\347\233\256.md" @@ -0,0 +1,193 @@ +### 链表 +#### 2.两数相加 +两个数字倒序以链表存储每一位数字,返回最终结果的链表头指针 +解题主要考虑进位,以及如果最后结果产生多的位数时的情形 如[5]、[5] -- [0,1] +```python +class Solution: + def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: + pre = ListNode(-1) + head, carry = pre, 0 + while l1 or l2: + x = l1.val if l1 else 0 + y = l2.val if l2 else 0 + cur = x + y + carry + carry = cur//10 + head.next =ListNode(cur%10) + if l1: l1 = l1.next + if l2: l2 = l2.next + head = head.next + if carry == 1: + head.next = ListNode(1) + return pre.next +``` + +#### 25 k个一组翻转链表 +如果翻转过程中,长度小于k,不变化 +这题的思路和翻转链表一致,主要是要界定的条件比较多 +首先找到此轮中需要翻转的链表部分的首尾指针,然后进行翻转 返回这个k串翻转之后的头尾指针 +翻转之后要连接到原来的链表中,所以要一个pre和下一个k串的头指针 +对于组内翻转 也需要一个pre节点,注意到 这里不能用空节点 而是用下一个k串的头结点 +最后要返回翻转后的首尾节点 翻转前先记录 方便函数返回 +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + # 翻转一个子链表,并且返回新的头与尾 + def reverseKGroup(self, head, k): + dummy = ListNode(-1) + dummy.next = head + pre = dummy + while head: + tail = pre + for i in range(k):#先找到此时要翻转哪些节点,记录首尾指针 + tail = tail.next + if not tail:#如果不够k个 + return dummy.next + next_head = tail.next #记录翻转后的下一个节点 + head, tail = self.reverseList(head,tail)#翻转链表 + pre.next = head + tail.next = next_head + head = next_head + pre = tail + return dummy.next + def reverseList(self,head,tail): + # 如何原地翻转 + pre = tail.next#记录那个空节点【】 + tail_node = head #记录翻转后的尾节点 + while pre!=tail: #tail是刚进来的尾节点,用它来判断是否组内翻转完毕 + tmp = head.next + head.next = pre + pre = head + head = tmp + return pre, tail_node +``` +--- + +### 数组 + + +#### 4.寻找两个正序数组的中位数 +刚开始就想着用python内置的合并数组然后根据奇偶返回中位数嘛 但是时间复杂度是O(M+N)log(M+N),空间复杂度是O(M+N) +取决于排序方法 +2.归并排序 +3.双指针 排除数组中k//2个数 +题目要求是O(log(M+N)),所以在探查的时候应当用二分查找 +```python + +``` + + +#### 88 合并两个有序数组 +1.合并后排序,没有利用原始数组已排序的特点 O((M+N)log(M+N)) +2.双指针 从前往后 需要涉及大量元素的移动,且需要额外空间 +3.双指针 从后往前 无需挪动元素 O(M+N) +```python +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + # 把大的都往nums1后面放 + i, j = m-1, n-1#从后往前判断 + store_id = m + n - 1 + while i >= 0 and j >= 0: + if nums1[i] >= nums2[j]: + nums1[store_id] = nums1[i] + i, store_id = i - 1, store_id - 1 + else: + nums1[store_id] = nums2[j] + j, store_id = j - 1, store_id - 1 + nums1[:j+1] = nums2[:j+1]#if nums2 still have elems +``` + + +#### 27 移除元素 +给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度 +元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素 +双指针解法,用left记录不相同值的位置 +```python +class Solution: + def removeElement(self, nums: List[int], val: int) -> int: + left, size = 0, len(nums) + for i in range(size): + if nums[i] != val: + nums[left] = nums[i] + left += 1 + return left +``` + +#### 31.下一个排列 + + +---- +### 字符串 + +#### 3.无重复字符的最长子串 +给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度 +刚开始想的就是用队列记录最长子串,有相同的就一直出队列 直到将该元素出队列为止 +但是在双向队列或list里面判断是否在不在是O(N)的,所以可以用set优化一下 +优化后,整体的时间复杂度是O(N) +```python +class Solution: + def lengthOfLongestSubstring(self, strs: str) -> int: + if not strs: return 0 + visited = set() + max_len, cur_len, left = 0, 0, 0 + for i in range(len(strs)): + while strs[i] in visited: + visited.remove(strs[left]) + left = left + 1 + cur_len -= 1 + visited.add(strs[i]) + cur_len += 1 + max_len = max(max_len, cur_len) + return max_len +``` + + +#### 剑指offer67 字符串转数字 +```python +class Solution: + def strToInt(self, strs: str) -> int: + strs =''.join(strs.lstrip(' ')) + # +-1234 + # +-1234lmq + # +-1234-+ + # lmq1234 + # lmq 1234 + # 碰到空格/字符--->0 第二次碰到+-截断 + # pass + res, flag = 0 ,1 + strs = strs.strip() + for i in range(len(strs)): + ch = strs[i] + if (ch == '-' or ch == '+') and i == 0: + if ch == '-': flag = -1 + if ch == '+': flag = 1 + continue + if not ch.isdigit(): break + res = 10 * res + ord(ch) - ord('0') + if res == '+' or res == '-': return 0 + return max(-2**31,-1*res) if flag == -1 else min(2**31-1,res) + +``` + +#### 392 判断子序列 +1.双指针,匹配时同时后移,不匹配母串指针后移 O(M+N) +2.动态规划 唯实是没看懂 +```python +class Solution: + def isSubsequence(self, s: str, t: str) -> bool: + if not s: return True#与面试官沟通 + i, j = 0,0 + while i=b + if a%b == 0: return b + else: + return gcd(b,a%b) +def lcm(a,b): + return a*b/gcd(a,b) + +res = lcm(2,4) +print(res) diff --git "a/Week09/\346\234\200\351\225\277\345\255\220\345\272\217\345\210\227\343\200\201\345\255\220\344\270\262\343\200\201\345\211\215\347\274\200.md" "b/Week09/\346\234\200\351\225\277\345\255\220\345\272\217\345\210\227\343\200\201\345\255\220\344\270\262\343\200\201\345\211\215\347\274\200.md" new file mode 100644 index 000000000..7615d8162 --- /dev/null +++ "b/Week09/\346\234\200\351\225\277\345\255\220\345\272\217\345\210\227\343\200\201\345\255\220\344\270\262\343\200\201\345\211\215\347\274\200.md" @@ -0,0 +1,112 @@ + +#### 5.最长回文子串 +```python +class Solution: + def longestPalindrome(self, s: str) -> str: + # 暴力法 时间复杂度O(N^3) + # 中心扩散 最坏O(N^2) + # size = len(s) + # left, right = 0, 0 + # def extend(left,right):#要一直向外扩展,就和快排、验证回文串II 一样要一直找一直找 + # 扩散是有条件的 不能越界 + # while left>=0 and right < size and s[left] == s[right]: + # left, right = left - 1, right + 1 + # return left + 1, right - 1 + # for i in range(size): + # l1, r1 = extend(i,i) + # l2, r2 = extend(i,i+1) + # if r1 - l1 > right - left: + # left, right = l1, r1 + # if r2 - l2 > right - left: + # left, right = l2, r2 + # return s[left:right+1] + + size = len(s) + res = '' + dp = [[False]*size for _ in range(size)] + for l in range(size):#枚举长度 + for i in range(size):#枚举起点 + j = i + l + if j >= size: break + elif l == 0: dp[i][j] = True + elif l == 1: dp[i][j] = (s[i]==s[j]) + else: + #i-j是否为回文首先要判断s[i],s[j]是否相等 + dp[i][j] = (dp[i+1][j-1] and s[i]==s[j]) + if dp[i][j] and l >= len(res): + res = s[i:j+1] + return res +``` + +#### 1143 最长公共子序列 +```python +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + # 看题目和之前那道最长公共回文串,很类似,这里用动态规划做, + # 但是要注意 这里是最长公共子序列,是可以间断的 + if not text1 and not text2: return 0 + m, n = len(text1), len(text2) + dp = [[0]*(n+1) for _ in range(m+1)] + for i in range(1,m+1): + for j in range(1,n+1): + if text1[i-1] == text2[j-1]: + dp[i][j] = dp[i-1][j-1] + 1 + else: + dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + return dp[-1][-1] +``` + +#### 32 最长有效括号 +```python +class Solution: + def longestValidParentheses(self, strs: str) -> int: + #先和面试官讨论清楚,最长有效括号是否是连续的 + # pass + #中心扩散???-->NO + if not strs: return 0 + dp = [0]*len(strs)#表示下标为i的有效括号长度 + for i in range(len(strs)): + if strs[i] == ')' and strs[i-dp[i-1]-1]=='(' and i-dp[i-1]-1>=0:#自身是否为有效括号 + dp[i] = 2 + dp[i-1] + dp[i-dp[i-1]-2]#自身+内有效括号+外有效括号 + return max(dp) + # if not strs: return 0 + # stack,max_len,len1 = [-1], 0, 0 + # for i in range(len(strs)): + # if strs[i] == '(': + # stack.append(i) + # else: + # stack.pop() + # if not stack: + # stack.append(i) + # else: + # len1 = i - stack[-1] + # max_len = max(max_len,len1) + # return max_len +``` + +#### 最长公共前缀 +```python +class Solution: + def longestCommonPrefix(self, strs: List[str]) -> str: + # if not strs: return '' + # min_size = min([len(x) for x in strs])#公共前缀最长只会这么长 + # 枚举最长公共前缀长度 + # for i in range(min_size, 0, -1): + # tmp = strs[0][:i] # 当前待比较的公共前缀子串 + # if all(s[:i]==tmp for s in strs): + # return tmp + # return '' + # 分治 + def lcp(start, end): + if start == end: + return strs[start] + mid = (start + end) // 2 + lcpLeft, lcpRight = lcp(start, mid), lcp(mid + 1, end) + minLength = min(len(lcpLeft), len(lcpRight)) + for i in range(minLength): + if lcpLeft[i] != lcpRight[i]: + return lcpLeft[:i] + return lcpLeft[:minLength] + return "" if not strs else lcp(0, len(strs) - 1) +``` + diff --git "a/Week09/\346\240\210\345\222\214\345\215\225\350\260\203\346\240\210.py" "b/Week09/\346\240\210\345\222\214\345\215\225\350\260\203\346\240\210.py" new file mode 100644 index 000000000..84d82d3bc --- /dev/null +++ "b/Week09/\346\240\210\345\222\214\345\215\225\350\260\203\346\240\210.py" @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/7/25 9:56 PM \ No newline at end of file diff --git "a/Week09/\347\211\233\345\256\242_\346\266\202\346\224\271\346\234\250\346\235\277.py" "b/Week09/\347\211\233\345\256\242_\346\266\202\346\224\271\346\234\250\346\235\277.py" new file mode 100644 index 000000000..3bd90994b --- /dev/null +++ "b/Week09/\347\211\233\345\256\242_\346\266\202\346\224\271\346\234\250\346\235\277.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/6 9:44 PM + +# +# +# @param n int整型 +# @param m int整型 +# @param a int整型一维数组 +# @return int整型 +# +class Solution: + def solve(self, n, m, nums): + # write code here + # 6,1, [1,0,0,1,1,1] + # 设dp[i][j]是第i次染色,到第j块能拿到的最大板子长度 + # dp[0] = nums[:] + # dp[i][0] = 1 + # for i in range(1,m+1) + # dp[i][j] = max(dp[i-1][j],dp[i][j-1]+1) + + +s = Solution() +nums = [1,0,0,1,1,1] +res = s.solve(6,2,nums) +print(res) \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 000000000..4453034f7 --- /dev/null +++ b/test.py @@ -0,0 +1,97 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/11 8:20 PM + + +# def decode(stack): +# val1 = stack.pop() +# val2 = stack.pop() +# ch = chr(int(val1+val2,16)) +# if ch == '%': +# stack = decode(stack) +# else: +# stack.append(ch) +# return stack +# def main(): +# N = int(input()) +# for i in range(N): +# s = str(input()) +# stack = [] +# for c in s[::-1]: +# if c != '%':#%%32F +# stack.append(c) +# else: +# stack = decode(stack) +# print("".join(stack[::-1])) +# main() +# class Solution: +# def minCost(self,x,a,b): +# size = int((x+251)/500)#减少开辟的内存空间 +# dp = [0]*(size+1) +# for i in range(1,3): +# dp[i] = dp[i-1] + a +# print(dp) +# for i in range(3, size+1): +# dp[i] = min(dp[i-3]+b, dp[i-1]+a) +# return dp +# s = Solution() +# res = s.minCost(4999,5,10) +# print(res) +# def min_cost(x,a,b): +# if x == 0: return 0 +# size = int((x+251)/500) +# dp = [0]*(size+1) +# for i in range(1,3): +# dp[i] = dp[i-1] + a +# for i in range(1,size+1): +# dp[i] = min(dp[i-1]+a, dp[i-3]+b) +# return dp[-1] + +# def min_cost(x,a,b): +# if 3*a <= b: +# return x//500 * a#全部买小瓶的 +# else:#买1500ml均价更低 +# #先确定大瓶数量、在确定小瓶数量 +# m = x // 1500 + 1 if x % 1500 != 0 else x // 1500 +# # 1. 全买大瓶 +# cost1 = m * b +# # 2. 尽可能买大瓶,剩下买小的 +# x = x - 1500 * (m - 1) +# n = x // 500 + 1 if x % 500 != 0 else x // 500 +# cost2 = (m - 1) * b + n * a +# return min(cost1, cost2) +# while True: +# try: +# N = int(input()) +# for i in range(N): +# [x,a,b] = list(map(int,str(input()).split())) +# res = min_cost(x,a,b) +# print(res) +# except: +# break + + +# def cost(x, a, b): +# if 3 * a < b: +# n = x // 500 + 1 if x % 500 != 0 else x // 500 +# return n * a +# else: +# m = x // 1500 + 1 if x % 1500 != 0 else x // 1500 +# cost1 = m * b +# x = x - 1500 * (m - 1) +# n = x // 500 + 1 if x % 500 != 0 else x // 500 +# cost2 = (m - 1) * b + n * a +# return min(cost1, cost2) +# +# while True: +# try: +# n = int(input()) +# for i in range(n): +# [x, a, b] = list(map(int, input().split())) +# print(cost(x, a, b)) +# except: +# break +s= input().split(',') +print(s) +# a,b = list(map(int,[s1[1:-2],s2[:-2]])) +# print(a,b) \ No newline at end of file diff --git "a/\345\244\232\347\272\247\345\217\260\351\230\266\351\227\256\351\242\230.py" "b/\345\244\232\347\272\247\345\217\260\351\230\266\351\227\256\351\242\230.py" new file mode 100644 index 000000000..cb054ebc0 --- /dev/null +++ "b/\345\244\232\347\272\247\345\217\260\351\230\266\351\227\256\351\242\230.py" @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- +# Author : Ray +# Data : 2020/8/12 11:27 AM + +# 小明那题应该是 +# dp[i]表示走上第i级台阶有多少种走法 +# #0表示走1阶,1表示走两阶,由于连续两次不能重复, +# 所以如果你这次想走1个台阶,只能是你之前从i-2个台阶走两阶; +# 如果你这次想走2个台阶,(你之前只能走1个台阶)只能从i-1个台阶走过来 +# dp[0][0] = 0 dp[0][1] = 0 +# dp[1][0] = 1 dp[1][1] = 0 +# dp[2][0] = 0 dp[2][1] = 1 +# 那么现在 如果想走到三级台阶,有几种走法???1. 2+1 2.1+2 仅两种 +# dp[i][0] = dp[i-2][1] + 1 #dp[2][0] = dp[i-dp[i-1]][1]+1 = 0+1 = 1 +# dp[i][1] = dp[i-2][0] + 1# dp[2][1] = dp[0][0]+1 = 0 +# dp[3][0] +# dp[i][0,1]表示以走0或1(+1)的方式走上第i级台阶的方法 +# 如果想走到n级台阶,有两种走法,走1阶,走两阶 +# 1.确定此时走两阶 那么之前只能走一阶 dp[i][1] = dp[i-1][0] + 1 +# 2.确定此时只能走一阶 那么此前只能走两阶 dp[i][0] = dp[i-2][1] + 1 +# dp[0][0] = 0 dp[0][1] = 0 +# dp[1][0] = 1 dp[1][1] = 0 +# dp[2][0] = 0 dp[2][1] = 1 +# 如果要上三级台阶 1+2 或者2+1 +# dp[3][0] = dp[2][1] + 1= 2 +# dp[3][1] = dp[1][0] + 1 = 2 +# 最后返回max(dp[-1]) \ No newline at end of file