LeetCode四月刷題總結-按類型
這個是四月每日一題的總結,題解基本是官方題解,我按照自己的想法分了一下類方便查閱。主要使用python3解題,如果使用其他語言或者對其他解法感興趣的可以去官方看哈~prac代表題號。
矩陣相關
採用位置座標解題
動態規劃+搜索
prac542-01矩陣
題目描述:
給定一個由 0 和 1 組成的矩陣,找出每個元素到最近的 0 的距離。兩個相鄰元素間的距離爲 1 。
示例 1: 輸入:
0 0 0 0 1 0 0 0 0 輸出:
0 0 0 0 1 0 0 0 0
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/01-matrix
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
# -*- encoding: utf-8 -*-
"""
@File : prac542.py
@Time : 2020/4/15 8:27 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
01矩陣
廣度優先搜索可以找到從起點到其他所有點的最短距離
"""
import collections
from typing import List
class Solution:
"""廣度優先搜索
時間複雜度O(rc)
"""
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m,n = len(matrix),len(matrix[0])
dist = [[0]*n for _ in range(m)]
zeroes_pos = [(i,j) for i in range(m) for j in range(n) if matrix[i][j] == 0]
q = collections.deque(zeroes_pos)
seen = set(zeroes_pos)
# 廣度優先搜索
while q:
i,j = q.popleft()
for ni,nj in [(i-1,j),(i,j-1),(i+1,j),(i,j+1)]:
if 0<=ni<m and 0<=nj<n and (ni,nj) not in seen:
dist[ni][nj] = dist[i][j] + 1
q.append((ni,nj))
seen.add((ni,nj))
return dist
class Solution1:
"""動態規劃
需要遍歷四次矩陣,時間複雜度O(4rc)=O(rc)
"""
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
"""
對於矩陣中的任意一個1和一個0,從1到達0距離最短的方法:
- 只有水平向左移動和豎直向上移動
- 只有水平向左移動和豎直向下移動
- 只有水平向右移動和豎直向上移動
- 只有水平向右移動和豎直向下移動
:param matrix:
:return:
"""
m, n = len(matrix),len(matrix[0])
# 初始化動態規劃的數組,所有的距離值都設置一個很大的數
dist = [[10**9] * n for _ in range(m)]
# 如果(i,j)的元素爲0,那麼距離爲0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
dist[i][j] = 0
# 默認向左向上爲正,注意動態規劃計算順序
# 只有 水平向左移動 和 豎直向上移動
for i in range(m):
for j in range(n):
if i-1 >= 0:
dist[i][j] = min(dist[i][j],dist[i-1][j]+1)
if j-1 >= 0:
dist[i][j] = min(dist[i][j],dist[i][j-1]+1)
# 只有 水平向右移動 和 豎直向上移動
for i in range(m):
for j in range(n-1,-1,-1):
if i-1 >= 0:
dist[i][j] = min(dist[i][j],dist[i-1][j]+1)
if j+1 < n:
dist[i][j] = min(dist[i][j],dist[i][j+1]+1)
# 只有 水平向右移動 和豎直向下移動
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
if i+1 < m:
dist[i][j] = min(dist[i][j],dist[i+1][j]+1)
if j+1 < n:
dist[i][j] = min(dist[i][j],dist[i][j+1]+1)
return dist
class Solution2:
"""動態規劃的常數優化
需要遍歷兩次矩陣O(2rc)=O(rc)
"""
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
"""
- 只有 水平向左移動 和 豎直向上移動
- 只有 水平向右移動 和 豎直向下移動
去掉一些重複計算的地方
:param matrix:
:return:
"""
m,n = len(matrix),len(matrix[0])
# 初始化動態規劃的數組,所有的距離值都設置一個很大的數
dist = [[10 ** 9] * n for _ in range(m)]
# 如果(i,j)的元素爲0,那麼距離爲0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
dist[i][j] = 0
# 只有 水平向左移動 和 豎直向上移動
for i in range(m):
for j in range(n):
if i - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1)
if j - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1)
# 只有 水平向右移動 和豎直向下移動
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
if i + 1 < m:
dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1)
if j + 1 < n:
dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1)
return dist
if __name__ == '__main__':
# 0 0 0
# 0 1 0
# 0 0 0
matrix = [[0,0,0],
[0,1,0],
[0,0,0]]
s = Solution()
print(s.updateMatrix(matrix))
面試題13
題目描述:
地上有一個m行n列的方格,從座標 [0,0] 到座標 [m-1,n-1] 。一個機器人從座標 [0, 0] 的格子開始移動,它每次可以向左、右、上、下移動一格(不能移動到方格外),也不能進入行座標和列座標的數位之和大於k的格子。例如,當k爲18時,機器人能夠進入方格 [35, 37] ,因爲3+5+3+7=18。但它不能進入方格 [35, 38],因爲3+5+3+8=19。請問該機器人能夠到達多少個格子?示例 1:
輸入:m = 2, n = 3, k = 1 輸出:3 示例 2:
輸入:m = 3, n = 1, k = 0 輸出:1
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
# -*- encoding: utf-8 -*-
"""
@File : 面試題13.py
@Time : 2020/4/8 12:02 下午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
"""
class Solution:
"""廣度優先搜索"""
def movingCount(self, m, n, k):
from queue import Queue
q = Queue()
q.put((0,0))
s = set()
while not q.empty():
x,y = q.get()
if (x,y) not in s and 0<=x<m and 0<=y<n and self.digitsum(x)+self.digitsum(y)<=k:
s.add((x,y))
# 向右、向下搜索
for nx,ny in [((x+1),y),(x,(y+1))]:
q.put((nx,ny))
return len(s)
def digitsum(self,n):
ans = 0
while n:
ans += n%10
n //= 10
return ans
if __name__ == '__main__':
m = 2
n = 3
k = 1
s = Solution()
print(s.monvingCount(m,n,k))
prac200-島嶼數量
題目描述
給你一個由 ‘1’(陸地)和 ‘0’(水)組成的的二維網格,請你計算網格中島嶼的數量。島嶼總是被水包圍,並且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。
此外,你可以假設該網格的四條邊均被水包圍。
示例 1:
輸入: 11110 11010 11000 00000 輸出: 1
示例 2:輸入: 11000 11000 00100 00011 輸出: 3 解釋: 每座島嶼只能由水平和/或豎直方向上相鄰的陸地連接而成。
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/number-of-islands
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
# -*- encoding: utf-8 -*-
"""
@File : prac200.py
@Time : 2020/4/20 8:28 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
"""
from typing import List
class Solution:
"""
深度優先搜索,時間複雜度O(M*N),M,N爲矩陣的行、列數
"""
def dfs(self, grid, r, c):
grid[r][c] = 0
nr, nc = len(grid), len(grid[0])
for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
self.dfs(grid, x, y)
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
self.dfs(grid, r, c)
return num_islands
if __name__ == '__main__':
grid1 = [["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]
s = Solution()
print(s.numIslands(grid1))
prac289-生命遊戲
# -*- encoding: utf-8 -*-
"""
@File : prac289.py
@Time : 2020/4/2 9:37 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
給定一個包含 m × n 個格子的面板,每一個格子都可以看成是一個細胞。每個細胞都具有一個初始狀態:1 即爲活細胞(live),或 0 即爲死細胞(dead)。每個細胞與其八個相鄰位置(水平,垂直,對角線)的細胞都遵循以下四條生存定律:
如果活細胞周圍八個位置的活細胞數少於兩個,則該位置活細胞死亡;
如果活細胞周圍八個位置有兩個或三個活細胞,則該位置活細胞仍然存活;
如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡;
如果死細胞周圍正好有三個活細胞,則該位置死細胞復活;
根據當前狀態,寫一個函數來計算面板上所有細胞的下一個(一次更新後的)狀態。下一個狀態是通過將上述規則同時應用於當前狀態下的每個細胞所形成的,其中細胞的出生和死亡是同時發生的。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/game-of-life
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
"""
class Solution:
def gameOfLife(self, board):
"""
不返回任何值,僅就地修改細胞板子
"""
# 八個相鄰位置
neighbors = [(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1)]
rows = len(board)
cols = len(board[0])
# 複製原數組,作爲規則引用
copy_board = [[board[row][col] for col in range(cols)] for row in range(rows)]
#雙層循環遍歷數組
for row in range(rows):
for col in range(cols):
# 對於每一個細胞統計其八個相鄰位置活細胞數量
live_neighbors = 0
for neighbor in neighbors:
r = (row + neighbor[0])
c = (col + neighbor[1])
# 查看相鄰的細胞是否爲活細胞
if (r<rows and r>=0) and (c<cols and c>=0) and (copy_board[r][c]==1):
live_neighbors += 1
# 如果活細胞周圍八個位置的活細胞數少於兩個,則該位置活細胞死亡;
# 如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡;
if copy_board[row][col] == 1 and (live_neighbors < 2 or live_neighbors > 3):
board[row][col] = 0
# 如果死細胞周圍正好有三個活細胞,則該位置死細胞復活;
if copy_board[row][col] == 0 and live_neighbors == 3:
board[row][col] = 1
class Solution1:
"""定義複合狀態,原地改變數組
例子:如果細胞之前的狀態是 0,但是在更新之後變成了 1,我們就可以給它定義一個複合狀態 2
"""
def gameOfLife(self, board):
# 八個相鄰位置
neighbors = [(1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1)]
rows = len(board)
cols = len(board[0])
# 雙層循環遍歷數組
for row in range(rows):
for col in range(cols):
# 對於每一個細胞統計其八個相鄰位置活細胞數量
live_neighbors = 0
for neighbor in neighbors:
r = (row + neighbor[0])
c = (col + neighbor[1])
# 查看相鄰的細胞是否爲活細胞
if (r < rows and r >= 0) and (c < cols and c >= 0) and (abs(board[r][c]) == 1):
live_neighbors += 1
# 如果活細胞周圍八個位置的活細胞數少於兩個,則該位置活細胞死亡;
# 如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡;
if board[row][col] == 1 and (live_neighbors < 2 or live_neighbors > 3):
# -1代表這個細胞過去是火的現在死了
board[row][col] = -1
# 如果死細胞周圍正好有三個活細胞,則該位置死細胞復活;
if board[row][col] == 0 and live_neighbors == 3:
# 2代表這個細胞過去是死的現在活了
board[row][col] = 2
# 遍歷board得到一次更新後的狀態
for row in range(rows):
for col in range(cols):
if board[row][col] > 0:
board[row][col] = 1
else:
board[row][col] = 0
if __name__ == '__main__':
board = [
[0, 1, 0],
[0, 0, 1],
[1, 1, 1],
[0, 0, 0]
]
s = Solution1()
s.gameOfLife(board)
print(board)
容器盛水問題
prac42-接雨水
雙指針求法
給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。
上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。
示例:
輸入: [0,1,0,2,1,0,1,3,2,1,2,1] 輸出: 6
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/trapping-rain-water
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
# -*- encoding: utf-8 -*-
"""
@File : prac42.py
@Time : 2020/4/4 8:49 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
單調棧,單調隊列
"""
class Solution:
"""按行求解,提交後超出時間限制"""
def trap(self, height):
sum = 0
max_h = max(height)
for i in range(1,max_h+1):
# 標記是否開始更新
is_start = False
temp = 0
for j in range(len(height)):
# 如果當前的高度小於 i,並且兩邊有高度大於等於 i 的,說明這個地方一定有水,水就可以加 1
if is_start and height[j] < i:
temp += 1
# 遇到高度大於等於 i 的,就把 temp 加到最終的答案 ans 裏,並且 temp 置零,然後繼續循環。
if height[j] >= i:
sum = sum + temp
temp = 0
is_start = True
return sum
def get_max(self,height):
"""
找到最大高度
:param height:
:return:
"""
max_height = 0
for i in range(len(height)):
if height[i]>max_height:
max_height = height[i]
return max_height
class Solution1:
"""雙指針求法"""
def trap(self, height):
n = len(height)
if n == 0:
return 0
left = 0
right = n -1
# max_left [i] 代表第 i 列左邊最高的牆的高度
max_left = height[left]
# max_right[i] 代表第 i 列右邊最高的牆的高度
max_right = height[right]
ans = 0
while(left < right):
if max_left <= max_right:
ans += max_left-height[left]
left += 1
max_left = max(height[left],max_left)
if max_left > max_right:
ans += max_right-height[right]
right -= 1
max_right = max(height[right],max_right)
return ans
class Solution3:
"""棧的求法,類似括號匹配"""
def trap(self, height):
"""
將每堵牆作爲棧元素入棧
:param height:
:return:
"""
sum = 0
stack = []
current = 0
# 如果當前高度<棧頂高度,則入棧
while(current<len(height)):
# 如果棧不空且當前高度大於棧頂高度就一直循環
while(len(stack) != 0 and height[current] > height[stack[-1]]):
h = height[stack[-1]]
# 如果當前高度>棧頂高度,就出棧
stack.pop()
if len(stack) == 0:
break
# 計算兩堵牆之間的距離
distance = current - stack[-1] - 1
min_h = min(height[stack[-1]],height[current])
sum = sum + distance * (min_h - h)
stack.append(current)
current += 1
return sum
if __name__ == '__main__':
height = [0,1,0,2,1,0,1,3,2,1,2,1]
s = Solution3()
print(s.trap(height))
prac11-盛最多水的容器
給你 n 個非負整數 a1,a2,…,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別爲 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
說明:你不能傾斜容器,且 n 的值至少爲 2。
圖中垂直線代表輸入數組 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示爲藍色部分)的最大值爲 49。
示例:
輸入:[1,8,6,2,5,4,8,3,7] 輸出:49
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/container-with-most-water
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
# -*- encoding: utf-8 -*-
"""
@File : prac11.py
@Time : 2020/4/18 9:22 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
容納的水量 = 兩個指針指向的數字中較小值*指針之間的距離
"""
from typing import List
class Solution:
"""雙指針解法"""
def maxArea(self, height: List[int]) -> int:
l, r = 0,len(height)-1
ans = 0
while l < r:
area = min(height[l],height[r])*(r-l)
ans = max(ans,area)
if height[l] <= height[r]:
l += 1
else:
r -= 1
return ans
if __name__ == '__main__':
lis = [1,8,6,2,5,4,8,3,7]
s = Solution()
print(s.maxArea(lis))