- 字符串转换整数 (atoi)
这一题建议使用自动机来写,做这一题一定要仔细,中间的字符一个也不能写错,不然后面很难调,注意python判断一个字符是否是数字可以使用c.isdigit()这样的函数,int(c)表示将字符转换成数字,这里要求字符c一定是数值型的字符。最后在计算的时候,我们只需要关注signed和number这两种状态,其他的都不要管。这题基本上算是通过率最低的一道题了。
class Solution:
# space, sign, number, other
def __init__(self):
self.transpose = {
'start' : ['start', 'signed', 'number', 'end'],
'signed' : ['end', 'end', 'number', 'end'],
'number' : ['end', 'end', 'number', 'end'],
'end' : ['end', 'end', 'end', 'end']
}
def myAtoi(self, str: str) -> int:
def getCol(c):
if c == ' ':
return 0
elif c == '+' or c == '-':
return 1
elif c.isdigit():
return 2
else:
return 3
ans = 0
temp = 'start'
sign = 1
for c in str:
temp = self.transpose[temp][getCol(c)]
if temp == 'signed':
if c == '-':
sign = -1
elif temp == 'number':
ans = 10*ans + int(c)
ans = ans*sign
if ans > 2**31 - 1:
return 2**31 - 1
if ans < -2**31:
return -2**31
return ans
- 盛最多水的容器
最简单的解法,直接暴力遍历每一种状态,时间复杂度O(n2)。如果对这一题进行仔细分析,就会发现有一些状态是不需要遍历的。现在有两条线段height[i], height[j]可以围成一个矩形,如果我们把其中较高的一条线段往里移动,那么围成的矩形面积是一定会变小的。可以简单做一个分析:现在把这条较高的线段往里移动时,如果遇到更高的了,那么矩形的高度不变,而宽度变小了;如果遇到更低的了,那么矩阵的高度可能变小,而宽度变小,所以最终生成的矩形面积一定变小。因此最终实现的时候,只需要用一个双指针即可,复杂度将为O(n)。
解法1:
class Solution:
def maxArea(self, height: List[int]) -> int:
res = -inf
for i in range(len(height) - 1):
for j in range(i+1, len(height)):
res = max(res, (j-i)*min(height[i], height[j]))
return res
解法2:
class Solution:
def maxArea(self, height: List[int]) -> int:
res = -inf
i = 0
j = len(height) - 1
while(i < j):
res = max(res, (j-i)*min(height[i], height[j]))
if height[i] < height[j]:
i += 1
else:
j -= 1
return res
- 罗马数字转整数
将罗马数字转换成整数。需要判断一下一次读取一个字符还是读取两个字符。
class Solution:
def romanToInt(self, s: str) -> int:
Dict = {'I':1, 'IV':4, 'V':5, 'IX':9, 'X':10,
'XL':40, 'L':50, 'XC':90, 'C':100, 'CD':400, 'D':500,
'CM':900, 'M':1000}
ans = 0
i = 0
while(i < len(s)):
if (s[i] in ['I', 'X', 'C'] and (i+1 < len(s) and s[i:i+2] in Dict)):
ans += Dict[s[i:i+2]]
i += 2
else:
ans += Dict[s[i]]
i += 1
return ans
- 合并两个有序链表
链表的基本操作。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
newHead = ListNode()
temp = newHead
while(l1 and l2):
if l1.val < l2.val:
temp.next = l1
temp = l1
l1 = l1.next
else:
temp.next = l2
temp = l2
l2 = l2.next
if l1:
temp.next = l1
if l2:
temp.next = l2
return newHead.next
- 括号生成
用递归的方式来生成括号比较好理解,模拟二叉树的生长过程,注意一下递归函数的参数设计。
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
self.res = []
def dfs(route, left, right):
if left == 0 and right == 0:
self.res.append(route)
return
if left > right:
return
if left < 0 or right < 0:
return
dfs(route + '(', left - 1, right)
dfs(route + ')', left, right - 1)
dfs('', n, n)
return self.res
- 有效的数独
判断矩阵是否满足数独的三个条件。这个题的难点在于如何只用一次遍历来同时判断这3个条件。写法需要注意一下。
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
row = [[0]*9 for _ in range(9)]
col = [[0]*9 for _ in range(9)]
block = [[0]*9 for _ in range(9)]
for i in range(9):
for j in range(9):
if board[i][j] == '.':
continue
else:
board_index = i//3 * 3 + j // 3
c = int(board[i][j]) - 1
if row[i][c] or col[c][j] or block[board_index][c]:
return False
else:
row[i][c] = 1
col[c][j] = 1
block[board_index][c] = 1
return True
- 外观数列
这个题暂时还没有想到比较简洁的写法,但是考虑到n<=30,因此可以直接暴力。拿一个列表将前面的字符串全部存储起来,然后直接遍历最后一个字符串,统计连续相邻相同字符的个数即可。
class Solution:
def countAndSay(self, n: int) -> str:
if n == 1:
return '1'
res = ['1']
for _ in range(1, n):
s = ''
i = 0
while(i < len(res[-1])):
count = 1
while(i < len(res[-1])-1 and res[-1][i] == res[-1][i+1]):
count += 1
i += 1
s += str(count)+res[-1][i]
i += 1
res.append(s)
return res[-1]
- 全排列
同样是简单的DFS即可,这个是模拟多叉树的生长过程,需要注意同一条路径不可重复访问同一个节点,而不同路径之间又互不影响。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
length = len(nums)
self.res = []
flags = [0]*length
def dfs(route, index):
if index == length:
self.res.append(route)
return
for i in range(length):
if flags[i] == 0:
flags[i] = 1
dfs(route + [nums[i]], index+1)
flags[i] = 0
dfs([], 0)
return self.res
- 旋转图像
先转置再反转即可。python的调包反转很慢。
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
for i in range(len(matrix)):
for j in range(i, len(matrix[0])):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for i in range(len(matrix)):
p = 0
q = len(matrix[i])- 1
while(p<=q):
matrix[i][p], matrix[i][q] = matrix[i][q], matrix[i][p]
p += 1
q -= 1
return matrix
- 字母异位词分组
比较直观的想法是利用字典来解决。Dict.keys()、Dict.values()、Dict.items()这几个操作需要记清楚。
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
Dict = {}
for str in strs:
key = "".join(sorted(str))
if key not in Dict:
Dict[key] = []
Dict[key].append(str)
return list(Dict.values())
- 合并区间
根据左边界进行一个升序排序,这样方便判断两个区间是否有交集。
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
if not intervals:
return []
intervals.sort(key = lambda x : x[0])
res = [intervals[0]]
for i in range(1, len(intervals)):
if intervals[i][0] > res[-1][1]:
res.append(intervals[i])
else:
res[-1][1] = max(res[-1][1], intervals[i][1])
return res
- 不同路径
迷宫问题:求所有的路径。暴力搜索会超时,这个建议用DP。
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[0]*m for _ in range(n)]
for i in range(m):
dp[0][i] = 1
for i in range(n):
dp[i][0] = 1
for i in range(1, n):
for j in range(1, m):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
- 子集
简单的DFS即可,模拟二叉树的生长过程即可。
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
self.res = []
def dfs(route, i):
if i == len(nums):
self.res.append(route)
return
dfs(route, i+1)
dfs(route + [nums[i]], i+1)
dfs([], 0)
return self.res
- 二叉树的中序遍历
二叉树的基本操作,不过这一题需要手动实现栈来完成这一功能。系统栈除了记录函数调用的相互顺序还需要记录函数内部具体执行的步骤,简单来说就是哪些步骤已经执行了,哪些步骤还没有被执行。因此我们在实现这一功能的时候,除了使用栈这一结构,还需要记录当前节点的状态,每次在出栈之后,就立马更新当前节点的状态,不然的话整个栈就会陷入死循环,这一点非常重要。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res = []
stack = []
cur = root
while(cur or stack):
while(cur):
stack.append(cur)
cur = cur.left
cur = stack.pop()
res.append(cur.val)
cur = cur.right #这一步非常重要,不管右节点是否为空,都需要更新当前节点的状态,不然就会陷入死循环。
return res
- 二叉树的层序遍历
这一题与一般的层序遍历有所区别,需要记录每一层的长度。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
while(queue):
length = len(queue)
temp = []
for _ in range(length):
node = queue.pop(0)
temp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(temp)
return res
- 二叉树的最大深度
二叉树的基本操作。
# 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:
if not root:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
- 从前序与中序遍历序列构造二叉树
建树的基本操作。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
Dict = {}
for i in range(len(inorder)):
if inorder[i] not in Dict:
Dict[inorder[i]] = i
def recursion(index, left, right):
if left > right:
return None
node = TreeNode(preorder[index])
node.left = recursion(index+1, left, Dict[preorder[index]]-1)
node.right = recursion(index+Dict[preorder[index]]-left+1, Dict[preorder[index]]+1, right)
return node
return recursion(0, 0, len(inorder)-1)
- 将有序数组转换为二叉搜索树
这一题需要使用二分来找到中间节点,说实话这一题没看答案之前不知道咋做(滑稽)。
# 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 dfs(l, r):
if l > r:
return None
#while(l <= r):
mid = (l + r) // 2
root = TreeNode(nums[mid])
root.left = dfs(l, mid-1)
root.right = dfs(mid+1, r)
return root
return dfs(0, len(nums)-1)
- 填充每个节点的下一个右侧节点指针
题目给定了一颗满二叉树,需要找到每一个节点的右边兄弟节点。简单的层序遍历即可,需要记录一下每一层的节点数量。
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return root
queue = [root]
while(queue):
length = len(queue)
for i in range(length):
temp = queue.pop(0)
if i < length-1:
temp.next = queue[0]
if temp.left:
queue.append(temp.left)
if temp.right:
queue.append(temp.right)
return root
- 杨辉三角
基本题,没啥好说的。
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
nums = [[0]*numRows for i in range(numRows)]
res = []
for i in range(numRows):
temp = []
for j in range(i+1):
if j == 0 or (i==j):
nums[i][j] = 1
else:
nums[i][j] = nums[i-1][j-1] + nums[i-1][j]
temp = nums[i][:i+1]
res.append(temp)
return res
- 买卖股票的最佳时机 II
这一题与之前的只能买一次股票不一样,这里可以买卖任意多次。因此之前的DP公式在这里就不适用了。这里用到了一个比较直观的贪心思想,只要当天的价格比前一天的价格高,就可以卖出。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
ans = 0
for i in range(1, len(prices)):
if prices[i] > prices[i-1]:
ans += prices[i] - prices[i-1]
return ans
- 分割回文串
直观的想法就是使用DFS来遍历,每次都将字符串一分为二,但是我觉得这题的终止条件不太好想,这个需要注意一下。在判断一个字符串是否为回文字符串的时候需要使用DP。
class Solution:
def partition(self, s: str) -> List[List[str]]:
dp = [[0]*len(s) for i in range(len(s))]
for i in range(len(s)):
for j in range(len(s)):
if i == j:
dp[i][j] = 1
for i in range(len(s) - 2, -1, -1):
for j in range(i + 1, len(s)):
if s[i] == s[j]:
if j == i + 1:
dp[i][j] = 1
else:
dp[i][j] = dp[i+1][j-1]
else:
dp[i][j] = 0
self.res = []
def dfs(route, left, right):
if left == len(s): #这里需要注意一下
self.res.append(route)
return
for i in range(left, right+1):
if dp[left][i] == 1:
dfs(route + [s[left:i+1]], i+1, right)
dfs([], 0, len(s)-1)
return self.res
- 只出现一次的数字
异或操作。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for num in nums:
res ^= num
return res
- 排序链表
链表排序需要使用分治,使用快慢指针来将链表一分为二,然后再将链表合并起来。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
slow = head
fast = head.next
while(fast and fast.next):
slow = slow.next
fast = fast.next.next
newHead = slow.next
slow.next = None
l = self.sortList(head)
r = self.sortList(newHead)
First = ListNode(0)
temp = First
while(l and r):
if l.val < r.val:
temp.next = l
l = l.next
else:
temp.next = r
r = r.next
temp = temp.next
if l :
temp.next = l
if r :
temp.next = r
return First.next
- 多数元素
可以用字典来计数,也可使用排序,也可以使用摩尔投票法。摩尔投票法有两种不同的写法。仔细观察一下两者的区别。
写法1:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count = 0
for num in nums:
if count == 0:
cur = num
count += 1
elif cur == num:
count += 1
elif cur != num:
count -= 1
return cur
写法2:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count = 0
for num in nums:
if count == 0:
res = num
if num == res:
count += 1
else:
count -= 1
return res
- Excel表列序号
26进制
class Solution:
def titleToNumber(self, s: str) -> int:
res = 0
for c in s:
res = res*26 + ord(c) - 64
return res
- 颠倒二进制位
注意这一题输入的数字是32位的。
解法1:
class Solution:
def reverseBits(self, n: int) -> int:
ans = 0
for i in range(32):
ans = ans*2 + n %2
n = n // 2
return ans
解法2:(位运算写法)
class Solution:
def reverseBits(self, n: int) -> int:
ans = 0
for i in range(32):
ans = (ans<<1) + (n&1)
n = (n >> 1)
return ans
- 位1的个数
化二进制
class Solution:
def hammingWeight(self, n: int) -> int:
res = 0
while(n):
res += n%2
n = n // 2
return res
- 快乐数
正常的数字基本操作,这种操作会存在一些循环周期,因此可以把这些循环操作存储起来,如果到了相同的状态,还没有变成1,那么就说明这个数不是快乐数。
换一种思路,这个题本质上就是一个链表成环的问题,由于链表中一定存在环,因此只需要在环中判断是否在能达到1即可,具体的实现是通过快慢指针。
解法1:
class Solution:
def isHappy(self, n: int) -> bool:
def compute(num):
s = 0
while(num):
s += (num % 10)**2
num = num // 10
return s
Dict = {}
res = n
while(True):
res = compute(res)
if res == 1:
return True
if res not in Dict:
Dict[res] = 1
else:
return False
解法2:
class Solution:
def isHappy(self, n: int) -> bool:
def compute(num):
s = 0
while(num):
s += (num % 10)**2
num = num // 10
return s
slow = n
fast = compute(n)
while(fast != 1 and slow != fast):
slow = compute(slow)
fast = compute(compute(fast))
return fast == 1
- 反转链表
链表的基本操作,题目要求非递归和递归两种写法。
解法1:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
newHead = None
while(head):
temp = head.next
head.next = newHead
newHead = head
head = temp
return newHead
解法2:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next: #注意这个边界条件
return head
newHead = self.reverseList(head.next) #传入的参数一定是head.next,这样才能直到前面一个节点的信息。
head.next.next = head #反转操作
head.next = None
return newHead
- 实现 Trie (前缀树)
python中实现这一结构就是使用嵌套字典。
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.Tree = {}
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
Tree = self.Tree
for c in word:
if c not in Tree:
Tree[c] = {}
Tree = Tree[c]
Tree["#"] = "#"
def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
Tree = self.Tree
for c in word:
if c not in Tree:
return False
Tree = Tree[c]
if "#" not in Tree:
return False
return True
def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
Tree = self.Tree
for c in prefix:
if c not in Tree:
return False
Tree = Tree[c]
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)
- 数组中的第K个最大元素
写一个类快排。
import random
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
self.ans = 0
def qucksort(nums, l, r):
if l > r:
return
else:
rand = random.randint(l, r)
nums[l], nums[rand] = nums[rand], nums[l]
temp = nums[l]
i = l
j = r
while(i < j):
while(i < j and temp < nums[j]):
j -= 1
nums[i] = nums[j]
while(i < j and temp >= nums[i]):
i += 1
nums[j] = nums[i]
nums[i] = temp
index = len(nums) - k
if i == index:
self.ans = nums[i]
return
elif i < index:
qucksort(nums, i+1, r)
else:
qucksort(nums, l, i-1)
qucksort(nums, 0, len(nums)-1)
return self.ans
- 二叉搜索树中第K小的元素
可以直接进行dfs遍历,可以再加上剪枝。
解法1:
# 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: TreeNode, k: int) -> int:
self.res = []
def dfs(root):
if not root:
return
dfs(root.left)
self.res.append(root.val)
dfs(root.right)
dfs(root)
return self.res[k-1]
解法2:剪枝
# 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: TreeNode, k: int) -> int:
self.res = inf
self.count = 0
def dfs(root):
if self.count > k:
return
if not root:
return
dfs(root.left)
self.count += 1
if self.count == k:
self.res = root.val
return
dfs(root.right)
dfs(root)
return self.res
- 二叉树的最近公共祖先
这个题的递归函数设计的比较巧妙,递归函数为空的时候表示没有对应的节点,不为空的时候就是指找到了特定的节点。
def lowestCommonAncestor(root, p, q)表示在root为跟的条件下,找到的p,q这两个节点的最近公共祖先,一定要注意递归出口。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
if left:
return left
else:
return right
- 删除链表中的节点
链表的基本操作,不过这个题只给定了要删除的那个节点,也算是提供了一种新的删除方式。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
- 除自身以外数组的乘积
题目要求不能用除法,可以使用数组进行累乘,但是需要错开一位,从前往后和从后往前同时计算即可。
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
length = len(nums)
S = [1]*length
P = [1]*length
res = [1]*length
for i in range(1, length):
S[i] = S[i-1]*nums[i-1]
for i in range(length-1, 0, -1):
P[i-1] = P[i]*nums[i]
for i in range(length):
res[i] = S[i]*P[i]
return res
- 有效的字母异位词
字母异位词需要用字典来表示,或者直接排序即可。
解法1:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
Dict1 = {}
Dict2 = {}
for c in s:
if c not in Dict1:
Dict1[c] = 1
else:
Dict1[c] += 1
count = 0
for c in t:
if c not in Dict2:
Dict2[c] = 1
else:
Dict2[c] += 1
if c not in Dict1:
return False
else:
if Dict2[c] == Dict1[c]:
count += 1
return count == len(Dict1)
解法2:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return sorted(s) == sorted(t)
- 缺失数字
一共四种解法:排序、借助字典、或者通过直接计算求和也行。
解法1:位运算
class Solution:
def missingNumber(self, nums: List[int]) -> int:
res = 0
for i in range(len(nums)):
res = res ^ i ^ nums[i]
return res^len(nums)
解法2:排序
class Solution:
def missingNumber(self, nums: List[int]) -> int:
def qucksort(nums, l, r):
if l >= r:
return
else:
i = l
j = r
temp = nums[i]
while(i < j):
while(i < j and temp < nums[j]):
j -= 1
nums[i] = nums[j]
while(i < j and temp >= nums[i]):
i += 1
nums[j] = nums[i]
nums[i] = temp
qucksort(nums, l, i-1)
qucksort(nums, i+1, r)
qucksort(nums, 0, len(nums)-1)
for i in range(len(nums)):
if i != nums[i]:
return nums[i]-1
return len(nums)
- 完全平方数
DFS+剪枝或者DP。
class Solution:
def numSquares(self, n: int) -> int:
dp = [inf]*(n+1)
dp[0] = 0
for i in range(1, n+1):
j = 1
while(j*j <= i):
dp[i] = min(dp[i], dp[i-j*j]+1)
j += 1
return dp[n]
- 移动零
直接借用快排的双指针写法不行,因为快排是不稳定的,这里有一种比较直接的写法,直接遍历整个数组,如果当前元素不为零,就和前面的元素进行交换,紧接着前面的元素移动一位。最后将剩余的元素全部填充为0即可。
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
j = 0
for i in range(len(nums)):
if nums[i] != 0:
nums[j] = nums[i]
j += 1
for i in range(j, len(nums)):
nums[i] = 0
return nums
- 寻找重复数
这一题可以使用字典对每一个数字进行计数,也可以使用排序,也可以使用二分,但我个人认为这个二分不是很好写,还可以模拟列表的写法,找到一个链表中环的入口。链表的写法可以用数学公式来证明。
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow = 0
fast = nums[0]
while(slow != fast):
slow = nums[slow]
fast = nums[nums[fast]]
fast = -1 #前面的fast多走了一步,因此这里要退回一步
while(slow != fast):
if fast == -1:
fast = 0
else:
fast = nums[fast]
slow = nums[slow]
return slow
- 生命游戏
注意这个题需要同时处理所有的细胞,因此我们需要定义一个标记数据来记录全局的信息,在计数的时候需要注意边界条件。
class Solution:
def gameOfLife(self, board: List[List[int]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
length = len(board)
width = len(board[0])
flags = [[0]*width for _ in range(length)]
def count(x, y):
if x < 0 or x > length - 1 or y < 0 or y > width - 1:
return 0
elif board[x][y]== 1:
return 1
else:
return 0
for i in range(length):
for j in range(width):
temp = 0
temp = count(i-1, j-1) + count(i, j-1) + count(i+1, j-1) + count(i-1, j) + count(i+1, j) + count(i-1, j+1) + count(i, j+1) + count(i+1, j+1)
if board[i][j] == 1:
if temp < 2 or temp > 3:
flags[i][j] = 1
else:
if temp == 3:
flags[i][j] = 1
for i in range(length):
for j in range(width):
if flags[i][j] == 1:
board[i][j] = (board[i][j] + 1) % 2
return board
- 奇偶链表
需要记录一下偶数位置的节点和奇数位置的节点。最简单的做法就是直接使用额外空间将奇数节点和偶数节点分别存储起来。
解法1:(利用额外的存储空间)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
odd = []
even = []
index = 1
temp = head
while(temp):
pre = temp
temp = temp.next
pre.next = None
if index % 2 == 1:
odd.append(pre)
else:
even.append(pre)
index += 1
newhead = odd[0]
temp = newhead
for node in odd[1:]:
temp.next = node
temp = temp.next
for node in even:
temp.next = node
temp = temp.next
return newhead
解法2:(原地修改)我个人认为这个代码不是很好写。最终的奇数链表的头节点和偶数链表的头节点都需要保存下来。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
odd = head
even = head.next
temp = even
while(odd.next and temp.next):
odd.next = temp.next
odd = odd.next
temp.next = odd.next
temp = temp.next
odd.next = even
return head
- 扁平化嵌套列表迭代器
可以先将嵌套列表给展开,然后再来进行一步一步地取数,索引到头地时候表示数已经取完了。
# """
# This is the interface that allows for creating nested lists.
# You should not implement it, or speculate about its implementation
# """
#class NestedInteger:
# def isInteger(self) -> bool:
# """
# @return True if this NestedInteger holds a single integer, rather than a nested list.
# """
#
# def getInteger(self) -> int:
# """
# @return the single integer that this NestedInteger holds, if it holds a single integer
# Return None if this NestedInteger holds a nested list
# """
#
# def getList(self) -> [NestedInteger]:
# """
# @return the nested list that this NestedInteger holds, if it holds a nested list
# Return None if this NestedInteger holds a single integer
# """
class NestedIterator:
def __init__(self, nestedList: [NestedInteger]):
self.res = []
self.flattern(nestedList)
self.index = 0
self.length = len(self.res)
def flattern(self, data):
def dfs(data):
if data == []:
return
if type(data) == NestedInteger and data.isInteger():
self.res.append(data.getInteger())
return
if type(data) == NestedInteger and not data.isInteger():
dfs(data.getList())
if type(data) == list:
for num in data:
dfs(num)
dfs(data)
def next(self) -> int:
self.index += 1
return self.res[self.index-1]
def hasNext(self) -> bool:
if self.index < self.length:
return True
return False
# Your NestedIterator object will be instantiated and called as such:
# i, v = NestedIterator(nestedList), []
# while i.hasNext(): v.append(i.next())
- 反转字符串
最直接的做法是用额外空间,反过来赋值即可。但是题目要求不能使用额外空间,因此采用双指针的方式来交换比较合适。
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
i = 0
j = len(s) - 1
while(i <= j):
s[i], s[j] = s[j], s[i]
i += 1
j -= 1
return s
- 前 K 个高频元素
可以建立一个字典,然后对字典进行排序,也可以建立一个堆。
解法1:
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
Dict = {}
for num in nums:
if num not in Dict:
Dict[num] = 1
else:
Dict[num] += 1
temp = list(Dict.items())
temp.sort(key = lambda a : a[1], reverse=True)
return list(dict(temp).keys())[:k]
解法2:(heappush中没有提供关键字来建堆的接口,这就很烦)
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
Dict = {}
for num in nums:
if num not in Dict:
Dict[num] = 1
else:
Dict[num] += 1
temp = list(Dict.items())
res = heapq.nlargest(k, temp, key = lambda a:a[1])
return list(dict(res).keys())
- 有序矩阵中第K小的元素
这个题与合并k个有序链表一样。比较简单的解法是将每一行拼接起来直接进行排序;也可以直接将所有的数入堆;也可以按照合并k个有序链表那样对堆的写法进行优化(优先队列,保证当前每次出队列的都是最小的);还可以使用归并排序。
解法1:
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
res = []
for row in matrix:
res += row
return sorted(res)[k-1]
解法2:
from heapq import *
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
heap = []
for row in matrix:
for num in row:
heappush(heap, num) #这两行代码不能交换
if len(heap) > len(matrix)**2 - k +1:
heappop(heap)
return heappop(heap)
解法3:
from heapq import *
class Node:
def __init__(self, val, x, y):
self.val = val
self.x = x
self.y = y
def __lt__(self, other):
if self.val < other.val:
return True
else:
return False
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
heap = []
for i in range(len(matrix)):
node = Node(matrix[i][0], i, 0)
heappush(heap, node)
for _ in range(k-1):
node = heappop(heap)
val, x, y = node.val, node.x, node.y
if y < len(matrix) -1:
heappush(heap, Node(matrix[x][y+1], x, y+1))
return heappop(heap).val
解法4:
from heapq import *
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
def merge(s, t):
res = []
i = 0
j = 0
while(i < len(s) and j < len(t)):
if s[i] < t[j]:
res.append(s[i])
i += 1
else:
res.append(t[j])
j += 1
if i < len(s):
res += s[i:]
if j < len(t):
res += t[j:]
return res
def mergeSort(nums, l, r):
if l == r:
return nums[l]
if l > r:
return
mid = (l + r) // 2
left = mergeSort(nums, l, mid)
right = mergeSort(nums, mid+1, r)
return merge(left, right)
res = mergeSort(matrix, 0, len(matrix)-1)
return res[k-1]
- Fizz Buzz
没啥好说的。
class Solution:
def fizzBuzz(self, n: int) -> List[str]:
res = []
for i in range(1, n+1):
if i % 15 == 0:
temp = "FizzBuzz"
elif i % 5 == 0:
temp = "Buzz"
elif i % 3 == 0:
temp = "Fizz"
else:
temp = str(i)
res.append(temp)
return res