这里是链表的插入排序。时间效率和空间效率十分堪忧,但是思想比较简单。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # Definition for singly-linked list. class ListNode(object): def __init__(self, val=0, next=None): self.val = val self.next = next class Solution(object): def insertionSortList(self, head): """ 插入排序:除了第一个节点不动,第二个元素和前面已经排序好的元素进行比较,插入到合适的位置 重复上述过程即可。 比如: 1 3 5 2 4 |左边为排序好的节点 1 | 3 5 2 4 1 3 | 5 2 4 1 3 5 | 2 4 1 2 3 5 | 4 1 2 3 4 5 | :type head: ListNode :rtype: ListNode """ if head.next is None: return head ends = head.next node = head.next start = head # 单独处理前两个节点 if node.val < start.val: start.next = node.next node.next = start ends = start start = node head = node # 递归处理后面所有情况 node = ends.next while node is not None: # 寻找合适的插入位置 (3种情况:头插入、中间插入、尾插入) # 头插入 if node.val < start.val: ends.next = node.next node.next = start start = node head = node node = ends.next # 尾插入 elif node.val > ends.val: ends = node node = ends.next # 中间插入 else: cur = start # 寻找插入位置 while True: if node.val >= cur.val and node.val <=cur.next.val: break cur = cur.next # 插入 ends.next = node.next node.next = cur.next cur.next = node node = ends.next return head |
用一张图来说明归并排序:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # Definition for singly-linked list. class ListNode(object): def __init__(self, val=0, next=None): self.val = val self.next = next class Solution(object): # fixme: 归并排序(自底向上合并链表) def merge(self, node1, node2): dummy = ListNode() pre = dummy while node1 is not None and node2 is not None: if node1.val <= node2.val: pre.next = node1 pre = pre.next node1 = node1.next else: pre.next = node2 pre = pre.next node2 = node2.next if node1 is not None: pre.next = node1 if node2 is not None: pre.next = node2 return dummy.next # fixme: 归并排序(自顶向下划分链表) def merge_sort(self, head): if head is None or head.next is None: return head # 快慢指针寻找中间节点 slow = head fast = head while fast.next is not None and fast.next.next is not None: slow = slow.next fast = fast.next.next # 找到中间节点之后断开链表 new_head = slow.next slow.next = None # 递归断开所有的节点 slow = self.merge_sort(head) fast =self.merge_sort(new_head) # 合并 return self.merge(slow, fast) def sortList(self, head): """ 参考大佬的题解考虑使用归并排序 对于数组的归并排序来说,可以直接根据数组的长度来找到中间值,对于链表来说,我们可以通过快慢指针来找到中间节点 然后采用递归的方法将链表层层断开,排序后 最后再合并 :type head: ListNode :rtype: ListNode """ return self.merge_sort(head) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:
给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 示例 1: 输入:nums = [1,3,5] 输出:1 示例 2: 输入:nums = [2,2,2,0,1] 输出:0 提示: n == nums.length 1 <= n <= 5000 -5000 <= nums[i] <= 5000 nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Solution(object): def findMin(self, nums): """ 除了return min(nums)之外的考虑,延续上一道题的想法 :type nums: List[int] :rtype: int """ flag = True if nums[0] < nums[-1]: flag = True # 从左端开始找 else: flag = False # 从右端开始找 for i in range(1, len(nums)): if flag: if nums[i] < nums[i - 1]: return nums[i] else: if nums[len(nums) - i] < nums[len(nums) - 1 - i]: return nums[len(nums) - i] return nums[0] if __name__ == '__main__': s = Solution() print(s.findMin([2,2,2,0,1])) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 示例 1: 输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。 示例 2: 输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。 示例 3: 输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。 提示: n == nums.length 1 <= n <= 5000 -5000 <= nums[i] <= 5000 nums 中的所有整数 互不相同 nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转 |
没意义.
| 1 2 3 4 5 6 7 | class Solution(object): def findMin(self, nums): """ :type nums: List[int] :rtype: int """ return min(nums) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Solution(object): def findMin(self, nums): """ 分析: 感觉题目的意思可以看出本题的实质是找到分断点(因为原数组是有序数组) 因此从两端开始判断的话,只需找到比较小的那一端,然后从小的那一端开始判断 1.如果是从左端开始的话,如果nums[i] <= nums[i+1],则继续右移,直到不满足结果 2. 如果是从右端开始的话,如果nums[i] <= nums[i+1], 则继续左移,直到不满足结果 :type nums: List[int] :rtype: int """ flag = True if nums[0] < nums[-1]: flag = True # 从左端开始找 else: flag = False # 从右端开始找 for i in range(1, len(nums)): if flag: if nums[i] < nums[i-1]: return nums[i] else: if nums[len(nums) - i] < nums[len(nums) - 1 - i]: return nums[len(nums) - i] return nums[0] if __name__ == '__main__': s = Solution() print(s.findMin(nums = [1,2,3,4,5])) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
| 1 2 3 4 5 6 7 8 9 10 | 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Solution(object): def maxProduct(self, nums): """ 考虑使用动态规划. 因为数组中的值包含了正值和负值,可能会变为负负得正,或者你最大的正值乘个-1就会变为最小的负值 因此考虑使用两个数组来进行记录,分别记录当前的最大值和最小值, 然后进行后续应用 :type nums: List[int] :rtype: int """ max_dp = [0] * len(nums) min_dp = [0] * len(nums) dp = [0] * len(nums) max_dp[0] = nums[0] min_dp[0] = nums[0] dp[0] = nums[0] for i in range(1, len(nums)): max_dp[i] = max(max_dp[i-1] * nums[i], min_dp[i-1] * nums[i], nums[i]) min_dp[i] = min(max_dp[i-1] * nums[i], min_dp[i-1] * nums[i], nums[i]) dp[i] = max(max_dp[i], dp[i-1]) return dp[-1] if __name__ == '__main__': s = Solution() print(s.maxProduct([-1, -2, -9, 6])) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 示例 1: 输入:s = "the sky is blue" 输出:"blue is sky the" 示例 2: 输入:s = " hello world " 输出:"world hello" 解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。 示例 3: 输入:s = "a good example" 输出:"example good a" 解释:如果两个单词间有多余的空格,将翻转后单词间的空格减少到只含一个。 示例 4: 输入:s = " Bob Loves Alice " 输出:"Alice Loves Bob" 示例 5: 输入:s = "Alice does not even like bob" 输出:"bob like even not does Alice" 提示: 1 <= s.length <= 104 s 包含英文大小写字母、数字和空格 ' ' s 中 至少存在一个 单词 进阶: 请尝试使用 O(1) 额外空间复杂度的原地解法。 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Solution(object): def reverseWords(self, s): """ 使用split分割之后进行翻转即可 :type s: str :rtype: str """ s = s.split(' ') res = '' for i in range(len(s)): if s[len(s) - i - 1] == '': continue if res == '': res = s[len(s) - i - 1] else: res = res + ' ' + s[len(s) - i - 1] return res if __name__ == '__main__': s = Solution() print(s.reverseWords("a good example")) |
首先介绍一下中缀表达式,中缀表达式是人类最熟悉的表达式,比如1+2, (1+2)*3等。
如下图:
中缀表达式就是对上述二叉树进行中序遍历得到的结果。
波兰式又称为前缀表达式,它是对上述语法二叉树进行前序遍历得到的结果。上图的前缀表达式为:
-+A*B-CD*EF
逆波兰式又称为后缀表达式,是上述语法二叉树的后序遍历得到的结果。
]]> <h1>波兰式和逆波兰式</h1> <p>首先介绍一下中缀表达式,中缀表达式是人类最熟悉的表达式,比如1+2, (1+2)*3等。<br> 如下图:</p> <p><img src="https://gitee.com/zyp521/upload_image/raw/master LeetCode No.150 www.strivezs.com/2021/07/23/LeetCode%E7%AC%AC150%E9%A2%98/ 2021-07-23T09:19:13.883Z 2021-07-23T09:19:13.883Z LeetCode第150题—逆波兰表达式求值自己代码的开源仓库:click here 欢迎Star和Fork :)
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 示例 1: 输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9 示例 2: 输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6 示例 3: 输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] 输出:22 解释: 该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22 提示: 1 <= tokens.length <= 104 tokens[i] 要么是一个算符("+"、"-"、"*" 或 "/"),要么是一个在范围 [-200, 200] 内的整数 |
可以说只要想到用栈和理解逆波兰式的含义就十分简单了。唯一一点就是要注意只取整数部分,不考虑小数部分。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import math class Solution(object): def evalRPN(self, tokens): """ 逆波兰式是后缀表达式 后缀表达式的求法:只需要处理符号的前两个值就可以了 那么就可以考虑使用栈来模拟计算过程 需要注意的是,这里只取整数部分,不考虑小数 因此考虑使用math.modf() :type tokens: List[str] :rtype: int """ stack = [] # 数字栈 characters = ['-', '+', '*', '/'] # 符号 for i in range(len(tokens)): if tokens[i] in characters: b = stack[-1] stack.pop() a = stack[-1] stack.pop() if tokens[i] == '-': c = a - b elif tokens[i] == '+': c = a + b elif tokens[i] == '*': c = a * b elif tokens[i] == '/': c = a / b stack.append(math.modf(c)[1]) else: stack.append(int(tokens[i])) return int(stack[-1]) if __name__ == '__main__': s = Solution() print(s.evalRPN(["10","6","9","3","+","-11","*","/","*","17","+","5","+"])) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
| 1 2 3 4 | 示例 1: 输入:points = [[1,1],[2,2],[3,3]] 输出:3 |
| 1 2 3 4 5 6 7 8 9 10 | 示例 2: 输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] 输出:4 提示: 1 <= points.length <= 300 points[i].length == 2 -104 <= xi, yi <= 104 points 中的所有点 互不相同 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | from fractions import Fraction class Solution(object): # 统计在直线上点的个数 def num_points_on_line(self, k, b, points): num = 0 for i in range(len(points)): if points[i][0] * k + b == points[i][1]: num += 1 return num def time_out(self, points): """ 暴力搜索的方法,目前自己能想到的方法 找到两个点求出斜率,然后确定还有多少个点在上面,找到最大的, 暴力搜索不出意外的Time out了,下面尝试对代码进行优化 :type points: List[List[int]] :rtype: int """ if len(points) == 1: return 1 if len(points) == 2: return 2 max_num = 0 for i in range(len(points)): for j in range(len(points)): if i == j: continue if points[i][0] - points[j][0] == 0: # 为纵轴的情况 cur_num = 0 for m in range(len(points)): if points[m][0] == points[i][0]: cur_num += 1 else: k = Fraction((points[i][1] - points[j][1]) , (points[i][0] - points[j][0])) b = points[i][1] - k * points[i][0] cur_num = self.num_points_on_line(k, b, points) if cur_num > max_num: max_num = cur_num return max_num def maxPoints(self, points): """ 不出意料的暴力搜索的代码直接裂开了,我最开始的那个暴力算法冗余度太高了,后面需要进行优化,这里使用哈希表进行记忆 可以使用如下方法: 固定一个点来统计和其他的点的斜率 最后再将斜率和b相同的点个数统计,返回最大的值 考虑用字典来记录,字典:{斜率: [位于当前斜率上的点]} :type points: List[List[int]] :rtype: int """ if len(points) == 1: return 1 if len(points) == 2: return 2 max_num = 0 k_num = dict() for i in range(len(points)): for j in range(len(points)): if i == j: continue if points[i][0] - points[j][0] == 0: # 为纵轴的情况 斜率不存在用对应的x值的字符串表示 if str(points[i][0]) not in k_num.keys(): k_num[str(points[i][0])] = [] if points[i] not in k_num[str(points[i][0])]: k_num[str(points[i][0])].append(points[i]) if points[j] not in k_num[str(points[i][0])]: k_num[str(points[i][0])].append(points[j]) if len(k_num[str(points[i][0])]) > max_num: max_num = len(k_num[str(points[i][0])]) else: k = Fraction((points[i][1] - points[j][1]) , (points[i][0] - points[j][0])) b = points[i][1] - k * points[i][0] key = str(k)+','+str(b) if key not in k_num.keys(): k_num[key] = [] if points[i] not in k_num[key]: k_num[key].append(points[i]) if points[j] not in k_num[key]: k_num[key].append(points[j]) if len(k_num[key]) > max_num: max_num = len(k_num[key]) return max_num if __name__ == '__main__': s = Solution() print(s.maxPoints([[0,0],[4,5],[7,8],[8,9],[5,6],[3,4],[1,1]])) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
| 1 2 3 4 5 | 示例 1: 输入:head = [4,2,1,3] 输出:[1,2,3,4] 示例 2: |
| 1 2 3 4 5 6 7 8 9 10 11 12 | 输入:head = [-1,5,3,4,0] 输出:[-1,0,3,4,5] 示例 3: 输入:head = [] 输出:[] 提示: 链表中节点的数目在范围 [0, 5 * 104] 内 -105 <= Node.val <= 105 |
用一张图来说明归并排序:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # Definition for singly-linked list. class ListNode(object): def __init__(self, val=0, next=None): self.val = val self.next = next class Solution(object): # fixme: 归并排序(自底向上合并链表) def merge(self, node1, node2): dummy = ListNode() pre = dummy while node1 is not None and node2 is not None: if node1.val <= node2.val: pre.next = node1 pre = pre.next node1 = node1.next else: pre.next = node2 pre = pre.next node2 = node2.next if node1 is not None: pre.next = node1 if node2 is not None: pre.next = node2 return dummy.next # fixme: 归并排序(自顶向下划分链表) def merge_sort(self, head): if head is None or head.next is None: return head # 快慢指针寻找中间节点 slow = head fast = head while fast.next is not None and fast.next.next is not None: slow = slow.next fast = fast.next.next # 找到中间节点之后断开链表 new_head = slow.next slow.next = None # 递归断开所有的节点 slow = self.merge_sort(head) fast =self.merge_sort(new_head) # 合并 return self.merge(slow, fast) def sortList(self, head): """ 参考大佬的题解考虑使用归并排序 对于数组的归并排序来说,可以直接根据数组的长度来找到中间值,对于链表来说,我们可以通过快慢指针来找到中间节点 然后采用递归的方法将链表层层断开,排序后 最后再合并 :type head: ListNode :rtype: ListNode """ return self.merge_sort(head) |
自己代码的开源仓库:click here 欢迎Star和Fork :)
对链表进行插入排序。
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
| 1 2 3 4 5 6 7 8 | 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5 |
用一张原理图来说明。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # Definition for singly-linked list. class ListNode(object): def __init__(self, val=0, next=None): self.val = val self.next = next class Solution(object): def insertionSortList(self, head): """ 插入排序:除了第一个节点不动,第二个元素和前面已经排序好的元素进行比较,插入到合适的位置 重复上述过程即可。 比如: 1 3 5 2 4 |左边为排序好的节点 1 | 3 5 2 4 1 3 | 5 2 4 1 3 5 | 2 4 1 2 3 5 | 4 1 2 3 4 5 | :type head: ListNode :rtype: ListNode """ if head.next is None: return head ends = head.next node = head.next start = head # 单独处理前两个节点 if node.val < start.val: start.next = node.next node.next = start ends = start start = node head = node # 递归处理后面所有情况 node = ends.next while node is not None: # 寻找合适的插入位置 (3种情况:头插入、中间插入、尾插入) # 头插入 if node.val < start.val: ends.next = node.next node.next = start start = node head = node node = ends.next # 尾插入 elif node.val > ends.val: ends = node node = ends.next # 中间插入 else: cur = start # 寻找插入位置 while True: if node.val >= cur.val and node.val <=cur.next.val: break cur = cur.next # 插入 ends.next = node.next node.next = cur.next cur.next = node node = ends.next return head |
回家休息几天,搬宿舍心累。再回实验室就开始好好科研了!!!
自己代码的开源仓库:click here 欢迎Star和Fork :)
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 示例: 输入 ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] 输出 [null, null, null, 1, null, -1, null, -1, 3, 4] 解释 LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // 缓存是 {1=1} lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} lRUCache.get(1); // 返回 1 lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} lRUCache.get(2); // 返回 -1 (未找到) lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} lRUCache.get(1); // 返回 -1 (未找到) lRUCache.get(3); // 返回 3 lRUCache.get(4); // 返回 4 提示: 1 <= capacity <= 3000 0 <= key <= 10000 0 <= value <= 105 最多调用 2 * 105 次 get 和 put |
LRU:最近最少使用缓存机制
其设计的原则依据:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
假定系统为某进程分配了3个物理块,进程运行时的页面走向为 7 0 1 2 0 3 0 4,开始时3个物理块均为空,那么LRU算法是如下工作的:
效率和内存差了点,但是自己纯手工写的。QAQ
核心思想就是通过使用双向链表和字典来存储内容。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | class LRUCache(object): """ LRU 最近最少使用缓存机制: ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] 对上面例子分析: 1. LRUCache 2 表示:创建一个容量为2的LRU缓存 2. put表示执行put操作,把1放到LRU中,并设置它的使用次数为1 其他所有数值的使用次数-1 3. put 2,2表示:把2放到LRU中,并设置它的使用次数为1 其他所有数值的使用次数-1 4. get 1表示使用一次LRU中的1,并将它的使用次数+1 其他所有数值的使用次数-1 5. put 3,3表示:把3放入到LRU中,因为LRU已经满了,因此需要将使用次数最小的那个值(2)置换出来,把3放进入 其他所有数值的使用次数-1 使用字典来存储key-value 使用list作为双端链表来存储使用次数 """ def __init__(self, capacity): """ :type capacity: int """ self.length = capacity self.lru_cache = [] # 双端链表,头部表示最新使用的节点,尾部是最久没使用的节点 self.key_value = dict() def get(self, key): """ :type key: int :rtype: int """ if key not in self.key_value.keys(): return -1 else: # 如果能够获取,将访问的node放置于链表最前头 self.lru_cache.remove(key) self.lru_cache.insert(0,key) # 置于链表头部 return self.key_value[key] def put(self, key, value): """ :type key: int :type value: int :rtype: None """ if key in self.key_value.keys(): self.key_value[key] = value # 更新 # 如果能够获取,将访问的node放置于链表最前头 self.lru_cache.remove(key) self.lru_cache.insert(0, key) # 置于链表头部 else: if len(self.key_value) < self.length: self.lru_cache.insert(0, key) # 置于链表头部 self.key_value[key] = value else: # 链表末尾元素出链表 rm_key = self.lru_cache[-1] self.lru_cache.pop() self.key_value.pop(rm_key) # 添加新的元素 self.lru_cache.insert(0, key) # 置于链表头部 self.key_value[key] = value if __name__ == '__main__': t1 = ["LRUCache","get","put","get","put","put","get","get"] t2 = [[2],[2],[2,6],[1],[1,5],[1,2],[1],[2]] t = None for i in range(len(t1)): if t1[i] == 'LRUCache': t = LRUCache(t2[i][0]) print('None') elif t1[i] == 'put': print(t.put(t2[i][0], t2[i][1])) elif t1[i] == 'get': print(t.get(t2[i][0])) |
LRU:最近最少使用缓存机制
其设计的原则依据:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
假定系统为某进程分配了3个物理块,进程运行时的页面走向为 7 0 1 2 0 3 0 4,开始时3个物理块均为空,那么LRU算法是如下工作的:
上述操纵通过一个双向链表就可以轻松实现了。
只需要每次将不论是否出现在链表中的值都置于链表的头就可以了,如果链表满了,就将链表的元素移除链表。
回家休息几天,搬宿舍心累。再回实验室就开始好好科研了!!!
自己代码的开源仓库:click here 欢迎Star和Fork :)
v给定一个二叉树,返回它的 后序 遍历。
| 1 2 3 4 5 6 7 8 9 10 11 | 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Definition for a binary tree node. class TreeNode(object): def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class Solution(object): res = [] # fixme: 后序遍历 def backward(self, node): if node is not None: self.backward(node.left) self.backward(node.right) self.res.append(node.val) def postorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ self.res = [] self.backward(root) return self.res |
最近刚从雁栖湖搬到中关村。各方面和自己的预期很有差异。可能是还是没有适应。
自己代码的开源仓库:click here 欢迎Star和Fork :)
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 示例 1: 输入:root = [1,null,2,3] 输出:[1,2,3] 示例 2: 输入:root = [] 输出:[] 示例 3: 输入:root = [1] 输出:[1] |
| 1 2 3 | 示例 4: 输入:root = [1,2] 输出:[1,2] |
| 1 2 3 4 5 6 7 8 | 示例 5: 输入:root = [1,null,2] 输出:[1,2] 提示: 树中节点数目在范围 [0, 100] 内 -100 <= Node.val <= 100 |
即将回家!
自己代码的开源仓库:click here 欢迎Star和Fork :)
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
| 1 2 3 4 5 6 | 示例 1: 给定链表 1->2->3->4, 重新排列为 1->4->2->3. 示例 2: 给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3. |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | import copy # Definition for singly-linked list. class ListNode(object): def __init__(self, val=0, next=None): self.val = val self.next = next class Solution(object): def reorderList(self, head): """ 分析题目可以得到这个链表就是通过中间节点划分之后,前端链表和后端链表合并的结果 因此可以先用快慢指针来找到中间节点,然后用栈存储后端链表节点 最后实现前端链表和栈节点合并即可 :type head: ListNode :rtype: None Do not return anything, modify head in-place instead. """ if head is None or head.next is None: return head fast = head # 快指针 slow = head # 慢指针 mid = None # 中间节点 forward = [] # 用于存储前向链表的队列 stack = [] # 用于存储后端链表的栈 # 快慢指针寻找中间节点 while fast is not None and fast.next is not None: fast = fast.next.next forward.append(slow) slow = slow.next mid = slow # 遍历后端链表节点,将所有节点都放到栈里面 node = mid while node is not None: stack.append(node) node = node.next # 合并前端链表和反向后端链表 node = head temp = stack[-1] stack.pop() node.next = temp node = node.next for i in range(1,len(forward)): node.next = forward[i] node = node.next temp = stack[-1] stack.pop() node.next = temp node = node.next if len(stack) != 0: node.next = stack[-1] node = node.next node.next = None return head if __name__ == '__main__': root = ListNode(1) node1 = ListNode(2) node2 = ListNode(3) node3 = ListNode(4) root.next = node1 node1.next = node2 node2.next = node3 s = Solution() t = s.reorderList(root) while t is not None: print(t.val) t = t.next |
自行去官网下载安装VsCode就可以,下载地址
这里我建议还是安装Latex吧,如果你的电脑空间不够了可以尝试安装Basic Tex,关于Basic Tex的相关内容我在之前的博文中讲过了(ps:其实他还是存在一些问题的,因此建议安装的是MacTex)。下面是安装MacTex的话可以通过如下命令进行安装:
| 1 2 3 4 5 6 7 8 9 10 | brew cask install basictex export PATH=/usr/local/texlive/2019basic/bin/x86_64-darwin:$PATH // 打开usr.local隐藏路径,可以打开finder然后shift+command+G // 安装相关包,安装包使用 tlmgr install命令进行安装 sudo tlmgr update --self --repository http://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet sudo tlmgr install latexmk --repository http://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/tlnet |
在VsCode中安装latex workshop插件,如下图:
进入用户设置:
打开扩展->Json中的用户设置:
将下述内容添加到{}中即可:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | "latex-workshop.latex.recipes": [{ "name": "xelatex", "tools": [ "xelatex" ] }, { "name": "latexmk", "tools": [ "latexmk" ] }, { "name": "pdflatex -> bibtex -> pdflatex*2", "tools": [ "pdflatex", "bibtex", "pdflatex", "pdflatex" ] } ], "latex-workshop.latex.tools": [{ "name": "latexmk", "command": "latexmk", "args": [ "-synctex=1", "-interaction=nonstopmode", "-file-line-error", "-pdf", "%DOC%" ] }, { "name": "xelatex", "command": "xelatex", "args": [ "-synctex=1", "-interaction=nonstopmode", "-file-line-error", "%DOC%" ] }, { "name": "pdflatex", "command": "pdflatex", "args": [ "-synctex=1", "-interaction=nonstopmode", "-file-line-error", "%DOC%" ] }, { "name": "bibtex", "command": "bibtex", "args": [ "%DOCFILE%" ] }], "latex-workshop.view.pdf.viewer": "tab", "latex-workshop.latex.clean.fileTypes": [ "*.aux", "*.bbl", "*.blg", "*.idx", "*.ind", "*.lof", "*.lot", "*.out", "*.toc", "*.acn", "*.acr", "*.alg", "*.glg", "*.glo", "*.gls", "*.ist", "*.fls", "*.log", "*.fdb_latexmk" ], |
完成上述步骤之后重启VsCode即可。
至于中文的设置可以通过引用
| 1 | \documentclass[UTF8]{ctexart} |
来实现.
]]> <h1>MAC+VSCode+Latex 配置Latex编写环境</h1> <h2 id="安装VsCode"><a class="header-anchor" href="#安装VsCode">¶</a>安装VsCode</h2> <p>自行去官网下载安装VsCode就可以,< LeetCode No.142 www.strivezs.com/2021/07/09/LeetCode%E7%AC%AC142%E9%A2%98/ 2021-07-09T00:55:19.752Z 2021-07-09T00:55:19.752Z LeetCode第142题—环形链表II即将回家!
自己代码的开源仓库:click here 欢迎Star和Fork :)
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
| 1 2 3 4 5 | 示例 1: 输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。 |
| 1 2 3 4 5 | 示例 2: 输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。 |
| 1 2 3 4 5 6 7 8 9 10 11 | 示例 3: 输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。 提示: 链表中节点的数目范围在范围 [0, 104] 内 -105 <= Node.val <= 105 pos 的值为 -1 或者链表中的一个有效索引 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # Definition for singly-linked list. class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution(object): return_node = None flag = True def detectCycle(self, head): """ dfs遍历,返回环的第一个节点就好了 :type head: ListNode :rtype: ListNode """ if head is None or head.next is None: return None self.return_node = None self.flag = True # 结束标志 meomory = [] # 记忆列表 def dfs(node): if self.flag: if node is not None: if node in meomory: self.return_node = node self.flag = False meomory.append(node) dfs(node.next) dfs(head) return self.return_node |
创建新的环境的命令如下:
| 1 | conda env create -f environment.yml |
其中.yml是需要自己的配置的。
配置格式如下:
| 1 2 3 4 5 6 7 8 9 | name: 虚拟环境名 channels: - pytorch - defaults - 还是使用国内地清华源、科大源等 dependencies: - 包名=版本号 - pip:(使用pip 进行安装的一些包) - 包名=版本号 |
例子:
| 1 2 3 4 5 6 7 8 9 10 | name: Total3D channels: - pytorch - defaults dependencies: - _libgcc_mutex=0.1 - blas=1.0 - pip: - cycler==0.10.0 - jellyfish==0.8.2 |
这几天课比较多,有点忙,可能来不及更新喔
自己代码的开源仓库:click here 欢迎Star和Fork :)
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
| 1 2 3 4 5 | 示例 1: 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 |
| 1 2 3 4 5 | 示例 2: 输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。 |
| 1 2 3 4 5 6 7 8 9 10 11 | 示例 3: 输入:head = [1], pos = -1 输出:false 解释:链表中没有环。 提示: 链表中节点的数目范围是 [0, 104] -105 <= Node.val <= 105 pos 为 -1 或者链表中的一个 有效索引 |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # Definition for singly-linked list. class ListNode(object): def __init__(self, x): self.val = x self.next = None class Solution(object): flag = True def hasCycle(self, head): """ :type head: ListNode :rtype: bool """ if head is None: return False if head.next is None: return False self.flag = True node_list = [] # 记忆node,如果出现过则表示存在环了 def dfs(node): if node.next != None: if node in node_list: self.flag = False return node_list.append(node) dfs(node.next) dfs(head) if self.flag: return False else: return True |