[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.3 diagonal traversal 

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 [0] [0] for the first time, and the second layer starts from [1] [1]
        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 [0]*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[0]):  # 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:
                        zero_row.add(i)
                        zero_col.add(j)
            # Line clearing                 
            for r_i in zero_row:
                matrix[r_i] = [0 for _ in range(len(matrix[0]))]  
            # 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[0]):  # 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:
                        zero_col.add(j)  # 0 element ordinate
                        hasZero = True
                if hasZero:
                    matrix[i] = [0 for _ in range(len(matrix[0]))]  # 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[0]):  # 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:
                        zero_col.add(j)  # 0 element ordinate
                        hasZero = True
                if hasZero:
                    matrix[i] = [0 for _ in range(len(matrix[0]))]  # 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[0])  # 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[0])  # 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[0])):
                dic[i+j].append(matrix[i][j])
        print(dic)
        
        # Initialize output results
        res = []
        for i in range(len(matrix)+len(matrix[0])-1):
            if i%2==0:
                res += dic[i][::-1]
            else:
                res += dic[i]
            print(res)
        return res

 

Topics: less REST