赞
踩
有基础的话,可以直接去w3school看教程复习一下基本语法。
之前用C++做过力扣,这次用py再做一遍,当作复习。之前的博客:http://t.csdnimg.cn/oWX7v
持续更新中,一天做几道,欢迎follow
https://leetcode.cn/problems/two-sum
暴力
class Solution(object):
def twoSum(self, nums, target):
for i in range(0, len(nums)-1):
for j in range(i+1, len(nums)):
if (target == nums[i] + nums[j]):
return [i, j]
return []
哈希表降低搜索复杂度
class Solution(object):
def twoSum(self, nums, target):
hashtable = dict()
for i, num in enumerate(nums):
if (target - num in hashtable.keys()):
return [hashtable[target-num], i]
hashtable[num] = i
return []
https://leetcode.cn/problems/group-anagrams
排序,当作key
class Solution(object):
def groupAnagrams(self, strs):
my_dict = dict()
for s in strs:
s1 = sorted(s)
s1 = str(s1)
if s1 in my_dict:
my_dict[s1].append(s)
else:
my_dict[s1] = [s]
res = []
res = my_dict.values()
return res
用字母出现的次数当作key
class Solution(object):
def groupAnagrams(self, strs):
my_dict = dict()
for st in strs:
counts = [0] * 26
for ch in st:
counts[ord(ch) - ord('a')] += 1
if tuple(counts) in my_dict.keys():
my_dict[tuple(counts)].append(st)
else:
my_dict[tuple(counts)] = [st]
return my_dict.values()
https://leetcode.cn/problems/longest-consecutive-sequence/
class Solution(object):
def longestConsecutive(self, nums):
myset = set(nums)
res = 0
for s in myset:
if (s-1 not in myset):
n, tmp = 1, s+1
while (tmp in myset):
n += 1
tmp += 1
res = max(n, res)
else:
continue
return res
双指针,交换元素
class Solution(object):
def moveZeroes(self, nums):
i = j = 0
n = len(nums)
while j < n:
if (nums[j] != 0):
nums[i], nums[j] = nums[j], nums[i]
i += 1
j += 1
return nums
https://leetcode.cn/problems/container-with-most-water
双指针,移动板,更新水
class Solution(object):
def maxArea(self, height):
l, r, res = 0, len(height)-1, 0
while l < r:
res = max(res, (r-l)*min(height[l], height[r]))
if height[l] < height[r]:
l += 1
else:
r -= 1
return res
https://leetcode.cn/problems/3sum
排序,遍历,双指针,记得答案去重。
class Solution(object): def threeSum(self, nums): n, res = len(nums), [] if (n < 3): return nums.sort() for i in range(n): if i > 0 and nums[i] == nums[i-1]: continue l, r = i+1, n-1 while l < r: sum = nums[i] + nums[l] + nums[r] if (sum < 0): l += 1 elif (sum > 0): r -= 1 else: res.append([nums[i], nums[l], nums[r]]) while l < r and nums[l] == nums[l+1]: l += 1 while l < r and nums[r] == nums[r-1]: r -= 1 l += 1 r -= 1 return res
按列计算,第i列的雨水 = min(左边最高墙的高度,右边最高墙的高度) - 第i列的墙高,O(N2)复杂度,超时了。
class Solution(object):
def trap(self, height):
n, res = len(height), 0
for i in range(n):
if (i == 0 or i == n-1):
continue
l, r = 0, 0
for j in range(0, i):
l = max(l, height[j])
for k in range(i+1, n):
r = max(r, height[k])
if min(l, r) - height[i] > 0:
res += min(r, l) - height[i]
return res
dp优化上述过程,O(N)复杂度
class Solution(object): def trap(self, height): n, res = len(height), 0 left, right = [0]*n, [0]*n left[0], right[n-1] = height[0], height[n-1] for i in range(1, n): left[i] = max(left[i-1], height[i]) for j in range(n-2, 0, -1): right[j] = max(right[j+1], height[j]) for k in range(n): if (k == 0 or k == n-1): continue tmp = min(left[k], right[k]) - height[k] if tmp > 0: res += tmp return res
https://leetcode.cn/problems/longest-substring-without-repeating-characters
滑动窗口思想的模拟
class Solution(object):
def lengthOfLongestSubstring(self, s):
res, tmp = 0, ''
for ch in s:
while tmp.find(ch) > -1:
tmp = tmp[1:]
tmp += ch
res = max(res, len(tmp))
return res
滑动窗口,哈希集检测重复字符
class Solution(object):
def lengthOfLongestSubstring(self, s):
res = 0
hashset = set()
n = len(s)
j = -1
for i in range(n):
if i != 0:
hashset.remove(s[i-1])
while j+1 < n and s[j+1] not in hashset:
hashset.add(s[j+1])
j += 1
res = max(res, j-i+1)
return res
https://leetcode.cn/problems/find-all-anagrams-in-a-string
滑动窗口模拟,可惜超时了
class Solution(object): def findAnagrams(self, s, p): res = [] n, n1 = len(s), len(p) for i in range(n): cnt = 0 tmp_p = p if s[i] in tmp_p: cnt += 1 tmp_p = tmp_p.replace(s[i], '', 1) right = i while right+1 < n and s[right+1] in tmp_p: cnt += 1 tmp_p = tmp_p.replace(s[right + 1], '', 1) right += 1 if cnt == n1: res.append(i) return res
滑动窗口,窗口的长度 = p的长度
class Solution(object): def findAnagrams(self, s, p): """ :type s: str :type p: str :rtype: List[int] """ res = [] ns, np = len(s), len(p) if ns < np: return res s_cnt = [0]*26 p_cnt = [0]*26 for i in range(np): s_cnt[ord(s[i]) - ord('a')] += 1 p_cnt[ord(p[i]) - ord('a')] += 1 if s_cnt == p_cnt: res.append(0) for i in range(1, ns-np+1): s_cnt[ord(s[i-1])-ord('a')] -= 1 s_cnt[ord(s[i+np-1]) - ord('a')] += 1 if s_cnt == p_cnt: res.append(i) return res
https://leetcode.cn/problems/subarray-sum-equals-k
神中神的题解,前缀和+字典。
使用暴力会超时
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
dic = {0: 1}
sums, res = 0, 0
for num in nums:
sums += num
res += dic.get(sums-k, 0)
dic[sums] = dic.get(sums, 0)+1
return res
使用前缀和的方法可以解决这个问题,因为我们需要找到和为k的连续子数组的个数。通过计算前缀和,我们可以将问题转化为求解两个前缀和之差等于k的情况。
假设数组的前缀和数组为prefixSum,其中prefixSum[i]表示从数组起始位置到第i个位置的元素之和。那么对于任意的两个下标i和j(i < j),如果prefixSum[j] - prefixSum[i] = k,即从第i个位置到第j个位置的元素之和等于k,那么说明从第i+1个位置到第j个位置的连续子数组的和为k。
通过遍历数组,计算每个位置的前缀和,并使用一个哈希表来存储每个前缀和出现的次数。在遍历的过程中,我们检查是否存在prefixSum[j] - k的前缀和,如果存在,说明从某个位置到当前位置的连续子数组的和为k,我们将对应的次数累加到结果中。
这样,通过遍历一次数组,我们可以统计出和为k的连续子数组的个数,并且时间复杂度为O(n),其中n为数组的长度。
【单调队列 滑动窗口最大值【基础算法精讲 27】】 https://www.bilibili.com/video/BV1bM411X72E/?share_source=copy_web&vd_source=aa3fec063f2bca95bca01c76f6509322
class Solution(object): def maxSlidingWindow(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ res = [] q = deque() for i, x in enumerate(nums): # 入 while q and nums[q[-1]] <= x: q.pop() q.append(i) # 出 if i - q[0] >= k: q.popleft() # 记录答案 if i >= k-1: res.append(nums[q[0]]) return res
https://leetcode.cn/problems/minimum-window-substring
滑动窗口,字典记录是否覆盖了t;对于每一个右边界,寻找size最小的左边界,记录答案。
class Solution(object): def minWindow(self, s, t): """ :type s: str :type t: str :rtype: str """ dic = dict() need_cnt = len(t) # 把t存入字典中,后面的窗口要用到 for ch in t: dic[ch] = dic.get(ch, 0) + 1 left, start = 0, 0 size = 100010 for right, ch in enumerate(s): if dic.get(ch, 0) > 0: need_cnt -= 1 dic[ch] = dic.get(ch, 0) - 1 if need_cnt == 0: # 移动左边界,剔除多余的字符 while dic[s[left]] < 0: c = s[left] dic[c] += 1 left += 1 # 如果size更短了,更新答案 if right-left+1 < size: size = right - left + 1 start = left # 破坏左边界,开始下一轮 dic[s[left]] += 1 left += 1 need_cnt += 1 if size != 100010: return s[start:start + size] return ''
https://leetcode.cn/problems/maximum-subarray
dp:
状态转移:以第i位结尾的最大数组和 = max(nums[i],以第i-1位结尾的最大数组和+nums[i])
class Solution(object):
def maxSubArray(self, nums):
for i, num in enumerate(nums):
if i==0:
res = nums[0]
pre = nums[0]
else:
pre = max(pre + num, num)
res = max(res, pre)
return res
更骚的:
如果你是负的,那就用0来代替你,然后从新开始
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
nums[i] += max(nums[i - 1], 0)
return max(nums)
方法二:分治的思想
class Solution(object): def maxSubArray(self, nums): """ :type nums: List[int] :rtype: int """ def sub(nums, l, r): if l == r: return nums[l] mid = (l+r) >> 1 return max(sub(nums, l, mid), sub(nums, mid+1, r), cross(nums, l, mid, r)) def cross(nums, l, mid, r): left_sum_max = 0 start_left = mid-1 s1 = 0 while start_left >= l: s1 += nums[start_left] left_sum_max = max(left_sum_max, s1) start_left -= 1 right_sum_max = 0 start_right = mid+1 s2 = 0 while start_right <= r: s2 += nums[start_right] right_sum_max = max(right_sum_max, s2) start_right += 1 return left_sum_max + nums[mid] + right_sum_max n = len(nums) if n == 0: return 0 return sub(nums, 0, n-1)
https://leetcode.cn/problems/merge-intervals
先对最左端点排序,然后merge
class Solution(object): def merge(self, intervals): """ :type intervals: List[List[int]] :rtype: List[List[int]] """ res = [] intervals.sort() n = len(intervals) i = 0 while i < n: l, r = intervals[i][0], intervals[i][1] while i+1 < n and r >= intervals[i+1][0]: r = max(r, intervals[i+1][1]) i += 1 res.append([l, r]) i += 1 return res
https://leetcode.cn/problems/rotate-array
方法一:时间空间复杂度都是O(N)
class Solution(object):
def rotate(self, nums, k):
new_nums = list(nums)
n = len(nums)
for i in range(n):
nums[(i+k) % n] = new_nums[i]
方法二:旋转
nums = "----->-->"; k =3
result = "-->----->";
reverse "----->-->" we can get "<--<-----"
reverse "<--" we can get "--><-----"
reverse "<-----" we can get "-->----->"
this visualization help me figure it out :)
class Solution(object): def rotate(self, nums, k): """ :type nums: List[int] :type k: int :rtype: None Do not return anything, modify nums in-place instead. """ def reverse(i, j): while i < j: nums[i], nums[j] = nums[j], nums[i] i += 1 j -= 1 n = len(nums) reverse(0, n-1) reverse(0, k % n-1) reverse(k % n, n-1)
https://leetcode.cn/problems/product-of-array-except-self
太难了,O(N)的复杂度并且还不能使用除法
class Solution(object): def productExceptSelf(self, nums): """ :type nums: List[int] :rtype: List[int] """ n = len(nums) res = [1]*n l, r = 1, 1 # 从左右开始累乘 for i in range(n): # 左边的乘积 res[i] *= l l *= nums[i] # 右边的乘积 res[n-1-i] *= r r *= nums[n-1-i] return res
哈希表记录,时间空间复杂度都是O(N)
class Solution(object):
def firstMissingPositive(self, nums):
s = set()
n = len(nums)
for num in nums:
s.add(num)
for i in range(1, n+1):
if i not in s:
return i
return n+1
时间N,空间1
from typing import List class Solution: # 3 应该放在索引为 2 的地方 # 4 应该放在索引为 3 的地方 def firstMissingPositive(self, nums: List[int]) -> int: size = len(nums) for i in range(size): # 先判断这个数字是不是索引,然后判断这个数字是不是放在了正确的地方 while 1 <= nums[i] <= size and nums[i] != nums[nums[i] - 1]: self.__swap(nums, i, nums[i] - 1) for i in range(size): if i + 1 != nums[i]: return i + 1 return size + 1 def __swap(self, nums, index1, index2): nums[index1], nums[index2] = nums[index2], nums[index1] 作者:liweiwei1419 链接:https://leetcode.cn/problems/first-missing-positive/solutions/7703/tong-pai-xu-python-dai-ma-by-liweiwei1419/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://leetcode.cn/problems/set-matrix-zeroes
两个bool数组记录行列是否为0,然后再遍历一次,为matrix置零。
时间复杂度:O(mn)
空间复杂度:O(m+n)
class Solution(object): def setZeroes(self, matrix): """ :type matrix: List[List[int]] :rtype: None Do not return anything, modify matrix in-place instead. """ m, n = len(matrix), len(matrix[0]) helper_m, helper_n = [False]*m, [False]*n for i in range(m): for j in range(n): if matrix[i][j] == 0: helper_m[i] = helper_n[j] = True for i in range(m): for j in range(n): if helper_m[i] or helper_n[j]: matrix[i][j] = 0
优化空间复杂度,挺没意思的。。。
时间复杂度:O(mn)
空间复杂度:O(1)
class Solution(object): def setZeroes(self, matrix): """ :type matrix: List[List[int]] :rtype: None Do not return anything, modify matrix in-place instead. """ m, n = len(matrix), len(matrix[0]) # 记录第一行和第一列是否有0 flag_col0, flag_row0 = False, False for i in range(m): if matrix[i][0] == 0: flag_col0 = True for j in range(n): if matrix[0][j] == 0: flag_row0 = True # 将各个元素的0信息记录到第一行和第一类中,例如matrix[5][3]==0,那么matrix[5][0] = matrix[0][3] = 0 for i in range(1, m): for j in range(1, n): if matrix[i][j] == 0: matrix[i][0] = 0 matrix[0][j] = 0 # 根据第一行和第一列中记录的信息为matrix置零 for i in range(1, m): for j in range(1, n): if matrix[i][0] == 0 or matrix[0][j] == 0: matrix[i][j] = 0 # 处理matrix的第一行和第一列 if flag_col0: for i in range(m): matrix[i][0] = 0 if flag_row0: for j in range(n): matrix[0][j] = 0
https://leetcode.cn/problems/spiral-matrix
顺时针螺旋打印矩阵
可以通过总元素个数跳出循环,也可以通过l r t b判断来跳出循环
class Solution(object): def spiralOrder(self, matrix): """ :type matrix: List[List[int]] :rtype: List[int] """ l, r, t, b = 0, len(matrix[0])-1, 0, len(matrix)-1 nums = (r+1)*(b+1) res = [] if not matrix or not matrix[0]: return res # while nums > 0: while l <= r and t <= b: # 最上行 for j in range(l, r+1): res.append(matrix[t][j]) nums -= 1 # 最右列 for i in range(t+1, b+1): res.append(matrix[i][r]) nums -= 1 if l < r and t < b: # 最下行 for j in range(r-1, l, -1): res.append(matrix[b][j]) nums -= 1 # 最左列 for i in range(b, t, -1): res.append(matrix[i][l]) nums -= 1 # 更新left right top bottom l, r, t, b = l + 1, r - 1, t + 1, b - 1 return res
https://leetcode.cn/problems/rotate-image
把一个矩阵顺时针旋转90度 = 先转置,再水平镜像
class Solution(object): def rotate(self, matrix): """ :type matrix: List[List[int]] :rtype: None Do not return anything, modify matrix in-place instead. """ n = len(matrix) # 先转置 for i in range(n): for j in range(i): matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] # 在水平镜像 for i in range(n): for j in range(n/2): matrix[i][j], matrix[i][n-1-j] = matrix[i][n-1-j], matrix[i][j]
方法一:从右上角开始搜索,如果该元素比target大,那么往左边搜索;如果小于target,那么往下搜索。
时间复杂度:O(n+m)
class Solution(object): def searchMatrix(self, matrix, target): """ :type matrix: List[List[int]] :type target: int :rtype: bool """ m, n = len(matrix), len(matrix[0]) i, j = 0, n-1 while i < m and j >= 0: if matrix[i][j] == target: return True elif matrix[i][j] > target: j -= 1 else: i += 1 return False
方法二:逐行/逐列二分
class Solution(object): def searchMatrix(self, matrix, target): def search(i, l, r): mid = (l+r)/2 while l <= r: if target == matrix[i][mid]: return mid elif target < matrix[i][mid]: return search(i, l, mid-1) else: return search(i, mid+1, r) m, n = len(matrix), len(matrix[0]) for i in range(m): if search(i, 0, n-1) >= 0: return True return False
https://leetcode.cn/problems/intersection-of-two-linked-lists/
方法一:哈希表或哈希集
时间:O(M+N)
空间:O(M)
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def getIntersectionNode(self, headA, headB): """ :type head1, head1: ListNode :rtype: ListNode """ dic = dict() while headA: dic[headA] = dic.get(headA, 0) + 1 headA = headA.next while headB: dic[headB] = dic.get(headB, 0) + 1 if dic[headB] == 2: return headB headB = headB.next return None
方法二:双指针
时间:O(M+N)
空间:O(1)
初始化p,q分别指向头节点。
如果两链表相交,设A的长度为a+c,B的长度为b+c,那么p和q走过a+b+c长度之后,会指向同一节点。
如果两链表不相交,p和q走过a+b之后,都指向None,也会跳出while循环。
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA == None or headB == None:
return None
p, q = headA, headB
while p != q:
p = p.next if p else headB
q = q.next if q else headA
return p
https://leetcode.cn/problems/reverse-linked-list
迭代
开始的时候:pre, cur = None, head
结束的时候:pre = 反转后的链表的head,cur = None
# 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 reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ pre, cur = None, head while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre
递归
第一轮出栈,head为5,head.next为空,返回5 第二轮出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4, 把当前节点的子节点的子节点指向当前节点 此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null 此时链表为1->2->3->4<-5 返回节点5 第三轮出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3, 此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null 此时链表为1->2->3<-4<-5 返回节点5 第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2, 此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null 此时链表为1->2<-3<-4<-5 返回节点5 第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1, 此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null 此时链表为1<-2<-3<-4<-5 返回节点5 出栈完成,最终头节点5->4->3->2->1
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None:
return head
newHead = self.reverseList(head.next)
head.next.next = head
head.next = None
return newHead
https://leetcode.cn/problems/palindrome-linked-list
方法一:复制到数组中,再比较
时间和空间都是O(N)
# 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 isPalindrome(self, head): """ :type head: ListNode :rtype: bool """ nums = [] while head: nums.append(head.val) head = head.next return nums == nums[::-1]
方法二:先找到链表的中点,再翻转后半部分链表,再比较
时间:O(N)
空间:O(1)
class Solution(object): def isPalindrome(self, head): if head is None: return True # 先找到链表的中点 first_half_end = self.find_first_half(head) # 反转后半部分链表 second_half_start = self.reverse_list(first_half_end.next) while head and second_half_start: if head.val != second_half_start.val: return False head = head.next second_half_start = second_half_start.next return True def find_first_half(self, head): p = head q = head while q.next and q.next.next: p, q = p.next, q.next.next return p def reverse_list(self, head): pre, cur = None, head while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre
https://leetcode.cn/problems/linked-list-cycle
快慢指针,时间O(N),空间O(1)
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def hasCycle(self, head): """ :type head: ListNode :rtype: bool """ if not head: return False p = head q = head while q.next and q.next.next: p, q = p.next, q.next.next if p == q: return True return False
哈希集肯定也是可以的,空间复杂度更高一些。
https://leetcode.cn/problems/linked-list-cycle-ii
这是个数学题啊,还是快慢指针,接上题。
快慢指针在环中相遇后,相遇点不一定是环的入口。
此时让第三个指针从head出发,一次走一步,slow继续走,他们会在环的入口相遇。纯数学题。
class Solution(object): def detectCycle(self, head): """ :type head: ListNode :rtype: ListNode """ if not head: return None slow, fast = head, head while fast.next and fast.next.next: slow, fast = slow.next, fast.next.next if slow == fast: while head != slow: head, slow = head.next, slow.next return slow return None
方法一:双指针迭代
最开始申请一个dummy节点,整个过程中,dum是已完成的尾节点。
# 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 mergeTwoLists(self, list1, list2): """ :type list1: Optional[ListNode] :type list2: Optional[ListNode] :rtype: Optional[ListNode] """ dum = ListNode() res = dum p, q = list1, list2 while p and q: if p.val <= q.val: dum.next = p p = p.next else: dum.next = q q = q.next dum = dum.next dum.next = p if p else q return res.next
方法二:递归
class Solution(object):
def mergeTwoLists(self, list1, list2):
if list1 is None:
return list2
elif list2 is None:
return list1
elif list1.val < list2.val:
list1.next = self.mergeTwoLists(list1.next, list2)
return list1
else:
list2.next = self.mergeTwoLists(list1, list2.next)
return list2
这个图很好:l1 = 1, l2 = 3,那么l1.next =merge(l1的2,l2的3),,并且要 return l1
https://leetcode.cn/problems/add-two-numbers
方法一:模拟迭代
class Solution(object): def addTwoNumbers(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ carry = 0 res = dum = ListNode(-1) while l1 or l2: num1 = l1.val if l1 else 0 num2 = l2.val if l2 else 0 num, carry = (num1+num2+carry, 0) if num1+num2 + \ carry <= 9 else (num1+num2+carry-10, 1) dum.next = ListNode(num) dum = dum.next if l1: l1 = l1.next if l2: l2 = l2.next if carry: dum.next = ListNode(carry) return res.next
方法二:递归
class Solution(object): def addTwoNumbers(self, l1, l2): return self.helper(l1, l2, 0) def helper(self, l1, l2, carry): if l1 is None and l2 is None and carry == 0: return None sum1, sum2 = 0, 0 if l1: sum1 = l1.val l1 = l1.next if l2: sum2 = l2.val l2 = l2.next sum = sum1 + sum2 + carry node = ListNode(sum % 10) node.next = self.helper(l1, l2, sum / 10) return node
更简洁的写法
https://leetcode.cn/problems/add-two-numbers/solutions/2327008/dong-hua-jian-ji-xie-fa-cong-di-gui-dao-oe0di
class Solution(object):
def addTwoNumbers(self, l1, l2):
return self.helper(l1, l2, 0)
def helper(self, l1, l2, carry):
if l1 is None and l2 is None:
return ListNode(carry) if carry else None
if l1 is None: # 这个if是为了保证:l1总是l1和l2中,后为空的那个
l1, l2 = l2, l1
carry += l1.val + (l2.val if l2 else 0)
l1.val = carry % 10
l1.next = self.helper(l1.next, l2.next if l2 else None, carry/10)
return l1
https://leetcode.cn/problems/remove-nth-node-from-end-of-list
快慢指针
# 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 removeNthFromEnd(self, head, n): """ :type head: ListNode :type n: int :rtype: ListNode """ fast = head for i in range(n): fast = fast.next slow = ListNode(0, head) res = slow while fast: slow = slow.next fast = fast.next slow.next = slow.next.next return res.next
方法一:迭代
class Solution(object): def swapPairs(self, head): """ :type head: ListNode :rtype: ListNode """ if head is None or head.next is None: return head res = node0 = ListNode(0, head) while node0.next and node0.next.next: # 有两个节点就可以交换 node1, node2 = node0.next, node0.next.next node0.next = node2 # 0->2 node1.next = node2.next # 1->3 node2.next = node1 # 2->1 node0 = node1 return res.next
方法二:递归
请看注释。
class Solution(object): def swapPairs(self, head): """ :type head: ListNode :rtype: ListNode """ # 终止条件 if head is None or head.next is None: return head # 赋值 node1 = head node2 = head.next node3 = node2.next # node2 -> node1 -> 递归返回的链表头 node2.next = node1 node1.next = self.swapPairs(node3) return node2
https://leetcode.cn/problems/reverse-nodes-in-k-group
方法一:递归
class Solution(object): def reverseKGroup(self, head, k): """ :type head: ListNode :type k: int :rtype: ListNode """ cur = head cnt = 0 # 判断是否有k个节点 while cur and cnt < k: cur = cur.next cnt += 1 flag = True if cnt == k else False if flag: # 如果有k个,那么递归吧,返回的是啥画个图就懂了 cur = self.reverseKGroup(cur, k) while cnt: tmp = head.next head.next = cur cur = head head = tmp cnt -= 1 return cur else: # 没有k个,就不动,返回头节点 return head
方法二:纯模拟,没有任何技巧
class Solution(object): def reverseKGroup(self, head, k): """ :type head: ListNode :type k: int :rtype: ListNode """ dum = ListNode(0, head) pre = dum while head: tail = pre for i in range(k): tail = tail.next if not tail: return dum.next nex = tail.next head, tail = self.reverse(head, tail) pre.next, tail.next = head, nex pre = tail head = tail.next return dum.next # 翻转一个链表 def reverse(self, head, tail): dum = ListNode(0, head) pre = head cur = head.next while pre is not tail: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre, dum.next
https://leetcode.cn/problems/copy-list-with-random-pointer
前两种方法:时间空间都是N
方法一:哈希表,两次循环
""" # Definition for a Node. class Node: def __init__(self, x, next=None, random=None): self.val = int(x) self.next = next self.random = random """ class Solution(object): def copyRandomList(self, head): """ :type head: Node :rtype: Node """ if not head: return None cur = head dic = dict() # 把原链表和新构造的链表通过字典关联起来 while cur: dic[cur] = Node(cur.val) cur = cur.next cur = head # 再用一个循环完成对新链表每个结点的next域和random域的赋值 while cur: dic[cur].next = dic.get(cur.next) dic[cur].random = dic.get(cur.random) cur = cur.next return dic[head]
方法二:哈希表的递归写法
class Solution(object): dic = dict() def copyRandomList(self, head): """ :type head: Node :rtype: Node """ if not head: return None # 如果字典中没有当前节点,那么创建节点 if self.dic.get(head) is None: self.dic[head] = Node(head.val) # 检查next和random的情况,完成赋值 self.dic[head].next = self.copyRandomList(head.next) self.dic[head].random = self.copyRandomList(head.random) return self.dic[head]
方法三:复制连接,再断开
时间N,空间1
class Solution(object): def copyRandomList(self, head): """ :type head: Node :rtype: Node """ if head is None: return None cur = head # 1、复制各node,并建立连接:1->2->3 变成 1->1_new->2->2_new->3->3_new while cur: tmp = Node(cur.val) tmp.next = cur.next cur.next = tmp cur = tmp.next # 2、构建新链表的random指向 cur = head while cur: if cur.random: cur.next.random = cur.random.next cur = cur.next.next # 3、拆分两链表,返回新链表的头节点 cur = res = head.next pre = head while cur.next: pre.next = pre.next.next cur.next = cur.next.next pre, cur = pre.next, cur.next pre.next = None # 处理原链表的尾节点 return res
https://leetcode.cn/problems/sort-list
https://leetcode.cn/problems/sort-list/solutions/13728/sort-list-gui-bing-pai-xu-lian-biao-by-jyd
方法一:自顶向下归并
时间:O(nlogn)
空间:O(logn)
class Solution(object): def sortList(self, head): """ :type head: ListNode :rtype: ListNode """ # 1、终止条件。如果没有节点或者只有一个节点,那么return if head is None or head.next is None: return head # 2、找到中间节点并断开链表,递归下探。1->2->3->4 变成 1->2 3->4,mid是3 slow = fast = head while fast.next and fast.next.next: slow, fast = slow.next, fast.next.next mid = slow.next slow.next = None l, r = self.sortList(head), self.sortList(mid) # 3、合并两个有序链表 dum = res = ListNode() while l and r: if l.val <= r.val: dum.next = l l = l.next else: dum.next = r r = r.next dum = dum.next dum.next = l if l else r return res.next
方法二:自底向上归并。时间复杂度 O(nlogn),空间复杂度 O(1)
迭代的写法
class Solution(object): def sortList(self, head): """ :type head: ListNode :rtype: ListNode """ length, sublen = 0, 1 res = ListNode(0, head) # 1、得到链表的长度 while head: head = head.next length += 1 # 2、当sublen小于length时: while sublen < length: pre, cur = res, res.next while cur: # 找到第一个长度为sublen的链表,头节点为left left = cur for i in range(sublen-1): if cur.next: cur = cur.next else: break # 如果left长度没到sublen,直接将left附加到上一个链表结尾 if not cur.next: pre.next = left break # 找第二个长度为sublen的链表,头节点为right right = cur.next cur.next = None # 断开 cur = right for i in range(sublen-1): if cur.next: cur = cur.next else: break # 处理rihgt链表与后续链表 tmp = None if cur.next: tmp = cur.next cur.next = None cur = tmp # 将l和r这两个sublen长度的链表合并 merged = self.mergeTwo(left, right) pre.next = merged while pre.next: pre = pre.next sublen *= 2 return res.next def mergeTwo(self, l1, l2): dum = ListNode() res = dum while l1 and l2: if l1.val <= l2.val: dum.next = l1 l1 = l1.next else: dum.next = l2 l2 = l2.next dum = dum.next dum.next = l1 if l1 else l2 return res.next
https://leetcode.cn/problems/merge-k-sorted-lists
方法一:借用合并两个升序链表,遍历即可。
# 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 mergeKLists(self, lists): """ :type lists: List[ListNode] :rtype: ListNode """ l0 = None for l in lists: l0 = self.mergeTwo(l0, l) return l0 def mergeTwo(self, l1, l2): dum = ListNode() res = dum while l1 and l2: if l1.val <= l2.val: dum.next = l1 l1 = l1.next else: dum.next = l2 l2 = l2.next dum = dum.next dum.next = l1 if l1 else l2 return res.next
方法二:二分分治
class Solution(object): def mergeKLists(self, lists): return self.merge(lists, 0, len(lists)-1) def merge(self, lists, l, r): if l == r: return lists[l] if l > r: return None mid = (l+r)/2 return self.mergeTwo(self.merge(lists, l, mid), self.merge(lists, mid+1, r)) def mergeTwo(self, l1, l2): dum = ListNode() res = dum while l1 and l2: if l1.val <= l2.val: dum.next = l1 l1 = l1.next else: dum.next = l2 l2 = l2.next dum = dum.next dum.next = l1 if l1 else l2 return res.next
方法三:优先队列
python自带的heapq,利用val进行排序。先存第一列,再逐个pop最小的元素。
class Solution(object): def mergeKLists(self, lists): dum = ListNode() res = dum # 创建一个小顶堆 import heapq heap = [] # 将k个链表的第一个元素加入堆中 for i in range(len(lists)): if lists[i]: heapq.heappush(heap, (lists[i].val, i)) lists[i] = lists[i].next # 当堆不为空时 while heap: val, idx = heapq.heappop(heap) dum.next = ListNode(val) dum = dum.next if lists[idx]: heapq.heappush(heap, (lists[idx].val, idx)) lists[idx] = lists[idx].next return res.next
照着灵神的题解写的,本题使用双向链表 + 哈希表实现O(1)的LRU。增加一个dum节点简化流程。
https://leetcode.cn/problems/lru-cache/solutions/2456294/tu-jie-yi-zhang-tu-miao-dong-lrupythonja-czgt
# 定义一个类 class Node: def __init__(self, key=0, value=0): self.key = key self.value = value self.prev = None self.next = None # 解决方法为双向链表 + 字典 class LRUCache(object): def __init__(self, capacity): """ :type capacity: int """ self.capacity = capacity self.dum = Node() self.dum.prev = self.dum self.dum.next = self.dum self.dic = dict() def get(self, key): """ :type key: int :rtype: int """ node = self.get_node(key) return node.value if node else -1 def put(self, key, value): """ :type key: int :type value: int :rtype: None """ # 如果有这个节点,那么直接覆盖value即可 node = self.get_node(key) if node: node.value = value return # 如果没有key,就new一个 node = Node(key, value) self.dic[key] = node self.push_front(node) # 放在最上面 # 如果大于容量了,删掉最后一个 if len(self.dic) > self.capacity: last = self.dum.prev del self.dic[last.key] self.remove(last) # 通过key查询node def get_node(self, key): if key not in self.dic.keys(): return None node = self.dic[key] self.remove(node) self.push_front(node) return node # 删除一个node def remove(self, node): node.prev.next = node.next node.next.prev = node.prev # 在链表头,即dum后面,添加一个node def push_front(self, node): node.prev = self.dum node.next = self.dum.next node.prev.next = node node.next.prev = node # Your LRUCache object will be instantiated and called as such: # obj = LRUCache(capacity) # param_1 = obj.get(key) # obj.put(key,value)
方法一:递归
class Solution(object):
def inorderTraversal(self, root):
res = [] # 将 res 定义为方法内的局部变量
if not root:
return res # 返回空列表
return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
class Solution(object):
def inorderTraversal(self, root):
def dfs(cur):
if not cur:
return
dfs(cur.left)
res.append(cur.val)
dfs(cur.right)
res = []
dfs(root)
return res
方法二:迭代
显式地维护一个栈。
class Solution(object):
def inorderTraversal(self, root):
res = []
stk = []
cur = root
while cur or stk:
while cur:
stk.append(cur)
cur = cur.left
cur = stk.pop()
res.append(cur.val)
cur = cur.right
return res
方法一:dfs
class Solution(object):
def maxDepth(self, root):
if root is None:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right))+1
方法二:bfs,利用队列层序遍历
首先将root入队。对于每一层,先利用tmp存储它的下一层,再将tmp赋值给q,再++res
class Solution(object): def maxDepth(self, root): res = 0 if root is None: return res q = [root] tmp = [] while q: tmp = [] for node in q: if node.left: tmp.append(node.left) if node.right: tmp.append(node.right) q = tmp res += 1 return res
方法一:递归
class Solution(object): def invertTree(self, root): """ :type root: TreeNode :rtype: TreeNode """ def dfs(root): if not root: return if root.left or root.right: root.left, root.right = root.right, root.left dfs(root.left) dfs(root.right) dfs(root) return root
方法二:迭代
出栈一个节点,首先把它的左右孩子入栈,其次交换左右孩子。
class Solution(object): def invertTree(self, root): """ :type root: TreeNode :rtype: TreeNode """ if not root: return None st = [root] while st: node = st.pop() if node.left: st.append(node.left) if node.right: st.append(node.right) node.left, node.right = node.right, node.left return root
递归:
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def dfs(l, r):
if l is None and r is None:
return True
if l is None or r is None:
return False
return l.val == r.val and dfs(l.left, r.right) and dfs(l.right, r.left)
return dfs(root, root)
迭代:
class Solution(object): def isSymmetric(self, root): """ :type root: TreeNode :rtype: bool """ # 如果根节点为空或者没有左右孩子,那么为对称二叉树 if root is None or not (root.left or root.right): return True que = [root.left, root.right] while que: l = que.pop() r = que.pop() # 如果都为空,继续循环 if not l and not r: continue # 两者有一个空,那么就不是对称的 if l is None or r is None: return False if l.val != r.val: return False que.append(l.left) que.append(r.right) que.append(l.right) que.append(r.left) return True
class Solution(object): def diameterOfBinaryTree(self, root): """ :type root: TreeNode :rtype: int """ self.res = 0 # return root的最大深度,并且维护全局变量res,即以root为根节点的二叉树的直径(不一定要经过root) def helper(root): if root is None: return 0 l = helper(root.left) r = helper(root.right) self.res = max(self.res, l+r) return 1+max(l, r) helper(root) return self.res
迭代写法:对于第k层,首先记录这层的节点数,对于每一个节点,首先pop出来,再将其左右孩子入队,再将其val记录到答案中。
class Solution(object): def levelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ if root is None: return None que = [root] res = [] while que: size = len(que) tmp = [] for _ in range(size): node = que.pop(0) if node.left: que.append(node.left) if node.right: que.append(node.right) tmp.append(node.val) res.append(tmp) return res
迭代写法:
每次递归的时候都需要带一个 lev (表示当前的层数)。如果当前行对应的 list 不存在,就加入一个空 list 进去。
class Solution(object):
def levelOrder(self, root):
res = []
def dfs(root, lev):
if root is None:
return
if lev == len(res):
res.append([])
res[lev].append(root.val)
dfs(root.left, lev+1)
dfs(root.right, lev+1)
dfs(root, 0)
return res
递归分治
# 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): def sortedArrayToBST(self, nums): """ :type nums: List[int] :rtype: TreeNode """ def dfs(nums, l, r): if l > r: return None mid = l+r >> 1 node = TreeNode(nums[mid], dfs(nums, l, mid-1), dfs(nums, mid+1, r)) return node return dfs(nums, 0, len(nums)-1)
方法一:递归
class Solution(object): def isValidBST(self, root): """ :type root: TreeNode :rtype: bool """ def dfs(root, lo, hi): if root is None: return True val = root.val if val <= lo or val >= hi: return False if dfs(root.left, lo, val) is False or dfs(root.right, val, hi) is False: return False return True return dfs(root, float('-inf'), float('inf'))
方法二:中序遍历
进行中序遍历,中序遍历的结果一定是升序的。维护一个最小值,利用栈,边中序,边比较当前元素是否小于这个最小值。
class Solution(object): def isValidBST(self, root): """ :type root: TreeNode :rtype: bool """ st = [] res = True init = float('-inf') while st or root: while root: st.append(root) root = root.left root = st.pop() res = res and root.val > init init = root.val root = root.right return res
中序遍历,找第k个即可
class Solution(object): def kthSmallest(self, root, k): """ :type root: TreeNode :type k: int :rtype: int """ st = [] cnt = 0 while (st or root) and cnt < k: while root: st.append(root) root = root.left root = st.pop() res = root.val root = root.right cnt += 1 return res
就是二叉树的层序遍历,每次记录最右边的元素
bfs:
class Solution(object): def rightSideView(self, root): """ :type root: TreeNode :rtype: List[int] """ if root is None: return None res = [] que = [root] while que: size = len(que) res.append(que[-1].val) for _ in range(size): node = que.pop(0) if node.left: que.append(node.left) if node.right: que.append(node.right) return res
dfs:深度优先搜索,这次从right侧深度
class Solution(object):
def rightSideView(self, root):
res = []
def dfs(lev, root):
if root is None:
return
if lev == len(res):
res.append(root.val)
dfs(lev+1, root.right)
dfs(lev+1, root.left)
dfs(0, root)
return res
https://leetcode.cn/problems/flatten-binary-tree-to-linked-list
class Solution(object): def flatten(self, root): """ :type root: TreeNode :rtype: None Do not return anything, modify root in-place instead. """ def dfs(root): if root is None: return l = dfs(root.left) r = dfs(root.right) # 把操作后的左孩子接到 root.right root.left = None root.right = l # 把操作后的右孩子,接到root的最右下角 tmp = root while tmp.right: tmp = tmp.right tmp.right = r return root root = dfs(root) # 作者:小太子仔 # 链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/solutions/791939/di-gui-jie-jue-by-xiao-xiu-8-h021/ # 来源:力扣(LeetCode) # 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
递归写法
# 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): def buildTree(self, preorder, inorder): """ :type preorder: List[int] :type inorder: List[int] :rtype: TreeNode """ def dfs(p_start, p_end, i_start, i_end): if p_start > p_end: return None idx = inorder.index(preorder[p_start]) size = idx - i_start root = TreeNode(preorder[p_start] ,dfs(p_start+1, p_start+size, i_start, idx-1) ,dfs(p_start+size+1, p_end, idx+1, i_end)) return root n = len(preorder) return dfs(0, n-1, 0, n-1)
方法一:朴素的递归。
首先搜索所有节点,再对于每个当前节点,搜索以其为根的所有(往下的)路径,同时累加路径总和为 targetSum的所有路径。
O(N2)
class Solution(object): def pathSum(self, root, targetSum): """ :type root: TreeNode :type targetSum: int :rtype: int """ self.res = 0 def dfs(root, curSum): if root is None: return curSum += root.val if curSum == targetSum: self.res += 1 dfs(root.left, curSum) dfs(root.right, curSum) def traverse(root): if root is None: return dfs(root, 0) traverse(root.left) traverse(root.right) traverse(root) return self.res
方法二:前缀和
快速排序
class Solution(object): def sortArray(self, nums): """ :type nums: List[int] :rtype: List[int] """ def quicksort(l, r): if l >= r: return i, j, pivot = l, r, nums[l] while i < j: while i < j and nums[j] >= pivot: j -= 1 while i < j and nums[i] <= pivot: i += 1 nums[i], nums[j] = nums[j], nums[i] nums[i], nums[l] = nums[l], nums[i] quicksort(l, i-1) quicksort(i+1, r) quicksort(0, len(nums)-1) return nums
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。