被围绕的区域
Given a 2D board containing 'X'
and 'O'
(the letter O), capture all regions surrounded by 'X'
.
A region is captured by flipping all 'O'
s into 'X'
s in that surrounded region.
Example:
X X X X X O O X X X O X X O X X
After running your function, the board should be:
X X X X X X X X X X X X X O X X
Explanation:
Surrounded regions shouldn’t be on the border, which means that any 'O'
on the border of the board are not flipped to 'X'
. Any 'O'
that is not on the border and it is not connected to an 'O'
on the border will be flipped to 'X'
. Two cells are connected if they are adjacent cells connected horizontally or vertically.
Code(By myself):
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board:
return
self.row = len(board)
self.col = len(board[0])
for i in range(1,self.col-1):
if board[0][i] == 'O' and board[1][i] == 'O':
self.change(board,1,i)
if board[self.row-1][i] == 'O' and board[self.row-2][i] == 'O':
self.change(board,self.row-2,i)
for i in range(1,self.row-1):
if board[i][0] == 'O' and board[i][1] == 'O':
self.change(board,i,1)
if board[i][self.col-1] == 'O' and board[i][self.col-2] == 'O':
self.change(board,i,self.col-2)
for i in range(1,self.row-1):
for j in range(1,self.col-1):
if board[i][j] == 'O':
board[i][j] = 'X'
elif board[i][j] == 'W':
board[i][j] = 'O'
def change(self,board,i,j):
board[i][j] = 'W'
if j + 1 < self.col-1 and board[i][j+1] == 'O':
self.change(board,i,j+1)
if i + 1 < self.row - 1 and board[i+1][j] == 'O':
self.change(board,i+1,j)
if i - 1 > 0 and board[i-1][j] == 'O':
self.change(board,i-1,j)
if j - 1 > 0 and board[i][j-1] == 'O':
self.change(board,i,j-1)
Code(others):
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not any(board):
return
n, m = len(board), len(board[0])
q = [ij for k in range(max(n,m)) for ij in ((0, k), (n-1, k), (k, 0), (k, m-1))]
while q:
i, j = q.pop()
if 0 <= i < n and 0 <= j < m and board[i][j] == 'O':
board[i][j] = 'W'
q += (i, j-1), (i, j+1), (i-1, j), (i+1, j)
board[:] = [['XO'[c == 'W'] for c in row] for row in board]
总结:
从外围向里扩散。
二叉树的最近公共祖先
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]
Example:
_______3______ / \ ___5__ ___1__ / \ / \ 6 _2 0 8 / \ 7 4
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 Output: 3 Explanation: The LCA of of nodes5
and1
is3.
Code(By myself):
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
res = root
if not root:
return self.res
res = self.find(root,p,q)[1]
return res
def find(self,root,p,q):
if not root:
return (0,root)
a = self.find(root.left,p,q)
b = self.find(root.right,p,q)
n = a[0] + b[0]
if a[1]:
res = a[1]
else:
res = b[1]
if root == p or root == q:
n += 1
if n == 2:
res = root
n -= 1
return (n,res)
Code(others):
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
if not root:
return None
if root==p:
if self.searchnode(root.left,q) or self.searchnode(root.right,q):
return root
return None
if root == q:
if self.searchnode(root.left, p) or self.searchnode(root.right, p):
return root
return None
if self.searchnode(p,q):
return p
if self.searchnode(q,p):
return q
pinleft=self.searchnode(root.left,p)
pinright=not pinleft
qinleft=self.searchnode(root.left,q)
qinright=not qinleft
if pinleft:
if qinright:
return root
return self.lowestCommonAncestor(root.left,p,q)
if qinleft:
if pinright:
return root
return self.lowestCommonAncestor(root.left,p,q)
return self.lowestCommonAncestor(root.right,p,q)
def searchnode(self, root, p):
if not root:
return False
if root == p:
return True
return self.searchnode(root.left, p) or self.searchnode(root.right, p)
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
pathP, pathQ = self.findPath(root, p), self.findPath(root, q)
lenP, lenQ = len(pathP), len(pathQ)
ans, x = None, 0
while x < min(lenP, lenQ) and pathP[x] == pathQ[x]:
ans, x = pathP[x], x + 1
return ans
def findPath(self, root, target):
stack = []
lastVisit = None
while stack or root:
if root:
stack.append(root)
root = root.left
else:
peek = stack[-1]
if peek.right and lastVisit != peek.right:
root = peek.right
else:
if peek == target:
return stack
lastVisit = stack.pop()
root = None
return stack
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
if root in (None,q,p):
return root
if self.isParent(p,q):
return p
if self.isParent(q,p):
return q
while root:
if self.isParent(root.left,p) and self.isParent(root.left,q):
root=root.left
elif self.isParent(root.right,p) and self.isParent(root.right,q):
root=root.right
else:
return root
return root
def isParent(self,p,q):
if not p:
return False
if p==q:
return True
return self.isParent(p.left,q) or self.isParent(p.right,q)
总结:
- 判断p,q是否都在左子树或者都在右子树,若在两边,则该节点就是最近祖先
- 将从根节点到p和q的路径分别记录下来,同时遍历,两者不同之前最后一个节点就是最近祖先
二叉树中的最大路径和
Given a non-empty binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.
Example:
Input: [1,2,3] 1 / \ 2 3 Output: 6
Code(By myself):
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def maxPathSum(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
self.treePathLen = []
res = self.pathSum(root)
return max(self.treePathLen)
def pathSum(self,root):
if not root:
return -float('inf')
leftLen = self.pathSum(root.left)
rightLen = self.pathSum(root.right)
if leftLen == -float('inf') and rightLen == -float('inf'):
treeLen = root.val
elif leftLen == -float('inf'):
treeLen = root.val + rightLen
elif rightLen == -float('inf'):
treeLen = root.val + leftLen
else:
treeLen = root.val + leftLen + rightLen
maxTreeLen = max(treeLen,leftLen,rightLen,root.val,max(leftLen,rightLen) + root.val)
self.treePathLen.append(maxTreeLen)
return max(max(leftLen,rightLen) + root.val, root.val)
Code(others):
class Solution(object):
maxVal = 0
def maxPathSum(self, root):
"""
:type root: TreeNode
:rtype: int
"""
global maxVal
maxVal = root.val
def maxSum(r):
if(r == None):
return 0
curVal = r.val
lmaxSum = maxSum(r.left)
rmaxSum = maxSum(r.right)
if(lmaxSum > 0):
curVal += lmaxSum
if(rmaxSum > 0):
curVal += rmaxSum
global maxVal
if(curVal > maxVal):
maxVal = curVal
return max(r.val, r.val + lmaxSum, r.val + rmaxSum)
maxSum(root)
return maxVal
总结:
- 递归求解,每部都返回节点值、节点值加左子树能到达根节点最长的路径和,节点值加右子树能到达根节点最长的路径和三者最大,全局变量更新子树的最大路径和。
- 思想类似,代码能力差距太大,理清思路在写代码
Friends circles
There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a directfriend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.
Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.
Example:
Input: [[1,1,0], [1,1,0], [0,0,1]] Output: 2 Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. The 2nd student himself is in a friend circle. So return 2.
Code(By myself):
class Solution(object):
def findCircleNum(self, M):
"""
:type M: List[List[int]]
:rtype: int
"""
row = len(M)
count = 0
mark = [True for i in range(row)]
for i in range(row):
if mark[i]:
self.dfs(M,mark,i)
count += 1
return count
def dfs(self,M,mark,i):
mark[i] = False
for j in range(len(M[0])):
if mark[j] and M[i][j] == 1:
self.dfs(M,mark,j)
Code(others):
class Solution(object):
def findCircleNum(self, M):
"""
:type M: List[List[int]]
:rtype: int
"""
if M ==[] or len(M)==0 or len(M[0])!=len(M):
return 0
ans = 0
rest = list(range(len(M)))
while rest:
stack = [rest.pop(0)]
while stack:
cur = stack.pop()
for x in [x for x in rest if M[cur][x]]:
rest.remove(x)
stack.append(x)
ans += 1
return ans
总结:
- 问题本质上是求无向图的连通分量的数量
- 可用dfs和kahn两种算法求解,详细见https://blog.csdn.net/qinzhaokun/article/details/48541117
课程表Ⅰ
There are a total of n courses you have to take, labeled from 0
to n-1
.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
Example:
Input: 2, [[1,0]] Output: true Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
Code(By myself):
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
inDegree = [0 for i in range(numCourses)]
dic = {}
for i in prerequisites:
inDegree[i[0]] += 1
if i[1] not in dic:
dic[i[1]] = [i[0]]
else:
dic[i[1]].append(i[0])
stack = []
n = 0
for i in range(numCourses):
if inDegree[i] == 0:
stack.append(i)
while stack:
cur = stack.pop(0)
n += 1
if cur in dic:
for i in dic[cur]:
inDegree[i] -= 1
if inDegree[i] == 0:
stack.append(i)
if n == numCourses:
return True
else:
return False
Code(others):
class Solution(object):
def canFinish(self, n, pres):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
from collections import deque
ind = [[] for _ in xrange(n)] # indegree
oud = [0] * n # outdegree
for p in pres:
oud[p[0]] += 1
ind[p[1]].append(p[0])
dq = deque()
for i in xrange(n):
if oud[i] == 0:
dq.append(i)
k = 0
while dq:
x = dq.popleft()
k += 1
for i in ind[x]:
oud[i] -= 1
if oud[i] == 0:
dq.append(i)
return k == n
class Solution:
def canFinish(self, numCourses, prerequisites):
graph = [[] for _ in range(numCourses)]
visit = [0 for _ in range(numCourses)]
for x, y in prerequisites:
graph[x].append(y) # 生成每门课的全部先修课程列表,角标为当前课,内容为先修课程列表
def dfs(i):
if visit[i] == -1:
return False
if visit[i] == 1:
return True
visit[i] = -1
for j in graph[i]: # 循环检查所有先修课程的所有先修课程,有没有指向后修课程的,即为-1的
if not dfs(j):
return False
visit[i] = 1
return True
for i in range(numCourses): # 遍历每一门课,检查先修课程以及先修课程的先修课程。。。有没有环
if not dfs(i):
return False
return True
总结:
- 本题本质上是判断有向图中是否存在环
- 可用dfs和kahn两种算法求解,详细见https://blog.csdn.net/qinzhaokun/article/details/48541117
课程表Ⅱ
There are a total of n courses you have to take, labeled from 0
to n-1
.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
Example:
Input: 2, [[1,0]] Output:[0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is[0,1] .
Code(By myself):
class Solution(object):
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
visit = [0 for i in range(numCourses)]
graph = [[] for i in range(numCourses)]
res = []
for i in prerequisites:
graph[i[0]].append(i[1])
def dfs(i):
if visit[i] == -1:
return False
elif visit[i] == 1:
return True
visit[i] = -1
for j in graph[i]:
if not dfs(j):
return False
visit[i] = 1
res.append(i)
return True
for i in range(numCourses):
if not dfs(i):
return []
return res
Code(others):
class Solution(object):
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
graph = [[] for _ in xrange(numCourses)]
ins = [0 for _ in xrange(numCourses)]
for a in prerequisites:
graph[a[1]].append(a[0])
ins[a[0]] += 1
q = []
for i in xrange(numCourses):
if ins[i] == 0:
q.append(i)
res = []
while len(q) > 0:
t = q.pop(0)
res.append(t)
for a in graph[t]:
ins[a] -= 1
if ins[a] == 0:
q.append(a)
return res if len(res) == numCourses else []
class Solution(object):
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
graph = [[] for _ in range(numCourses)]
level = [0 for _ in range(numCourses)]
visit = [0 for _ in range(numCourses)]
for x, y in prerequisites:
graph[x].append(y) # 生成每门课的全部先修课程列表,角标为当前课,内容为先修课程列表
def dfs(i):
_max = level[i]
if visit[i] == -1:
return False, _max
if visit[i] == 1:
return True, _max
visit[i] = -1
for j in graph[i]: # 循环检查所有先修课程的所有先修课程,有没有指向后修课程的,即为-1的
flag, _level = dfs(j)
if not flag:
return False, _max
_max = max(_max, _level+1)
level[i] = _max
visit[i] = 1
return True, _max
for i in range(numCourses): # 遍历每一门课,检查先修课程以及先修课程的先修课程。。。有没有环
flag, _level = dfs(i)
if not flag:
return []
res = {}
for k, v in enumerate(level):
if v not in res:
res[v] = []
res[v].append(k)
ret = []
i = 0
while True:
if i in res:
ret += res[i]
i += 1
else:
break
return ret
总结:
- 本题本质上是求有向图的拓扑序列
- 可用dfs和kahn两种算法求解,详细见https://blog.csdn.net/qinzhaokun/article/details/48541117
计算右侧小于当前元素的个数
You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i]
is the number of smaller elements to the right of nums[i]
.
Example:
Input: [5,2,6,1]
Output: [2,1,1,0]
Explanation:
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.
Code(By myself):
class Solution(object):
def countSmaller(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
if not nums:
return nums
n = len(nums)
counts = [0 for i in range(n)]
temp = [nums[n-1]]
for i in range(n-2,-1,-1):
left = 0
right = len(temp)
while left < right:
mid = (left + right) // 2
if temp[mid] < nums[i]:
left = mid + 1
else:
right = mid
counts[i] = left
temp.insert(left,nums[i])
return counts
Code(others):
class BinaryIndexedTree(object):
def __init__(self, n):
self.sums = [0] * (n + 1)
def update(self, i, val):
while i < len(self.sums):
self.sums[i] += 1
i += i & -i
def sum(self, i):
r = 0
while i > 0:
r += self.sums[i]
i -= i & -i
return r
class Solution(object):
def countSmaller(self, nums):
hashTable = {v: i for i, v in enumerate(sorted(set(nums)))}
tree, r = BinaryIndexedTree(len(hashTable)), []
for i in xrange(len(nums) - 1, -1, -1):
r.append(tree.sum(hashTable[nums[i]]))
tree.update(hashTable[nums[i]] + 1, 1)
return r[::-1]
class Solution:
def countSmaller(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
tmp = []
ans = []
for i in nums[::-1]:
x = bisect.bisect_left(tmp, i)
ans.append(x)
tmp.insert(x, i)
return ans[::-1]
总结:
- 利用双层循环时间复杂度为O(n²),不满足时间要求,则插入采取二分查找后插入,时间复杂度为O(n²)顺利通过。
单词接龙
Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time.
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Example:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: 5 Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5.
Code(By myself):
import string
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: int
"""
if endWord not in wordList:
return 0
queue = [beginWord]
n = len(beginWord)
wordDic = {}
for i in wordList:
if i not in wordDic:
wordDic[i] = 1
lowercase = [i for i in string.lowercase]
dic = {}
dic[beginWord] = 1
while queue:
cur = queue.pop(0)
for i in range(n):
for j in lowercase:
temp = cur
if temp[i] == j:
continue
else:
temp = temp[:i] + j + temp[i+1:]
if temp == endWord:
return dic[cur] + 1
if temp in wordDic and temp not in dic:
queue.append(temp)
dic[temp] = dic[cur] + 1
if endWord not in dic:
return 0
return dic[endWord]
Code(others):
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
if endWord not in wordList:
return 0
wordList = set(wordList)
forward, backward, n, cnt = {beginWord}, {endWord}, len(beginWord), 2
dic = set(string.ascii_lowercase)
while len(forward) > 0 and len(backward) > 0:
if len(forward) > len(backward): # 加速
forward, backward = backward, forward
next = set()
for word in forward:
for i, char in enumerate(word):
first, second = word[:i], word[i + 1:]
for c in dic: # 遍历26个字母
candidate = first + c + second
if candidate in backward: # 如果找到了,返回结果,没有找到,则在wordList中继续寻找
return cnt
if candidate in wordList:
wordList.discard(candidate) # 从wordList中去掉单词
next.add(candidate) #加入下一轮的bfs中
forward = next
cnt += 1
return 0
总结:
- 利用广度优先搜索BFS算法,队列可以实现,每次找到最接近的,相当于树的层次遍历。
矩阵中最长的递增路径
Given an integer matrix, find the length of the longest increasing path.
From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).
Example:
Input: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9]
.
Code(By myself):
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
maxPathLen = 0
if not matrix:
return maxPathLen
row = len(matrix)
col = len(matrix[0])
path = [(1,0),(-1,0),(0,1),(0,-1)]
maxPath = [[-1 for j in range(col)] for i in range(row)]
def increasingPath(matrix,i,j,pre):
n = 0
if i < 0 or i >= row or j < 0 or j >= col:
return n
if matrix[i][j] > pre:
if maxPath[i][j] >= 0:
return maxPath[i][j]
for temp in path:
n = max(n, increasingPath(matrix, i + temp[0], j + temp[1], matrix[i][j]) + 1)
maxPath[i][j] = max(maxPath[i][j],n)
return n
for i in range(row):
for j in range(col):
m = 0
for k in path:
m = max(m, increasingPath(matrix, i + k[0], j + k[1], matrix[i][j]) + 1)
maxPath[i][j] = max(maxPath[i][j],m)
maxPathLen = max(maxPathLen, m)
return maxPathLen
Code(others):
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
if not matrix or not matrix[0]:
return 0
m = len(matrix)
n = len(matrix[0])
memo = [[0] * n for i in range(m)]
def helper(i, j):
if not memo[i][j]:
ans = 0
num = matrix[i][j]
if i > 0 and matrix[i-1][j] > num:
ans = max(ans, helper(i-1, j))
if j > 0 and matrix[i][j-1] > num:
ans = max(ans, helper(i, j-1))
if i < m - 1 and matrix[i+1][j] > num:
ans = max(ans, helper(i+1, j))
if j < n - 1 and matrix[i][j+1] > num:
ans = max(ans, helper(i, j+1))
memo[i][j] = ans + 1
return memo[i][j]
ans = 0
for i in range(m):
for j in range(n):
ans = max(ans, helper(i, j))
return ans
总结:
- 在寻找最长路径的过程中,在新建的一个二维表中记录每个计算过的点的最长递增路径
- 优化代码