@创建于:20220215
1、Task01 数组
15. 三数之和
排序 + 双指针
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
size = len(nums)
result = []
if size < 3:
return []
nums = sorted(nums)
for i in range(size-2):
if nums[i] > 0:
return result
if i>0 and (nums[i] == nums[i-1]):
continue
left = i + 1
right = size - 1
while left < right:
three_sum = nums[i] + nums[left] + nums[right]
if three_sum == 0:
result.append([nums[i], nums[left], nums[right]])
while (left < right) and (nums[left]==nums[left+1]):
left += 1
while (left < right) and (nums[right]==nums[right-1]):
right -= 1
left += 1
right -= 1
elif three_sum < 0:
left += 1
else:
right -= 1
return result
26. 删除有序数组中的重复项
双指针
定义两个指针 fast和 slow 分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标 1。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
size = len(nums)
if size<1:
return 0
slow = 1
fast = 1
while fast < size:
if nums[fast] != nums[fast-1]:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
27. 移除元素
使用双指针:右指针 right指向当前将要处理的元素,左指针 left 指向下一个将要赋值的位置。
如果右指针指向的元素不等于 vall,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;
如果右指针指向的元素等于 val,它不能在输出数组里,此时左指针不动,右指针右移一位。
整个过程保持不变的性质是:区间 [0,left 中的元素都不等于 val。当左右指针遍历完输入数组以后,leftt 的值就是输出数组的长度。
这样的算法在最坏情况下(输入数组中没有元素等于 val),左右指针各遍历了数组一次。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
size = len(nums)
if size < 1:
return size
slow = 0
fast = 0
while fast < size:
if nums[fast] == val:
fast += 1
else:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
2、Task02 链表
21. 合并两个有序链表
当 list1 和 list2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
prehead = ListNode(-1)
pre = prehead
while list1 and list2:
if list1.val < list2.val:
pre.next = list1
list1 = list1.next
else:
pre.next = list2
list2 = list2.next
pre = pre.next
if list1:
pre.next = list1
else:
pre.next = list2
return prehead.next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
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
160. 相交链表
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
dictA = dict()
while headA:
dictA[headA] = 1
headA = headA.next
while headB:
if dictA.get(headB):
return headB
headB = headB.next
return None
# 双指针
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
A = headA
B = headB
while A!=B:
if A:
A = A.next
else:
A = headB
if B:
B = B.next
else:
B = headA
return A
82. 删除排序链表中的重复元素 II
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return head
dummy = ListNode(val=0, next=head)
cur = dummy
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
x = cur.next.val
while cur.next and cur.next.val == x:
cur.next = cur.next.next
else:
cur = cur.next
return dummy.next
3、Task03 栈
155. 最小栈
采用辅助站选择栈内最小值
class MinStack:
def __init__(self):
self.stack = []
self.stack_min = [math.inf]
def push(self, val: int) -> None:
self.stack.append(val)
self.stack_min.append(min(val, self.stack_min[-1]))
def pop(self) -> None:
self.stack.pop()
self.stack_min.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.stack_min[-1]
844. 比较含退格的字符串
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
def build(ss: str) -> str:
ret = list()
for ch in ss:
if ch != "#":
ret.append(ch)
elif ret:
ret.pop()
return "".join(ret)
return build(s) == build(t)
227. 基本计算器 II
class Solution:
def calculate(self, s: str) -> int:
n = len(s)
stack = []
sign = '+'
num = 0
for i in range(n):
if s[i]!=' ' and s[i].isdigit():
num = num*10 + ord(s[i]) - ord('0')
if i == (n-1) or s[i] in '+-*/':
if sign == '+':
stack.append(num)
elif sign =='-':
stack.append(-num)
elif sign =='*':
stack.append(stack.pop()*num)
else:
stack.append(int(stack.pop()/num))
sign = s[i]
num = 0
return sum(stack)
4、字符串
680. 验证回文字符串 Ⅱ
贪心算法
class Solution:
def validPalindrome(self, s: str) -> bool:
def check_palindrome(low, high):
i, j = low, high
while i < j:
if s[i] == s[j]:
i += 1
j -= 1
else:
return False
return True
left, right = 0, len(s)-1
while left < right:
if s[left] == s[right]:
left += 1
right -= 1
else:
st1 = check_palindrome(left+1, right)
st2 = check_palindrome(left, right-1)
return st1 or st2
return True
168. Excel表列名称
class Solution:
def convertToTitle(self, columnNumber: int) -> str:
res = list()
while columnNumber > 0:
ch = (columnNumber-1) % 26 + 1
res.append(chr(ch-1+ord('A')))
columnNumber = (columnNumber - ch) // 26
return ''.join(res[::-1])
394. 字符串解码
class Solution:
def decodeString(self, s: str) -> str:
stack = list()
for c in s:
if c !=']':
stack.append(c)
else:
# 弹出需要重复的字符
temp = ''
while stack[-1] != '[':
temp = stack.pop() + temp
# 弹出[
stack.pop()
# 弹出倍数数值
num = ''
while stack and stack[-1].isdigit():
num = stack.pop() + num
num = int(num)
# 获得按倍数重复的字符
temp = temp*num
# 新字符串逐一入栈
for i in temp:
stack.append(i)
return ''.join(stack)
5、树
111. 二叉树的最小深度
# 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 minDepth(self, root: TreeNode) -> int:
if not root:
return 0
if (not root.left) and (not root.right):
return 1
min_depth = float('inf')
if root.left:
min_depth = min(self.minDepth(root.left), min_depth)
if root.right:
min_depth = min(self.minDepth(root.right), min_depth)
return min_depth + 1
112. 路径总和
# 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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
if (not root.left) and (not root.right):
if root.val == targetSum:
return True
else:
return False
status_left = self.hasPathSum(root.left, targetSum - root.val)
status_right = self.hasPathSum(root.right, targetSum - root.val)
return status_left or status_right
173. 二叉搜索树迭代器
# 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 BSTIterator:
def __init__(self, root: TreeNode):
self.data = []
self.enqueue(root)
def enqueue(self, node):
while node:
self.data.append(node)
node = node.left
def next(self) -> int:
res = self.data.pop()
self.enqueue(res.right)
return res.val
def hasNext(self) -> bool:
return bool(self.data)
# Your BSTIterator object will be instantiated and called as such:
# obj = BSTIterator(root)
# param_1 = obj.next()
# param_2 = obj.hasNext()
6、位运算
231. 2 的幂
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
# method 1,自己的方法,效率更高效
# while n > 1:
# if n%2 == 1:
# return False
# n = n>>1
# return n == 1
# method 2 n & (-n) = n
return (n>0) and (n&-n==n)
78. 子集
数组的每个元素,可以有两个状态:
- 不在子数组中(用 000 表示);
- 在子数组中(用 111 表示)。
从 0 到 2 的数组个数次幂(不包括)的整数的二进制表示就能表示所有状态的组合。
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
size = len(nums)
n = 1 << size
res = []
for i in range(n):
temp = []
for j in range(size):
if (i>>j) & 1:
temp.append(nums[j])
res.append(temp)
return res
137. 只出现一次的数字 II
137. 只出现一次的数字 II(有限状态自动机 + 位运算,清晰图解)
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ones = 0
twos = 0
for num in nums:
ones = ones^num & (~twos)
twos = twos^num & (~ones)
return ones
7、双指针
83. 删除排序链表中的重复元素
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if (not head) or (head.next == None):
return head
cur = head
while cur.next:
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head
141. 环形链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
# 快慢指针
slow, fast = head, head
# 循环内 bike 每次后移一个结点, car 每次后移 2 个结点
# car 和 car->next 需要不为空,否则会发生非法内存访问
# car 不为空,那么 bike 肯定也不为空
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
148. 排序链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 合并两个有序链表
def merge(head1: ListNode, head2: ListNode) -> ListNode:
dummyHead = ListNode(0)
temp, temp1, temp2 = dummyHead, head1, head2
while temp1 and temp2:
if temp1.val <= temp2.val:
temp.next = temp1
temp1 = temp1.next
else:
temp.next = temp2
temp2 = temp2.next
temp = temp.next
if temp1:
temp.next = temp1
elif temp2:
temp.next = temp2
return dummyHead.next
# 判断异常情况
if not head:
return head
# 计算链表长度
length = 0
node = head
while node:
length += 1
node = node.next
dummyHead = ListNode(0, head)
subLength = 1
# 自底向上归并
while subLength < length:
prev, curr = dummyHead, dummyHead.next
# 不停的分成两组,直到链表分组完成
while curr:
# 第1个待归并的链表
head1 = curr
for i in range(1, subLength):
if curr.next:
curr = curr.next
else:
break
# 第2个待归并的链表
head2 = curr.next
curr.next = None
curr = head2
for i in range(1, subLength):
if curr and curr.next:
curr = curr.next
else:
break
# 找到两个链表与后续的断点
succ = None
if curr:
succ = curr.next
curr.next = None
# 合并两个有序链表
merged = merge(head1, head2)
prev.next = merged
while prev.next:
prev = prev.next
curr = succ
# 子链表长度倍增
subLength <<= 1
return dummyHead.next
8、搜索
101. 对称二叉树
# 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 isSymmetric(self, root: TreeNode) -> bool:
def check(t1, t2):
if (not t1) and (not t2):
return True
elif (not t1) or (not t2):
return False
else:
return (t1.val==t2.val) and check(t1.left, t2.right) and check(t1.right, t2.left)
return check(root, root)
94. 二叉树的中序遍历
# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def middle(cur):
if not cur:
return
middle(cur.left)
res.append(cur.val)
middle(cur.right)
middle(root)
return res
230. 二叉搜索树中第K小的元素
# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
res = []
while root or res:
while root:
res.append(root)
root = root.left
root = res.pop()
k = k - 1
if k == 0:
return root.val
root = root.right
我的思路:先进行中序遍历,然后返回第k个元素
# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
res = []
def mid(node):
if not node:
return
mid(node.left)
res.append(node.val)
mid(node.right)
mid(root)
return res[k-1]
9、排序
977. 有序数组的平方
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
size = len(nums)
res = [0]*len(nums)
index = size - 1
left = 0
right = size - 1
while left <= right:
s_left = nums[left]*nums[left]
s_right = nums[right]*nums[right]
if s_left >= s_right:
res[index] = s_left
left += 1
else:
res[index] = s_right
right -= 1
index -= 1
return res
1122. 数组的相对排序
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
rank = {x:i for i,x in enumerate(arr2)}
def my_sort(x):
return (0, rank[x]) if x in rank else (1, x)
arr1.sort(key=my_sort)
return arr1
147. 对链表进行插入排序
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
dummpy = ListNode(0)
dummpy.next = head
last = head
cur = head.next
while cur:
if last.val <= cur.val:
last = last.next
else:
pred = dummpy
while pred.next.val <= cur.val:
pred = pred.next
last.next = cur.next
cur.next = pred.next
pred.next = cur
cur = last.next
return dummpy.next
10、动态规划
121. 买卖股票的最佳时机
一次遍历
class Solution:
def maxProfit(self, prices: List[int]) -> int:
pmin = 1e5
profit = 0
for p in prices:
profit = max(p-pmin, profit)
pmin = min(p, pmin)
return profit
动态规划
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
if n == 0:
return 0
minp = prices[0]
profit = [0]*n
for i in range(1, n):
minp = min(prices[i], minp)
profit[i] = max(prices[i]-minp, profit[i-1])
return profit[-1]
122. 买卖股票的最佳时机 II
贪心算法
class Solution:
def maxProfit(self, prices: List[int]) -> int:
res = 0
for i in range(1, len(prices)):
res += max(0, prices[i]-prices[i-1])
return res
动态规划
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
profit = [[0]*2]*n
profit[0][0] = 0
profit[0][1] = -prices[0]
for i in range(1, n):
profit[i][0] = max(profit[i-1][0], profit[i-1][1]+prices[i])
profit[i][1] = max(profit[i-1][1], profit[i-1][0]-prices[i])
return profit[-1][0]
516. 最长回文子序列
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n = len(s)
res = [[0 for __ in range(n)] for _ in range(n)]
# 为什么逆序?
for i in range(n-1, -1, -1):
res[i][i] = 1
for j in range(i+1, n):
if s[i]==s[j]:
res[i][j] = res[i+1][j-1] + 2
else:
res[i][j] = max(res[i+1][j], res[i][j-1])
return res[0][n-1]
11、分治
169. 多数元素
排序后,返回中间值
class Solution:
def majorityElement(self, nums: List[int]) -> int:
nums.sort()
return nums[len(nums)//2]
投票法
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count = 0
res = None
for num in nums:
if count == 0:
res = num
count += 1 if res==num else -1
return res
53. 最大子数组和
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
if n < 1:
return 0
dp = [0 for i in range(n)]
dp[0] = nums[0]
for i in range(1, n):
if dp[i-1] > 0:
dp [i] = dp[i-1] + nums[i]
else:
dp[i] = nums[i]
return max(dp)
105. 从前序与中序遍历序列构造二叉树
递归方法
# 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 buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if not (preorder and inorder):
return None
root = TreeNode(preorder[0])
mid = inorder.index(preorder[0])
root.left = self.buildTree(preorder[1:mid+1], inorder[0:mid])
root.right = self.buildTree(preorder[mid+1:], inorder[mid+1:])
return root
12. 哈希表
219. 存在重复元素 II
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
# 哈希法
# pos = dict()
# for i, num in enumerate(nums):
# if num in pos and abs(i-pos[num])<=k:
# return True
# pos[num] = i
# return False
# 滑动窗口
s = set()
for i, num in enumerate(nums):
if i > k:
s.remove(nums[i-k-1])
if num in s:
return True
s.add(num)
return False
771. 宝石与石头
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
res_map = dict()
for j in jewels:
res_map[j] = 0
for s in stones:
if s in res_map:
res_map[s] += 1
return sum(res_map.values())
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
js = set(jewels)
return sum(s in js for s in stones)
811. 子域名访问计数
class Solution:
def subdomainVisits(self, cpdomains: List[str]) -> List[str]:
res = dict()
for item in cpdomains:
tmp = item.split(' ')
num = int(tmp[0])
cpd = tmp[1].split('.')
for i in range(len(cpd)):
x = ".".join(cpd[i:])
if x in res:
res[x] += num
else:
res[x] = num
return ["{} {}".format(v, k) for k, v in res.items()]