
leetcode+剑指offer
刷题记录
Emma1997
一个努力想要做到更好的学渣。
展开
-
leetcode专题训练1035. Uncrossed Lines
这道题算是最长公共子序列的变形。会写公共子序列就可以写这道题。主要的难点是怎么看出这道题是最长公共子序列。设dp[i][j]为到nums1数组的第i个元素、nums2数组的第j个元素(从0开始)的最长公共子序列长度,递推逻辑:dp[i][j] = max(dp[i-1][j], dp[i][j-1])if nums1[i] == nums2[j]: dp[i][j] = max(dp[i][j], dp[i-1][j-1]+1)完整代码:class Solution: def maxUn原创 2021-05-21 18:56:16 · 297 阅读 · 0 评论 -
leetcode专题训练1269. Number of Ways to Stay in the Same Place After Some Steps
又是一道dp,本来想着滚动数组做,后来想了想好像不太好写,就直接开了个二维数组。class Solution: def numWays(self, steps: int, arrLen: int) -> int: maxNum = 10**9+7 dp = [[0 for i in range(min(steps+1, arrLen))] for j in range(steps+1)] dp[0][0] = 1 for i原创 2021-05-13 19:38:05 · 204 阅读 · 0 评论 -
leetcode专题训练1310. XOR Queries of a Subarray
很简单的一道dp加异或性质的题。比如一个长度为4的序列,数字的索引分别是0, 1, 2, 3,那么可以先把从初始位置到所有位置的异或求出来,若要求某个区间,比如[1, 2]区间的异或时,直接用dp[2] xor dp[0]即可,也就是dp[r] xor dp[l-1]。class Solution: def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]: dp = [arr[0原创 2021-05-13 00:15:54 · 171 阅读 · 0 评论 -
leetcode专题训练329. Longest Increasing Path in a Matrix
很简单的一道题啊,DFS加自定义比较函数的priorityqueueimport queueclass Node: def __init__(self, value, x, y): self.value = value self.x = x self.y = y # 按照value升序排列 def __lt__(self, other): return self.value < other.valuecla原创 2021-04-29 22:25:39 · 173 阅读 · 0 评论 -
leetcode专题训练295. Find Median from Data Stream
这道题在插入元素时,维持一个有序数组,维持的方式是通过二分查找,找到当前插入元素应该插入位置,时间复杂度为O(logn)O(logn)O(logn),再利用list的insert函数插入O(n)O(n)O(n),插入元素的时间复杂度为O(logn)+O(n)=o(n)O(logn)+O(n)=o(n)O(logn)+O(n)=o(n),查询中位数的时候,直接按位置索引即可,查询的时间复杂度为O(1)O(1)O(1)。需要注意的是,如果一个插入的元素比当前列表中所有元素都小,二分查找是找不出应该插入位置的,原创 2021-04-28 16:50:30 · 163 阅读 · 0 评论 -
leetcode专题训练315. Count of Smaller Numbers After Self
一开始就联想到了用归并排序求逆序数这道题,可是当时求逆序数的时候,不需要知道逆序数出现在哪个位置,只用记录逆序数个数即可,所以改了一下当时的代码,利用index数组记录某位置的元素的初始位置,再通过result[index[pos]] += 1即可把当前逆序数加入到原位置的结果。然而我写的加入到原位置的代码会超时。超时代码:class Solution: def countSmaller(self, nums: List[int]) -> List[int]:原创 2021-04-28 15:24:15 · 193 阅读 · 0 评论 -
leetcode专题训练 218. The Skyline Problem
最开始看到这道题先想的线段树,后来发现并不用得上线段树。看题解直接把所有的线扫一遍就行了。参考题解写了一份代码,估计下回遇到这道题还是不会做哈哈哈哈哈。import queueclass Node: def __init__(self, x, y): self.x = x self.y = y def __lt__(self, other): if self.x == other.x: return self.y原创 2021-04-27 15:30:22 · 191 阅读 · 0 评论 -
leetcode专题训练149. Max Points on a Line
这道题1 <= points.length <= 300,所以直接计算任意两点之间的斜率,并把到同一个点相同斜率的点的个数记下来,再和当前结果比较就可以了。时间复杂度O(n2)O(n^2)O(n2)。需要注意的斜率为无穷的情况。class Solution: def maxPoints(self, points: List[List[int]]) -> int: l = len(points) dic = [dict() for i in rang原创 2021-04-26 16:23:17 · 174 阅读 · 0 评论 -
leetcode专题训练140. Word Break II
直接DFS就可以了,由于之前的字符串都匹配上之后,才涉及之后的字符串是否能匹配上的问题,所以问题就可以转化为逐步获取目标字符串,就又转化为了路径问题。import collectionsclass Solution: def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: ls = len(s) dictWord = collections.defaultdict(list)原创 2021-04-26 15:45:50 · 156 阅读 · 0 评论 -
leetcode专题训练127. Word Ladder
最先想出的方法的时间复杂度是O(n2l)O(n^2l)O(n2l)的,其中n是wordList长度,l是单词长度,果然超时了。import queueclass Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: lWord = len(beginWord) lList = len(wordList) # 连原创 2021-04-26 14:54:10 · 204 阅读 · 0 评论 -
leetcode专题训练297. Serialize and Deserialize Binary Tree
BFS层次遍历整棵树,按层保存所有节点的值,由于要回复回原树,所以None值也要保存,在本代码中,None位置在字符串中用’N’表示。需要注意负数和多位数的情况,所以使用e来代表一个数的结尾,从而可以处理该情况。在回复树的结构的时候,按层恢复即可。(看题解可以先把str用split函数处理,就不用我代码中复杂的找’e’位置的过程了)# Definition for a binary tree node.# class TreeNode(object):# def __init__(self,原创 2021-04-25 16:15:10 · 200 阅读 · 0 评论 -
leetcode专题训练301. Remove Invalid Parentheses
DFS一般用在路径求解问题上,这道题也算是一种变形的路径求解。具体的路径选择就是要不要添加当前的括号。这道题和第85题均是先对当前的数据遍历,进行了一次处理之后再往下做。就相当于把问题分解为两部分了。第一部分先遍历字符串,求出整个字符串中需要删除的左括号数和右括号数,分别存在leftRemove和rightRemove中。第二部分再对字符串进行深度优先搜索DFS,如果遍历到字符串尾后,所有该删除的左括号和右括号都被删除了,那么就说明找到了一条路径,找到了一个解。在DFS时,对是否向路径添加某个符号的过程进行原创 2021-04-25 14:16:58 · 167 阅读 · 0 评论 -
leetcode专题训练312. Burst Balloons
解法1:主要思路就是将戳气球的问题转化为往区间里加气球的问题,也就是将整个过程逆过来。solve(i, j)代表着(i, j)区间内所有气球全部被加好后,最多的coin个数。遍历(i,j)区间内第一个可以加的气球的位置mid,由于其他气球都还没加,所以此时加mid后coin个数为nums[mid]*nums[i]*nums[j],之后再以mid切割(i, j),分别计算solve(i, mid)和solve(mid, j)的值,便知道第一个加此mid位置时,最多能获得的coin数。遍历mid位置,取max原创 2021-04-22 22:26:03 · 190 阅读 · 0 评论 -
leetcode专题训练 239. Sliding Window Maximum
优先队列,需要学习一下优先队列的自定义排序,而且python的优先队列的get函数会在取队头的同时将其弹出(注意priorityqueue没有que[0]这个操作,只能通过queue.get()取元素,collections的deque有que[0]操作,可取队列头)。import queueclass Node: def __init__(self, num, index): self.num = num self.index = index原创 2021-04-21 22:03:40 · 147 阅读 · 0 评论 -
leetcode专题训练85. Maximal Rectangle
84题的升级版。将到每个位置的最长的连续序列长度记录到left数组中,就转化为了85题了。切记,写完代码,一定先要看特殊情况,测完所有样例,之后算时间复杂度**,最好是在写代码之前就算好。class Solution: def maximalRectangle(self, matrix: List[List[str]]) -> int: if not matrix: return 0 row = len(matrix)原创 2021-04-19 16:38:53 · 192 阅读 · 1 评论 -
leetcode专题训练128. Longest Consecutive Sequence
直接排序一下,再找连续就好了。class Solution: def longestConsecutive(self, nums: List[int]) -> int: nums.sort() l = len(nums) if l == 0: return 0 maxLen = 1 left = 0 nowLen = 1 for r in range(1,原创 2021-04-16 17:28:33 · 149 阅读 · 0 评论 -
leetcode专题训练124. Binary Tree Maximum Path Sum
这道题是很普通的一道DFS,思路大概就是深度优先遍历树中所有节点,返回以当前节点开始的最长的单边路径的长度,而由于路径可以是左子树连到根连到右子树,所以最长的路径为max(root.val, root.val+max(maxLeft, maxRight))。然而我居然WA了两次,第一次是因为调用函数时调用错了,第二次是因为忽略了左右边的最长路径都可能为负值的情况,切记切记。到时候笔试的时候可不会提示错误用例。写法一:# Definition for a binary tree node.# class原创 2021-04-15 22:55:56 · 219 阅读 · 0 评论 -
leetcode专题训练647. Palindromic Substrings
这道题我的思路是找到所有可能的中心位置,再从中心位置扩展,找到所有的回文子串。比如一个长度为5的串,其中心位置可能为0、1、2、3、4索引位置,那么回文子串长度就为奇数,也可能是0、1之间,1、2之间,2、3之间,3、4之间,4、5之间,那么回文子串长度就为偶数。从中心位置开始往外扩展,直到扩展到边界或者不再是回文子串。具体看注释。class Solution: def countSubstrings(self, s: str) -> int: l = len(s)原创 2021-04-14 23:23:37 · 150 阅读 · 0 评论 -
leetcode专题训练146. LRU Cache
解法1:解法1我是当作大模拟来做的。由于key如果被用,那么无论之前在什么位置,都要被换到最新使用的位置。所以一直在想什么数据结构可以灵活换位置,后来发现可以用链表,所以维护了一个链表,链表中的顺序由最远使用到最近使用。而且由于需要把最远使用的弹出,把最新使用的插入,所以链表的头和尾都需要有个指针指示。在本代码中,分别使用cache_head和cache_tail表示。而取键值的操作,为了不每次都从链表头遍历,我使用了一个dict数据结构,这个数据结构单纯的用于存储LRU中的键值,取值的复杂度为O(1),原创 2021-04-12 23:10:13 · 173 阅读 · 0 评论 -
leetcode专题训练 97. Interleaving String
这道题是一道动态规划的题,首先要判断空的异常情况,之后判断s1和s2合并后字符串长度和s3不同的情况,然后就是动态规划了。动态规划公式:dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and s2[j-1] == s3[i+j-1])其中i和j分别代表着到s1的第i个数,到s2的第j个数,所以到取s1或s2种索引时,要相应的减1。dp[i][j]为True则说明到s1的前i个数,s2的前j个数,可以组合成s3的前(i+j)原创 2021-04-11 23:50:32 · 129 阅读 · 0 评论 -
leetcode专题训练96 Unique Binary Search Trees
解法1:这道题和95题 Unique Binary Search Trees II很像,但是解题思路却相差很多。先用上一道题的思路按照递归写了一下,最后TLE超时了,后来想了一下超时原因,发现这道题由于只用输出个数,不用输出具体的树,所以右边界和左边界的差值相同的子树,数量都是相同的,所以就可以打个表,把已经算过的右边界和左边界的差值记录下来,下次再遇到相同的范围时,可以直接从表中获得结果,不用再回溯了。需要注意在为表赋初始值时,一定要注意这个初始值能否真正到达。最开始我设置了result_list[1原创 2021-04-09 21:08:52 · 183 阅读 · 0 评论 -
leetcode专题训练95 Unique Binary Search Trees II
有关树的问题时,一定要先想到回溯法,因为树独特的结构,使得问题在很多情况下可以由整个树的问题分解为左子树和右子树的问题,从而逐步解决问题。二叉搜索树关键的性质是根节点的值大于左子树所有节点的值,小于右子树所有节点的值,且左子树和右子树也同样为二叉搜索树。这道题的目标是找到有n个节点的所有的不同结构的二叉搜索树。而由于这些二叉搜索树的左右子树也均为二叉搜索树,所以可以将问题由之前的找[1, n]范围内的所有二叉搜索树,转化为找[1, i-1]、[i+1, n]范围内的所有二叉搜索树,也就是将问题分解为找以i原创 2021-04-09 19:39:37 · 141 阅读 · 0 评论 -
leetcode专题训练 94. Binary Tree Inorder Traversal
这道题是求中序遍历的题,可以用回溯法,也可以用迭代吗法回溯法# 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 = rightclass Solution: def Inorde原创 2020-09-21 18:33:32 · 176 阅读 · 0 评论 -
leetcode专题训练 93. Restore IP Addresses
直接dfs搞一发就行了,遍历’.'的所有可能情况,然后输出可行解。需要判断s的长度大于12的情况,因为这样肯定是不合法的,如果不判定会超时。还需要注意s1 == str(num)这条判断语句,因为’025’转化为int类型后也是在0和255之内,但不是合法的,所以需要通过s1 == str(num)语句来判断这类不合法的字符串。class Solution: def restoreIpAddresses(self, s: str) -> List[str]: def isVa原创 2020-09-21 16:50:47 · 162 阅读 · 0 评论 -
leetcode专题训练 92. Reverse Linked List II
这道题是第206题的升级版,与206题不同的是,这道题限制了反转的范围。206题的代码如下:# Definition for singly-linked list.# class ListNode:# def __init__(self, x):# self.val = x# self.next = Noneclass Solution: def reverseList(self, head: ListNode) -> ListNode:原创 2020-09-16 13:15:47 · 282 阅读 · 0 评论 -
leetcode专题训练 206. Reverse Linked List
反转链表的问题,prev存储当前p的前一个结点,也就是反转之后当前p应该指向的结点,p1存储当前p的下一个结点,用于p的更新。反转时,核心语句为p.next=prev,之后依次更新prev和p。当p为None时反转完毕,此时的prev就是新链表的头。# Definition for singly-linked list.# class ListNode:# def __init__(self, x):# self.val = x# self.next = N原创 2020-09-15 21:08:37 · 193 阅读 · 0 评论 -
leetcode专题训练 91. Decode Ways
这道题最开始用的暴力,直接TLE。后来看了题解说用动规。当前位置i的所有方案有两种转移方式,一种是通过dp[i-1]转移,也就是在s[i]为一个合规的可代表字母时,dp[i]+=dp[i-1];第二种转移方式是通过dp[i-2]转移,在s[i-1: i+1]为一个合规的可代表字母时,dp[i]+=dp[i-2]。然而需要注意的是,为了使得dp过程更加简洁,在dp数组的最边又加了一位1,当作哨兵,就不用单独处理s[1]这个位置时的dp[i-2]了。这样加了哨兵之后,s与dp之间错了一位,要注意。通过此题知道原创 2020-09-15 09:35:26 · 171 阅读 · 0 评论 -
leetcode专题训练 90. Subsets II
这道题是第78题的升级版,78题中所给数组的元素都是不相同的,所以直接回溯搞一发,每个元素都加或不加搞一发即可。然而这道题中元素可能是相同的,所以不能直接每个元素加或不加来搞。比如样例中的[1, 2, 2],只加前面的那个2和只加后面那个2的结果是重复的,所以需要对相同的数进行判断。在78题中,一个长为l的数组,子集list的第一个元素可以是数组中的每一个元素,第二个元素就是第一个元素的索引之后的数组中的每一个元素,以此类推。解法如下:class Solution: def subsets(se原创 2020-09-14 21:38:58 · 217 阅读 · 0 评论 -
leetcode专题训练 89. Gray Code
很简单的一道题,找规律就好。class Solution: def grayCode(self, n: int) -> List[int]: if n == 0: return [0] if n == 1: return [0, 1] code = [0, 1] addnum = 2 for i in range(n-1): tmpcode原创 2020-08-30 12:19:16 · 219 阅读 · 0 评论 -
leetcode专题训练 86. Partition List
这道题是要将小于x的节点全部放在大于等于x的节点左边,且小于部分和大于等于部分的节点顺序必须是初始顺序。看到这道题后,就想到创建两个链表,一个链表存储小于x的节点,一个链表存储大于等于x的节点,然后依次遍历原始的链表,遍历完之后将大于等于x的节点接在小于x的节点后面即可。# Definition for singly-linked list.# class ListNode:# def __init__(self, x):# self.val = x# se原创 2020-08-04 17:47:37 · 181 阅读 · 0 评论 -
leetcode专题训练 84. Largest Rectangle in Histogram
1. 方法一:代码比较多若一个位置的高度为h1h_1h1,在栈内,那么就说明后面有可能出现高为h1h_1h1而宽度更大的矩形,如果不在栈内,那么就说明后面不可能出现高为h1h_1h1而宽度更大的矩形。可以通过以下方式判断有没有可能出现高为h1h_1h1而宽度更大的矩形:如果h1h_1h1右边的高度h2h_2h2比h1h_1h1要小,那么右边界就卡死了,高h1h_1h1的矩形的宽度就不能更大了,高h1h_1h1的最大面积矩形已经确定,就可以将h1h_1h1弹出栈,同时计算面积。然而原创 2020-07-30 15:44:46 · 173 阅读 · 0 评论 -
leetcode专题训练 82. Remove Duplicates from Sorted List II
又是一道模拟题。这道题是要消除所有有重复值的节点,而且链表中的数是有序的。那么判断当前节点是否要删除,就是要判断当前节点是否和上一个节点的值相等,是否和下一个节点的值相等,满足一个相等条件,则删除这个节点。在本代码中,通过记录上一个节点的值来判断是否和上一个节点值相等(此处需要对表头特殊处理,因为表头没有上一指针。在本代码中,利用flag来标记是否是表头,若是表头,则不与上一节点值比较),通过p1.next is not None and p1.val == p1.next.val来判断是否和下一个节点值相原创 2020-07-29 11:09:36 · 186 阅读 · 0 评论 -
leetcode专题训练 81. Search in Rotated Sorted Array II
这道题是33. Search in Rotated Sorted Array的升级版,与之前不同的地方是这道题允许存在重复的数字。在之前的33题题解中,我采用的是先找pivot的方法,也就是先找到数组中最大的元素,这样的话,最大的元素两侧都是有序数组,再分别在这两边进行二分查找即可。然而在这道题中,参考了题解的方法,不用先找pivot。二分归到底就是要知道接下来要去左半边找还是去右半边找,题解中判断的方式就很巧妙。首先得到mid,也就是数组的中间位置。如果中间位置的左边有序,那么就可以通过判断num原创 2020-07-28 19:34:41 · 260 阅读 · 0 评论 -
leetcode专题训练 80. Remove Duplicates from Sorted Array II
最开始也想过用题解中的第一种方法,也就是直接用python list的pop函数,c++ vector的erase函数,可是如果直接用这种函数的话,空间复杂度满足要求,但是时间复杂度会很高,因为这种函数的时间复杂度是O(n)的。考虑最坏情况,一个长度为n的数组中所有的数字都是相同的,那么就需要执行(n-2)次删除函数,那么整体时间复杂度是O(n2n^2n2)的。所以在本代码中采用的是官方题解中的另一种方法。这个方法使用了两个指针,一个指针i用于存储当前处理到了哪个元素,另一个指针j用于存储当前有效的数组到原创 2020-07-27 13:11:10 · 154 阅读 · 0 评论 -
leetcode专题训练 79. Word Search
需要注意的就是已经用过的点不能再用,所以要设置一个vis数组来存储是否用过。class Solution: def exist(self, board: List[List[str]], word: str) -> bool: if word == '': return True if board is None: return False r = len(board) c =原创 2020-07-26 13:05:41 · 236 阅读 · 0 评论 -
leetcode专题训练 78. Subsets
直接回溯法搞一发即可,和77差不多。class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: output = [] l = len(nums) def backtrack(begin: int, cur: List[int]): output.append(cur[:]) for i in range(begi原创 2020-07-25 10:59:27 · 172 阅读 · 0 评论 -
leetcode专题训练 77. Combinations
方法1这道题用递归的方法即可。我的想法是,k=n时的所有排列组合result,一定是由k=n-1时的排列组合tmp和一个新数组成。class Solution: def solve(self, begin: int, end: int, k: int) -> List[List[int]]: if k == 1: return [[i] for i in range(begin, end+1)] result = [] .原创 2020-07-24 11:57:22 · 200 阅读 · 0 评论 -
leetcode专题训练 357. Count Numbers with Unique Digits
这道题是一个找规律的题,能推dp。但是我第一遍wa了,因为我在n=3的时候,不应该直接用dp[2]的值乘上(11-i)来计算,因为dp[2]中不止包含了两位的每位不同的数,还包含了一位的每位不同的数,所以要另外定义一个变量tmp来保存两位的每位不同的数。这时候新构成的数就都是三位的每位都不同的数,然后将三位的这种数的个数加上dp[2],即为dp[3]的值。class Solution: def countNumbersWithUniqueDigits(self, n: int) -> int原创 2020-07-23 17:06:45 · 216 阅读 · 0 评论 -
leetcode专题训练 103. Binary Tree Zigzag Level Order Traversal
这道题我最开始的思路是直接将树用层序遍历输出,得到没有zigzag过的层序遍历结果,然后再对这个结果进行处理,将从右向左的行,通过python的逆向切片操作[::-1]来得到最后的结果。不过后来想了一下,在层序遍历时,就可以知道哪一行是向左,哪一行是向右,所以直接在层序遍历时处理即可。最终思路:首先是层序遍历。定义两个队列,一个是queue一个是nextqueue,因为需要区分不同的层,所以需要定义两个队列。这里需要注意的是区分不同层的方法。将当前层存储在queue中,下一层存储在nextqueue中,原创 2020-07-23 16:49:42 · 148 阅读 · 0 评论 -
剑指offer 对称的二叉树
1.方法1看到这道题我的想法是如果两棵树对称,那么他们的前序遍历、后序遍历和中序遍历之间应该有关系,所以我尝试着写了一棵树的前序中序和后序遍历。就比如这棵树的前序遍历是8,6,5,7,6,7,58, 6, 5, 7, 6, 7, 58,6,5,7,6,7,5,后序遍历是5,7,6,7,5,6,85, 7, 6, 7, 5, 6, 85,7,6,7,5,6,8。又尝试着写了其他树的前序和后序遍历,发现如果一棵树是对称的,那么这棵树的前序遍历和后序遍历是相反的。也就是如果一棵树的前序遍历的逆序就是其后序遍原创 2020-06-12 19:25:15 · 225 阅读 · 0 评论