# [array and string] Introduction to 2D array

Posted by poelinca on Fri, 19 Jun 2020 13:33:37 +0200

catalog

2, Introduction to 2D array

2.1 rotation matrix

2.2 zero matrix

# 2, Introduction to 2D array

## 2.1 rotation matrix

### 2.1.1 problem description   ### 2.1.2 solution process

Method 1: no additional space is allowed, so you can only operate in place. In other words, each transformation must be completed once and cannot be accessed again. For this purpose, you can choose to rotate 90 ° clockwise for four corresponding position elements at a time from the outer layer to the inner layer. The number of circulation floor s is determined by rounding up n/2. The complexity is determined by rounding up n*n/4, which is O(n^2)

2020 / 06 / 01 - the solution is basically unique

```class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
# Adjust 4 pieces at a time, total n*n/4 up rounding
n = len(matrix)
if n <= 1:
return matrix

#quo, rem = divmod(n, 2)
#floor = quo + rem
floor = sum(divmod(n, 2))  # From outside to inside, processing layers
# i is the starting index of each layer, for example, the outermost layer starts from   for the first time, and the second layer starts from  
for i in range(floor):  # Number of layers
limit = n-i-1  # Upper index limit of current layer
k = 0  # index adjust auxiliary variable
for j in range(i, limit):  # Adjust the positions of 4 elements clockwise at the same time each time
matrix[i][j], matrix[j][limit], matrix[limit][limit-k], matrix[limit-k][i] = \
matrix[limit-k][i], matrix[i][j], matrix[j][limit], matrix[limit][limit-k]
k += 1
return matrix```

## 2.2 zero matrix

### 2.2.1 problem description   ### 2.2.2 solution process

Method 1: simple / violent method, the first traversal is used to find and record 0 elements, the second traversal is used to clear the row elements, and the third traversal is used to clear the column elements. It is inefficient because it contains many redundant operations. Complexity O(n^2).

In addition, using list derivation is better than *x, because you can avoid each row of 0 pointing to the same 0 list object! (although this topic does not reflect the harmfulness)

2020 / 06 / 01 - 81.48% - basically the best way

```class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
if (len(matrix) <= 1) and (0 not in matrix):  # Special case [[0,1]]
pass
else:
zero_row = set()  # Save the abscissa of the 0 element
zero_col = set()  # Save the ordinates of the 0 element
# Search and record zero
for i, row in enumerate(matrix):
for j, num in enumerate(row):
if num == 0:
# Line clearing
for r_i in zero_row:
matrix[r_i] = [0 for _ in range(len(matrix))]
# Column zeroing
for c_j in zero_col:
for k in range(len(matrix)):
matrix[k][c_j] = 0```

Method 2: simple method to optimize I. Add hasZero as a Flag to identify whether the current line has zero. If there is one, the whole line will be cleared directly after traversing the line. It is unnecessary to open another for loop to specifically clear the line. But the column is not good, because it is uncertain whether a new column index will be added, so a new for loop must be opened to clear the column. Complexity O(n^2).

2020/06/01 -

```class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
if (len(matrix) <= 1) and (0 not in matrix):  # Special case [[0,1]]
pass
else:
zero_col = set()  # Save the ordinates of the 0 element
# Search and record zero
for i, row in enumerate(matrix):
hasZero = False
for j, num in enumerate(row):
if num == 0:
hasZero = True
if hasZero:
matrix[i] = [0 for _ in range(len(matrix))]  # Clean up
# Column zeroing
for c_j in zero_col:
for k in range(len(matrix)):
matrix[k][c_j] = 0```

Method 3: simple method optimization II. Add zero again_ Row is used to store row index without 0, so as to combine zero_column implements the processing of the remaining 0. Complexity O(n^2).

2020/06/01 -

```class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
if (len(matrix) <= 1) and (0 not in matrix):  # Special case [[0,1]]
pass
else:
zero_row = set()  # Save row index without 0 element
zero_col = set()  # Save the ordinates of the 0 element
# Search and record 0
for i, row in enumerate(matrix):
hasZero = False  # This bank has 0 flag
for j, num in enumerate(row):
if num == 0:
hasZero = True
if hasZero:
matrix[i] = [0 for _ in range(len(matrix))]  # Zero in this line, clear the whole line directly
else:
zero_row.add(i)  # No 0 in this line, record line index for subsequent cleaning
# Clear the rest of the elements
for r_i in zero_row:
for c_j in zero_col:
matrix[r_i][c_j] = 0```

## 2.3 diagonal traversal

### 2.3.1 problem description   ### 2.2.2 solution process (☆)

Method 1 (intuitionistic method / naive method): in the example, the input range of two-dimensional array is 0-2. Let's first observe the ergodic Law: (0, 0) → (0, 1) → (1, 0) → (2, 0) → (1, 1) → (0, 2) → (1, 2) → (2, 1) → (2, 2). If the array index is (m, n), there are two ways to change the index: (m-1, n+1) or (m+1, n-1).

The array starts from (0,0) and the index changes in the way of (m-1, n+1), i.e. (0, 0) → (- 1, 1) (i.e. 0-1 = - 1, 0 + 1 = 1), but the abscissa m = -1 is out of the range (0 ~ 2), let m = 0 (to be within the range of 0 ~ 2) to get the starting point of the next traverse (0, 1).

Then, switch the index change mode to (m+1, n-1), execute (0, 1) → (1, 0) → (2, - 1) successively, but at this time, the ordinate n=-1 is out of the range (0 ~ 2), similarly, let n = 0 (to be within the range of 0 ~ 2) to get the starting point of the next traverse (2, 0).

Switch the index change mode to (m-1, n+1) again, execute (2, 0) → (1, 1) → (0, 2) → (- 1, 3) successively until it is out of range (0 ~ 2). However, the difference is that m < 0 and N > 2 are out of range. At this time, we should first determine whether n is out of range, and then, in particular, execute (m+2, n-1) implementation (- 1,3) → (1,2), to avoid switching the index change mode again due to m < 0.

Then, the index change mode switches back to (m+1, n-1) normally, and executes (1, 2) → (2, 1) → (3, 0) successively. Because m > 2 is out of range, execute (m-1, n+2) specially to realize (3, 0) → (2, 2) traversal.

It can be seen that two normal traversal directions (top right and bottom left) correspond to two index change modes respectively; four special cases (horizontal and vertical coordinates exceeding top and next) correspond to four index correction modes respectively, and adjust the traversal direction at the same time. Complexity O(n)

2020 / 06 / 03 - 51.32% - online data, but actually the second fastest algorithm!

```class Solution:
def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
# Special case handling mechanism
if not matrix:  # matrix = []
return []

col = len(matrix)  # Lines / ordinate Max
row = len(matrix)  # Number of columns / maximum abscissa
nums = col * row  # Total elements
m = 0  # Starting point abscissa index
n = 0  # Starting point ordinate index
flag = True  # Used to determine coordinate transformation mechanism (m-1, n+1) or (m+1, n-1)
res = []  # Initializing the list of diagonal traversal elements

# Start diagonal traversal of all elements in the matrix
for i in range(nums):
# Include element
res.append(matrix[m][n])
# Normal traversal
if flag:        # Coordinate transformation mechanism (m-1, n+1)
m -= 1
n += 1
else:           # Coordinate transformation mechanism (m+1, n-1)
m += 1
n -= 1
# Special case correction
if m >= col:    # If the abscissa m is greater than the range, one time order (m-1, n+2)
m -= 1
n += 2
flag = True
elif n >= row:  # If the ordinate n is greater than the range, one time order (m+2, n-1)
m += 2
n -= 1
flag = False
if m < 0:       # If the abscissa m is less than the range, let m=0 at one time
m = 0
flag = False
elif n < 0:     # If the ordinate n is less than the range, let n=0 at one time
n = 0
flag = True

return res```

Method 2: the same unknown principle. The former uses nested list to add elements; the latter uses defaultdict to add elements, so the efficiency is the highest!

2020 / 06 / 03 - (front) 97% - (back) 99% - reference answer

```class Solution:
def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
# Special case handling
if not matrix:
return []
row = len(matrix)  # Lines / ordinate Max
col = len(matrix)  # Number of columns / maximum abscissa
l = row + col - 1  # Total elements - 1
# Using list derivation to generate empty nested list as auxiliary table
rets = [[] for _ in range(l)]  # Faster and safer than [[] * l]!

for i in range(row):
for j, num in enumerate(matrix[i]):
rets[i+j].append(num)
print(rets)
# Initialize output results
ret = []
for k, x in enumerate(rets):
ret += x if (k % 2 == 1) else x[::-1]  # One line, unknown principle
print(ret)
return ret
# -------------------------------------------------------------------------------
class Solution:
def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
# Special case handling
if not matrix:
return []

# Construct default list dictionary
dic = collections.defaultdict(list)
# Add elements according to the sum of index
for i in range(len(matrix)):
for j in range(len(matrix)):
dic[i+j].append(matrix[i][j])
print(dic)

# Initialize output results
res = []
for i in range(len(matrix)+len(matrix)-1):
if i%2==0:
res += dic[i][::-1]
else:
res += dic[i]
print(res)
return res```

Topics: less REST