[LeetCode] #54. Spiral Matrix
題目
Given an m x n
matrix
, return all elements of the matrix
in spiral order.
直覺解
構想:
dictionary.target 紀錄接下來要印哪一個 row/ cole,用 dictionary.star 和 ictionary.end 紀錄是從哪裡印到哪裡。
如果 cell 位於 row 和 col 的交叉點,則把該 cell 歸類為 row。以 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
為例,cell 的歸類順序是:
上 row:
1, 2, 3
右 col:
6
下 row:
9, 8, 7
左 col:
4
上 row:
5
python 3 實作(失敗):
class Solution:
ans = []
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
self.ans = []
if matrix is None:
return self.ans
row = {'target': 0, 'star': 0, 'end': len(matrix[0]), 'reverse': False}
col = {
'target': len(matrix[0]) - 1,
'star': row['target'] + 1,
'end': len(matrix) - 1,
'reverse': False
}
while row['star'] < row['end'] and col['star'] < col['end']:
if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
if col['star'] < col['end']:
self.matrix_col(row, col, matrix)
else:
if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
elif col['star'] < col['end']:
self.matrix_col(row, col, matrix)
return self.ans
def matrix_row(self, row, col, matrix):
if row['reverse'] is False:
for num in matrix[row['target']][row['star']:row['end']]:
self.ans.append(num)
col['target'] = row['end'] - 1
else:
for num in reversed(matrix[row['target']][row['star']:row['end']]):
self.ans.append(num)
col['target'] = row['star']
row['star'] += 1
row['end'] -= 1
row['reverse'] = not row['reverse']
def matrix_col(self, row, col, matrix):
if col['reverse'] is False:
for i in range(col['star'], col['end']):
self.ans.append(matrix[i][col['target']])
row['target'] = col['end']
else:
for i in reversed(range(col['star'], col['end'])):
self.ans.append(matrix[i][col['target']])
row['target'] = col['star']
col['star'] += 1
col['end'] -= 1
col['reverse'] = not col['reverse']
Submission Detail
Wrong Answer
Input: [[3],[2]]
Output: [3]
Expected: [3,2]
失敗原因
因為「如果 cell 位於 row 和 col 的交叉點,則把該 cell 歸類為 row。」的設計,造成補東牆破西牆的問題。
原本的 while 迴圈長得比較清爽:
while row['star'] < row['end'] or col['star'] < col['end']:
if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
if col['star'] < col['end']:
self.matrix_col(row, col, matrix)
但原本的 while 迴圈在 Input: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
時,在 row['reverse'] 是 False 時已經窮盡了 matrix 中的所有 cell,但因為 row 的 star 和 end 只會在 row['reverse'] 是 True 時更新,導致重複把 5 放進去 ans 裡。為了避免這個問題,才把 while 迴圈改成現在的樣子。
但現在的 while 迴圈在 Input: [[3],[2]]
時,因為歸類 cell 的方式,導致沒有 col,而只有兩個 row,所以我需要執行兩次 matrix_row 函式,才能完成題目指定的結果。但我的程式碼只允許執行一次 matrix_row 函式(因為沒辦法滿足 col['star'] < col['end']
的條件)。
構想:
更改 cell 的歸類方式。以 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
為例,cell 的 歸類順序是:
上 row:
1, 2, 3
右 col:
6, 9
下 row:
8, 7
左 col:
4
上 row:
5
python 3 實作(失敗):
class Solution:
ans = []
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
self.ans = []
if matrix is None:
return self.ans
row = {'target': 0, 'star': 0, 'end': len(matrix[0]), 'reverse': False}
col = {
'target': len(matrix[0]) - 1,
'star': row['target'] + 1,
'end': len(matrix),
'reverse': False
}
while row['star'] < row['end'] and col['star'] < col['end']:
if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
if col['star'] < col['end']:
self.matrix_col(row, col, matrix)
return self.ans
def matrix_row(self, row, col, matrix):
if row['reverse'] is False:
for num in matrix[row['target']][row['star']:row['end']]:
self.ans.append(num)
col['target'] = row['end'] - 1
col['star'] = row['target'] + 1
else:
for num in reversed(matrix[row['target']][row['star']:row['end']]):
self.ans.append(num)
col['target'] = row['star']
col['end'] = row['target']
row['reverse'] = not row['reverse']
def matrix_col(self, row, col, matrix):
if col['reverse'] is False:
for i in range(col['star'], col['end']):
self.ans.append(matrix[i][col['target']])
row['target'] = col['end'] - 1
row['end'] = col['target']
else:
for i in reversed(range(col['star'], col['end'])):
self.ans.append(matrix[i][col['target']])
row['target'] = col['star']
row['star'] = col['target'] + 1
col['reverse'] = not col['reverse']
Submission Detail
Wrong Answer
Input: [[1]]
Output: []
Expected: [1]
失敗原因
len(matrix)
是 1 的時候,進不去 while 迴圈。
構想:
len(matrix)
是 1 的時候,當作特例處理。
python 3 實作:
class Solution:
ans = []
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
self.ans = []
if matrix is None:
return self.ans
if len(matrix) == 1:
return matrix[0][:]
row = {'target': 0, 'star': 0, 'end': len(matrix[0]), 'reverse': False}
col = {
'target': len(matrix[0]) - 1,
'star': row['target'] + 1,
'end': len(matrix),
'reverse': False
}
while row['star'] < row['end'] and col['star'] < col['end']:
if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
if col['star'] < col['end']:
self.matrix_col(row, col, matrix)
return self.ans
def matrix_row(self, row, col, matrix):
if row['reverse'] is False:
for num in matrix[row['target']][row['star']:row['end']]:
self.ans.append(num)
col['target'] = row['end'] - 1
col['star'] = row['target'] + 1
else:
for num in reversed(matrix[row['target']][row['star']:row['end']]):
self.ans.append(num)
col['target'] = row['star']
col['end'] = row['target']
row['reverse'] = not row['reverse']
def matrix_col(self, row, col, matrix):
if col['reverse'] is False:
for i in range(col['star'], col['end']):
self.ans.append(matrix[i][col['target']])
row['target'] = col['end'] - 1
row['end'] = col['target']
else:
for i in reversed(range(col['star'], col['end'])):
self.ans.append(matrix[i][col['target']])
row['target'] = col['star']
row['star'] = col['target'] + 1
col['reverse'] = not col['reverse']
效能:
Runtime: 20 ms, faster than 99.19% of Python3 online submissions for Spiral Matrix.
Memory Usage: 14.3 MB, less than 27.63% of Python3 online submissions for Spiral Matrix.
感想:這個程式碼,讀起來真是太眼花撩亂了⋯⋯
研究別人的解
來源:Python Easy to Understand beats 98 %
研究重點:怎麼寫得更易讀一點。
別人的 python 3 實作:
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m = len(matrix)
n = len(matrix[0])
left = 0
right = n-1
down = m-1
top = 0
direction = 0
ans = []
while(left<=right and down>=top):
if direction ==0:
# go right
for i in range(left , right+1):
ans.append(matrix[top][i])
top+=1
elif direction==1:
#go down
for j in range(top , down+1):
ans.append(matrix[j][right])
right-=1
elif direction ==2:
#go left
for j in range(right , left-1,-1):
ans.append(matrix[down][j])
down-=1
elif direction==3:
#go up
for j in range(down , top-1 , -1):
ans.append(matrix[j][left])
left+=1
direction= (direction +1)%4
return ans
效能:
Runtime: 28 ms, faster than 83.67% of Python3 online submissions for Spiral Matrix.
Memory Usage: 14.4 MB, less than 27.56% of Python3 online submissions for Spiral Matrix.
研究感想
direction 的用法好妙!直接用變數存上下左右的範圍,而不是包在 dictionary 裡面,value 取用起來乾淨俐落很多。依照我的寫法,還要特地存一個 target 用來標示要印哪一個 row/ col,但是他只要用上下左右的範圍,就可以直接知道輪到印哪一個 row/ col 了。原來 range 這樣使用就可以把數字由大往小的方向迭代。
他的「上」初始值是 0。我的「上」初始值是 row['target'] + 1,導致 matrix 只有一行的時候就進不去我的 while 迴圈,而需要把只有一行的 matrix 當作特例處理。
我的 while 迴圈裡的 if 其實可以刪掉。
小幅度優化我的 python 實作:為了方便對照,刪掉的地方姑且用 # 註解掉
class Solution:
ans = []
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
self.ans = []
if matrix is None:
return self.ans
# if len(matrix) == 1:
# return matrix[0][:]
row = {'target': 0, 'star': 0, 'end': len(matrix[0]), 'reverse': False}
col = {
'target': len(matrix[0]) - 1,
'star': 0,
'end': len(matrix),
'reverse': False
}
while row['star'] < row['end'] and col['star'] < col['end']:
# if row['star'] < row['end']:
self.matrix_row(row, col, matrix)
# if col['star'] < col['end']:
self.matrix_col(row, col, matrix)
return self.ans
def matrix_row(self, row, col, matrix):
if row['reverse'] is False:
for num in matrix[row['target']][row['star']:row['end']]:
self.ans.append(num)
col['target'] = row['end'] - 1
col['star'] = row['target'] + 1
else:
for num in reversed(matrix[row['target']][row['star']:row['end']]):
self.ans.append(num)
col['target'] = row['star']
col['end'] = row['target']
row['reverse'] = not row['reverse']
def matrix_col(self, row, col, matrix):
if col['reverse'] is False:
for i in range(col['star'], col['end']):
self.ans.append(matrix[i][col['target']])
row['target'] = col['end'] - 1
row['end'] = col['target']
else:
for i in reversed(range(col['star'], col['end'])):
self.ans.append(matrix[i][col['target']])
row['target'] = col['star']
row['star'] = col['target'] + 1
col['reverse'] = not col['reverse']
效能:
第一次:
Runtime: 24 ms, faster than 95.43% of Python3 online submissions for Spiral Matrix.
Memory Usage: 14 MB, less than 95.18% of Python3 online submissions for Spiral Matrix.
第二次:
Runtime: 28 ms, faster than 83.67% of Python3 online submissions for Spiral Matrix.
Memory Usage: 14.4 MB, less than 27.56% of Python3 online submissions for Spiral Matrix.
Comments
Post a Comment