Pointing to Offer - Arrays and Strings


Sword refers to Offer 04. Search in two-dimensional array

In a n * m2D array of :

  • Each row is sorted in non-decreasing order from left to right
  • Each column is sorted in non-decreasing order from top to bottom
    Please complete an efficient function, input such a two-dimensional array and an integer , and judge whether the array contains the integer .

Example:

  • The existing matrix matrix is ​​as follows:
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

Given target = 5, return true.
Given target = 20, returnfalse

限制:
0 <= n <= 1000
0 <= m <= 1000


Code

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        row=len(matrix)-1
        col=0
        while( row>=0 and col<len(matrix[0]) ):
            if(matrix[row][col]==target):
                return True
            else:
                if(matrix[row][col]>target):
                    row=row-1
                else:
                    col=col+1
        return False

Problem-solving plan + ideas

  • Tags: arraytraverse
  • From the lower left corner of the matrix, the numbers on the top are smaller than it, and the numbers on the right are larger than it, so judge whether the number exists according to this rule
    • Let the current number be curand the target number betarget
      • target < curWhen , cur is updated to the number above it
      • target > curWhen , cur is updated to the number to its right
    • Return until equal , otherwise return trueto matrix boundaryfalse
  • time complexity:O(m+n)

Algorithm steps

insert image description here

Other implementation ideas - binary search

  • Seeing order , the first reaction is binary search . The most direct way is to perform a binary search line by line.

Also, combined with the ordered nature, some situations can end early.

  • For example, if the first element of a row is greater than the target, the current row and all subsequent rows will be ignored, and false will be returned directly.
  • If the last element of a row is smaller than the target, the current row will not be considered, and the next row will be replaced.

This question does not ensure that "the first integer in each line is greater than the last integer in the previous line", so we cannot take the "twice dichotomy" approach.

  • The only solution is to traverse the rows/columns, and then divide the columns/rows into two.

In terms of time complexity, if it is m rows and n columns, yes O(mlog(n)).

import numpy as np

class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        matrix = np.array(matrix)
        row = matrix.shape[0]
        col = matrix.shape[1]

        flag =0
        for row in matrix:
            left = 0
            right = col-1
            while(left<=right):
                mid = (left+right+1)/2
                if row[mid]<target:
                    left=mid+1
                elif row[mid]>target:
                    right=mid-1
                else:
                    return True
        return False

Other Implementation Ideas_Deformed Dichotomy

The idea of ​​dichotomy is that the target value is compared with the midpoint value, and then half of the elements can be discarded.

  • This question is a matrix
  • If we find the center of the matrix, then compare with the target value to see if we can discard some elements.
如下图,中心位置是 9
[1,   4,  7, 11, 15],
[2,   5,  8, 12, 19],
[3,   6, /9/,16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]

通过中心位置, 我们可以把原矩形分成四个矩形, 左上, 右上, 左下, 右下
[1,   4,  7   [11, 15  
 2,   5,  8    12, 19  
 3,   6, /9/]  16, 22] 
 
[10, 13, 14   [17, 24
[18, 21, 23]   26, 30]

如果 target = 10,
此时中心值小于目标值,左上角矩形中所有的数都小于目标值,我们可以丢弃左上角的矩形,继续从剩下三个矩形中寻找

如果 target = 5,
此时中心值大于目标值,右下角矩形中所有的数都大于目标值,那么我们可以丢弃右下角的矩形,继续从剩下三个矩形中寻找

We have found the principle of discarding elements, and we can write code.

Here, the rectangle is represented by the coordinates of the upper left corner and the lower right corner. The following figure shows the coordinates of the divided rectangle.
insert image description here

We can write recursively,

  • For recursive exit, when there is only one element in the matrix, it is sufficient to directly judge whether the current element is the target value.

There is also the possibility of crossing the boundary when dividing.

  • For example, the original matrix has only one row, and the matrix in the lower left corner and lower right corner does not actually exist.
  • After calculating it according to the coordinate formula above, we need to judge whether it is out of bounds.


Sword Pointer Offer 05. Replace spaces

topic description

Please implement a function to sreplace each space in the string with "%20".

Example 1:

  • Input: s = "We are happy."
  • Output: "We%20are%20happy."

Limit:
0 <= s 的长度<= 10000


Code

Python simple way:

class Solution:
    def replaceSpace(self, s: str) -> str:
        return "%20".join(s.split(' '))

Python method:

class Solution {
    
    
public:
    string replaceSpace(string s) {
    
    
        for(int i = 0; i < s.length(); i++){
    
    
            if(s.find(" ") == i){
    
    
                s.erase(i, 1);
                s.insert(i, "%20");
            }
        }
        return s;
    }
};

class Solution(object):
    def replaceSpace(self, s):
        """
        :type s: str
        :rtype: str
        """
        s1=""
        for c in s:
            if c == ' ': 
                s1 += '%20'
            else:
                s1 +=c
        return s1

C++:

class Solution {
    
    
public:
    string replaceSpace(string s) {
    
    
        for(int i = 0; i < s.length(); i++){
    
    
            if(s.find(" ") == i){
    
     # 查找到空格所在的位置
                s.erase(i, 1); # 先清除空格所占的一个字符
                s.insert(i, "%20"); # 在该位置插入%20
            }
        }
        return s;
    }
};

Problem-solving plan + ideas

  • label: string
  • The easiest solution is naturally to use library functions directly ! Of course, the title definitely doesn't want us to do this!
  • Add a new string, traverse the original string , during the traversal process,
    • If it is not a space , the original characters are directly spliced ​​into the new string
    • If a space is encountered, it will %20be spliced ​​into a new string
  • Time complexity: O(n), space complexity:O(n)

Algorithm steps

insert image description here

Method summary

Method 1: Traversing and adding
In languages ​​such as Python and Java, strings are designed as "immutable" types, that is, a certain character of a string cannot be directly modified, and a new string needs to be created to implement it.

Algorithm flow:

  1. Initialize a list (Python) / StringBuilder (Java), denoted as res;
  2. Iterate over seach character in the list c:
    • When cis a space: resadd a string to the back "%20";
    • When cis not a space: resadd characters after c;
  3. Convert the list resto a string and return it.

Complexity analysis:

  • Time complexity O(N): O(N) is used for traversal, and O(1) is used for each round of adding (modifying) character operations;
  • Space complexity O(N): Python's new list and Java's new StringBuilder both use additional space of linear size.

insert image description here

Method 2: In-place modification
In the C++ language, string is designed as a "variable" type (reference), so in-place modification can be realized without creating a new string.

  • Since the space needs to be replaced with "%20", the total number of characters in the string increases, so the length of the original string s needs to be extended,
  • The calculation formula is: new string length = original string length + 2 * number of spaces,
  • An example is shown in the figure below.
    insert image description here
    Algorithm flow:
  1. Initialization: the number of spaces count, the length of the string s len;
  2. Count the number of blanks: traverse s, if blanks are encountered count++;
  3. Modify the length of s: the string length after adding "%20" should be len + 2 * count;
  4. Reverse order traversal modification : i point to the tail element of the original string, jpoint to the tail element of the new string;
    • Jump out when i = j (meaning there is no space on the left, no need to continue traversing);
    • When s[i] is not a space: execute s[j] = s[i];
    • When s[i] is a space: modify [j-2, j]the elements of the closed interval of the string to "%20"; since 3 elements have been modified, it is necessary j -= 2;
  5. Return value: the modified string s ;

insert image description here
Complexity analysis:

  • Time complexity O(N): Both traversal statistics and traversal modification use O(N) time.
  • Space complexity O(1): Since the length of s is extended in-place, O(1) extra space is used.
class Solution {
    
    
public:
    string replaceSpace(string s) {
    
    
        int count = 0, len = s.size();
        // 统计空格数量
        for (char c : s) {
    
    
            if (c == ' ') count++;
        }
        // 修改 s 长度
        s.resize(len + 2 * count);
        // 倒序遍历修改
        for(int i = len - 1, j = s.size() - 1; i < j; i--, j--) {
    
    
            if (s[i] != ' ')
                s[j] = s[i];
            else {
    
    
                s[j - 2] = '%';
                s[j - 1] = '2';
                s[j] = '0';
                j -= 2;
            }
        }
        return s;
    }
};


Sword refers to Offer 11. The minimum number of rotation array - solution

topic description

Moving the first few elements of an array to the end of the array is called the rotation of the array.

  • Input a rotation of an array sorted in ascending order, output the smallest element of the rotated array.
  • For example, the array [3,4,5,1,2] is a rotation of [1,2,3,4,5] with a minimum value of 1.
  • Note that [a[0], a[1], a[2], ..., a[n-1]]the result of rotating an array once is an array [a[n-1], a[0], a[1], a[2], ..., a[n-2]] .

Example 1:

  • Input: [3,4,5,1,2]
  • Output: 1

Example 2:

  • Input: [2,2,2,0,1]
  • output: 0

hint:

  • n == numbers.length
  • 1 <= n <= 5000
  • -5000 <= numbers[i] <= 5000
  • numbers turns out to be an ascending sorted array with 1 to n rotations

Code

  • python traversal
class Solution:
    def minArray(self, numbers: List[int]) -> int:
            j=numbers[0]
            for i in range(len(numbers)):
                if j<=numbers[i]:
                    j=j
                else:
                    j=numbers[i]
            return j

  • dichotomy
class Solution:
    def findMin(self, nums: List[int]) -> int:
        left, right = 0, len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] > nums[right]: left = mid + 1
            elif nums[mid] < nums[right]: right = mid
            else: right = right - 1 # key
        return nums[left]

Problem-solving plan + ideas

  • Tags: binary search
  • the whole idea:
    • First of all, the array is a rotation of an ordered array . From this condition, we can see that the array has a regular size .
    • Binary search can be used to quickly find the result by using the existing rules
  • Time complexity: O(logn), space complexity: O(1)

Algorithm steps

  1. Initialize subscripts leftandright
  2. Every time the middle subscript is calculated mid = (right + left) / 2, the division here is a rounding operation , and no decimals can appear
  • numbers[mid] < numbers[right]When , it means that the minimum value is [left, mid]​in the interval, then let right = midit be used for the next round of calculation
  • Whennumbers[mid] > numbers[right]​ , it means that the minimum value is in [mid, right]​the interval, then let left = mid + 1it be used for the next round of calculation
  • [Note] When numbers[mid] == numbers[right]​, it is impossible to judge which interval the minimum value is in. At this time, let’s right--narrow down the interval and judge in the next round

Why right-- narrows down , not left++ ?

  • Because the array is in ascending order, the smallest value must be closer to the left, not the right
  • For example, when there is a situation like [1,2,2,2,2], left = 0, right = 4, mid = 2, the value satisfies numbers[mid] == numbers[right]this condition, if left++, the minimum value cannot be found

insert image description here

Algorithm ideas (two points)

  • The rotation sorted array numscan be split into two sorted arrays nums1, nums2, and any element of nums1 >= any element of nums2; therefore, consider the dichotomy to find the dividing point nums[i] of the two arrays (that is, the second array first element of the ).
  • Set the left and right pointers at both ends of the nums array, and mid is the midpoint of each bisection:
    • nums[mid] > nums[right]When , mid must be in the first sorted array, and iii must satisfy mid < i <= right, so execute left = mid + 1;
    • At that nums[mid] < nums[right]time , mid must be in the second sorted array, and iii must satisfy left < i <= mid, so execute right = mid;
    • At that nums[mid] == nums[right]time , it was the difficulty of comparing this question with 153 questions (the reason is that the elements of the array in this question can be repeated, and it is difficult to judge the dividing point iii pointer interval);
      • For example [1,0,1,1,1], when left = 0, right = 4, mid = 2, it is impossible to determine which sorted array midmidmid is in.
      • We right = right - 1solve this problem by proving that:
        1. This operation will not make the array out of bounds: because the iteration condition guarantees right > left >= 0;
        2. This operation does not make the minimum value lost: assuming nums[right] is the minimum value, there are two cases:
          • If nums[right] is the only minimum value: it is impossible to satisfy the judgment condition nums[mid] == nums[right], because mid < right (left != right and mid = (left + right) // 2 down Rounding);
          • If nums[right] is not the only minimum value, since mid < right and nums[mid] == nums[right], that is, there is still a minimum value in the [left,right−1] interval, so the minimum value will not be lost.

insert image description here

The above is a theoretical analysis, which can be substituted into the following arrays to assist thinking:
[1,2,3]
[1,1,0,1]
[1,0,1,1,1]
[1,1,1,1]

  • Time complexity O(logN), degenerates to O(N) in special cases (eg [1,1,1,1]).



Jianzhi Offer 17. Print the number of n digits from 1 to the maximum

topic description

Input the number n, and print out the decimal numbers from 1 to the largest n in order.

  • For example, if you input 3, it will print out 1, 2, 3 up to the maximum 3-digit number 999.

Example 1:

  • enter:n = 1
  • output:[1,2,3,4,5,6,7,8,9]

illustrate:

  • return a list of integers instead of printing
  • n is a positive integer

Solution

Idea 1

Label: Array
Overall idea:

  1. First find the range of numbers to be printed,
  2. 然后再从 1 开始打印到最大的数字
    时间复杂度:O( 1 0 n 10 ^n 10n ),空间复杂度:O( 1 0 n 10 ^n 10n )

算法流程

  1. 初始化 sum = 1
  2. 循环遍历乘 10 让 sum 变为边界值
  3. 新建 res 数组,大小为 sum-1
  4. 从 1 开始打印,直到 sum-1 为止
class Solution(object):
    def printNumbers(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        max = 10**(n)
        list=[]
        for i in range(1,max):
            list.append(i)
        
        return list

思路 2

标签:字符串
整体思路:

  • 原题的题意其实是希望考察大数计算,因为 int 数组有可能会溢出,所以用字符串处理可以保证一定不会溢出
  • 但是呢,由于返回值规定是 int 数组,所以其实从返回值上来看,是一定不会溢出的,比较矛盾。
  • 所以给出个思路 2,学习下如何用字符串处理大数即可,不用特别纠结溢出这件事情
    时间复杂度:O( 1 0 n 10 ^n 10n ),空间复杂度:O( 1 0 n 10 ^n 10n )

算法流程

  1. 初始化字符串 str,另其初始值n-1 个 "0"
  2. 递增 str,使用字符去递增
    • 递增过程中判断是否存在进位,存在进位进位处 +1
    • 直到达到最大值为止,结束循环
  3. After each value is obtained, traverse the redundant "0" in front and remove the redundant "0"
    • Convert to int and store in the result array

insert image description here


[ Large number problem! 】In fact, the main test point of this question is the printing when the large number crosses the boundary .
Three issues need to be addressed:

  1. Variable types representing large numbers :

    • Whether it is short / int / long... any variable type, the value range of the number is limited .
    • Therefore, the representation of large numbers should be of type String .
  2. Generate a string set of numbers :

    • When using intthe type, the next number can be +1generated each round by , which cannot be applied to the String type .
    • Moreover, the carry operation efficiency of String type numbers is low. For example, "9999" to "10000" needs to be judged from ones to thousands, and carried 4 times.
    • It can be seen from observation that the generated list is actually a full arrangementn of bits 000 - 999 , so the carry operation can be avoided, and the String list of numbers can be generated recursively .
  3. Recursively generate full permutations :

    • Based on the idea of ​​divide-and-conquer algorithm, first fix the high bit, then recurse to the low bit , when the ones bit has been fixed, add a string of numbers.
    • For example, n=2when (the number range is 1−991 - 991−99 ), the tens digit is fixed to 000 - 999 , and the recursion is started in sequence, the ones digit is fixed to 000 - 999 , the recursion is terminated and a digital string is added.

insert image description here
According to the above method, the full arrangement code can be initially written:

class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n: # 终止条件:已固定完所有位
                res.append(''.join(num)) # 拼接 num 并添加至 res 尾部
                return
            for i in range(10): # 遍历 0 - 9
                num[x] = str(i) # 固定第 x 位为 i
                dfs(x + 1) # 开启固定第 x + 1 位
        
        num = ['0'] * n # 起始数字定义为 n 个 0 组成的字符列表
        res = [] # 数字字符串列表
        dfs(0) # 开启全排列递归
        return ','.join(res)  # 拼接所有数字字符串,使用逗号隔开,并返回

In this method, the strings of numbers are separated by commas to form a long string .
The returned digit set string looks like this:

输入:n = 1
输出:"0,1,2,3,4,5,6,7,8,9"

输入:n = 2
输出:"00,01,02,...,10,11,12,...,97,98,99"

输入:n = 3
输出:"000,001,002,...,100,101,102,...,997,998,999"

Observation shows that the current generation method still has the following problems:

  1. Such as 00,01,02,⋯,⋯ should be displayed as 0,1,2,⋯
    • That is, the redundant 0 in the high position should be deleted ;
  2. This method 0generates starting from , and the question request list 1starts from ;

The solutions to the above two problems are as follows:

  1. Remove extra 0's from high bits:
  • String left boundary definition:

    • Declaring the variable startspecifies the left boundary of the stringnum[start:] to ensure that there are no high-order redundant 0s in the added numeric string .
    • For example, when n=2, start=1 when 1−9, and start=0 when 10−99.
  • The change law of the left boundary start :

    • It can be seen from observation that when all the digits of the output number are 9, the next digit needs to carry 1 to the higher digit, and at this time, the left boundary start needs to be reduced by 1 (that is, the extra 0 in the upper digit should be reduced by one).
    • For example, when n=3 (number range 1−999), the left boundary start needs to be reduced by 1: "009" is carried to "010", and "099" is carried to "100".
    • Assuming that the number of 999 in each digit is nine, the judgment condition that all digits are 9 can be expressed by the following formula:
      n − start = ninen−start=ninenstart=nine
  • Statistical ninemethod:

    • fixed xxWhen x bit, when i = 9 i=9i=9戙执行nine = nine + 1 nine=nine+1nine=nine+1
    • And restore nine = nine − 1 nine=nine−1 before backtrackingnine=nine1
  1. Lists start at 1:
  • On the basis of the above method, judge whether it is "0" before adding the digital string, and skip it if it is "0" .

insert image description here
Complexity analysis:

  • Time complexity O ( 1 0 n ) O(10^n)O(10n ): The number of permutations generated recursively is1 0 n 10^n10n
  • Space complexity O ( 1 0 n ) O(10^n)O(10n ): The length of the result list res is1 0 n − 1 10^n - 110n1 , the length interval of each digital string is1 , 2 , . . . , n 1,2,...,n1,2,...,n , so takesO ( 1 0 n ) O(10^n)O(10n )of additional space.

To correctly represent large numbers, the return value of the following code is a long string concatenated from a set of numeric strings .

class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(s)
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10):
                if i == 9: self.nine += 1
                num[x] = str(i)
                dfs(x + 1)
            self.nine -= 1
        
        num, res = ['0'] * n, []
        self.nine = 0
        self.start = n - 1
        dfs(0)
        return ','.join(res)

This question requires the output of an array of int type.

  • To pass, convert the numeric string s to an int before adding it .

The code looks like this:

class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(int(s))
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10):
                if i == 9: self.nine += 1
                num[x] = str(i)
                dfs(x + 1)
            self.nine -= 1
        
        num, res = ['0'] * n, []
        self.nine = 0
        self.start = n - 1
        dfs(0)
        return res


[Others] Concise version of full permutation solution

In the case of a large number, even if the long type cannot carry it, it must be stored in a string .

  • For this question, it is actually the full arrangement of the number 09, and the full arrangement of n digits 0~9. It should be noted that there should be no 0 at the beginning of the number.

Simply mention the full arrangement , for example, the full arrangement of the numbers 1, 2, and 3 is:

123, 132, 213, 231, 312, 321

In order to be able to pass the test, finally change the string form to int form, in fact, it should return a string array

The following are the specific steps

  1. In order to avoid 0 0 at the beginning of the number0 ,firstfix the first digit first,firstthe value range is1 9 1~91 9
  2. Use the numberdigit of digits to represent the number to be generated , this question should start from 1 11 digit is generated untilnnFor n digits,the first digit is generated for each digit, so there is adouble for loop
  3. After generating the first digit, enter recursively to generate the remaining digit - 1digits, from 0 to 9 0 to 9Value from 0 to 9
  4. The recursion termination conditiondigit is that the number of digits has been generated , that is index == digit, the number num at this time is converted into an int and added to the result res
class Solution:
    def printNumbers(self, n: int) -> List[int]:
        def dfs(index, num, digit):
            if index == digit:
                res.append(int(''.join(num)))
                return
            for i in range(10):
                num.append(str(i))
                dfs(index + 1, num, digit)
                num.pop()

        res = []
        for digit in range(1, n + 1):
            for first in range(1, 10):
                num = [str(first)]
                dfs(1, num, digit)
        
        return res




Jianzhi Offer 21. Adjust the order of the array so that the odd number is in front of the even number

topic description

Input an array of integers , implement a function to adjust the order of the numbers in the array ,

  • so that all odd numbers are in the first half of the array ,
  • All even numbers are in the second half of the array .

Example:

  • enter:nums = [1,2,3,4]
  • output:[1,3,2,4]
    • NOTE: [3,1,2,4] Also one of the correct answers.

hint:

  • 1 <= nums.length <= 50000
  • 1 <= nums[i] <= 10000

Solution

train of thought

  • Tags: double pointer
  • the whole idea:
    • First specify the frontstart and back pointers ,end
    • Then the front pointer locates the even number , and the rear pointer locates the odd number ,
    • After positioning, swap the two values ​​until the array traversal is complete
  • Time complexity: O(n), space complexity:O(1)

Algorithm process

  1. Initialize the front pointer start = 0, the back pointerend = nums.length - 1
  2. At that start < endtime, it means that the array has not been traversed yet, then continue to exchange odd and even numbers
  3. When nums[start]is an odd number, then start++, until a non-odd subscript is found
  4. When nums[end]is an even number, then end--, until a non-even subscript is found
  5. Exchange nums[start]and nums[end], continue to the next round of exchange
  6. return nums, which is the result of the exchange

insert image description here

  • Ordinary traversal
class Solution(object):
    def exchange(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        List1 = []
        List2 = []
        for i in nums:
            if (i % 2) == 0:
                List1.append(i)
            else:
                List2.append(i)

        List2.extend(List1)

        return List2
  • double pointer method
class Solution(object):
    def exchange(self, nums):
        start = 0
        end = len(nums)-1
        
        while(start < end):
            while(nums[start] %2 != 0) and start < end:
                start+=1
            while(nums[end]%2 ==0)and start < end:
                end-=1
            tmp = nums[start]
            nums[start] = nums[end]
            nums[end] = tmp
            start+=1
            end-=1
        
        return nums

Problem-solving ideas (double pointer):

Consider defining double pointers iii, jjj to sort the left and right ends of the array, and execute it in a loop:

  1. pointer iii looks foreven numbersfrom left to right;
  2. pointer jjj looks forodd numbersfrom right to left;
  3. will even nums [ i ] nums[i]n u m s [ i ] and oddnums [ j ] nums[j]n u m s [ j ] exchange.

===> always guarantees: pointer iiThe left side of i is odd, the pointerjjThe right side of j is an even number.

insert image description here

Algorithm flow:

  1. Initialization: i , j are double pointers, pointing to the left and right ends of the array nums respectively;

  2. Cyclic exchange: when i = ji=ji=Jump out at j ;

    • When the pointer i encounters an odd number , execute i = i + 1 i=i+1i=i+1 skip untilan even number;
    • When the pointer j encounters an even number , execute j = j − 1 j=j−1j=j1 skip untilan odd number;
    • swap nums[i]and nums[j]values;
  3. Return Value: Returns the modified nums array.

insert image description here
Complexity analysis:

  • Time complexity O ( N ) O(N)O(N) N N N is the length of the array nums, double pointersi, ji, ji,j collectively iterates over the entire array.
  • Space complexity O ( 1 ) O(1)O ( 1 ) : double pointersi, ji, ji,j uses constant size extra space

code:

x & 1 Bit operations are equivalent to x % 2 remainder operations , that is, both can be used to judge the parity of numbers .

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        i, j = 0, len(nums) - 1
        while i < j:
            while i < j and nums[i] & 1 == 1: i += 1
            while i < j and nums[j] & 1 == 0: j -= 1
            nums[i], nums[j] = nums[j], nums[i]
        return nums

tips:

  • Basics of Quick Sort
    • That is, the quick sort will put the ones smaller than the base point in front , and the ones larger than the base point in the back

Other methods - fast and slow double pointer

  • Define the fast and slow double pointers fast and low , with fast in front and low in the back.
  • The role of fast is to search for the odd position forward , and the role of low is to point to the position where the next odd number should be stored
  • f a s t fast f a s t moves forward and when itfinds an odd number, it is combinedwith nums[low] nums[low]n u m s [ l o w ] exchange, at this timelow lowl o w Move forward one position.
  • Repeat the above operations until fast points to the end of the array.

insert image description here

class Solution {
    
    
public:
    vector<int> exchange(vector<int>& nums) {
    
    
        int low = 0, fast = 0;
        while (fast < nums.size()) {
    
    
            if (nums[fast] & 1) {
    
    
                swap(nums[low], nums[fast]);
                low ++;
            }
            fast ++;
        }
        return nums;
    }
};




Sword refers to Offer 29. Print matrix clockwise

topic description

Enter a matrix and print each number in clockwise order from the outside to the inside .

Example 1:
insert image description here

  • Input: matrix = [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] , [ 7 , 8 , 9 ] ] matrix = [[1,2,3],[4,5,6],[7 ,8,9]]matrix=[[1,2,3],[4,5,6],[7,8,9]]
  • Output: [ 1 , 2 , 3 , 6 , 9 , 8 , 7 , 4 , 5 ] [1,2,3,6,9,8,7,4,5][1,2,3,6,9,8,7,4,5]

Example 2:
insert image description here

  • Input: matrix = [ [ 1 , 2 , 3 , 4 ] , [ 5 , 6 , 7 , 8 ] , [ 9 , 10 , 11 , 12 ] ] matrix = [[1,2,3,4],[5 ,6,7,8],[9,10,11,12]]matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]
  • Output: [ 1 , 2 , 3 , 4 , 8 , 12 , 11 , 10 , 9 , 5 , 6 , 7 ] [1,2,3,4,8,12,11,10,9,5,6, 7][1,2,3,4,8,12,11,10,9,5,6,7]

limit:

  • 0 < = m a t r i x . l e n g t h < = 100 0 <= matrix.length <= 100 0<=matrix.length<=100
  • 0 < = m a t r i x [ i ] . l e n g t h < = 100 0 <= matrix[i].length <= 100 0<=matrix[i].length<=100

Solution

train of thought

  • Tags: 2D array
  • the whole idea:
    • Loop through the entire array, and nest four more loops in the loop ,
    • They are from left to right, from top to bottom, from right to left, and from bottom to top .
    • Complete the entire array traversal according to the meaning of the title, and control the boundaries
  • m m m is the number of rows,nnn is the number of columns, time complexity:O ( mn ) O(mn)O ( mn ) , space complexity:O ( 1 ) O(1)O(1)

Algorithm process

  1. matrix matrix in the titlemat r i x maybe empty,justreturn an empty array
  2. Initialize boundaries left, right, top, bottom left, right, top, bottoml e f t , r i g h t , t o p , b o tt o m four values, initializethe result array res resres and arraysubscript xxx
  3. According to the direction of traversal , take out the numbers and put them into the result array
    • From left to right : After the traversal is complete ++top, if top > bottom​ top > bottomtop>b o tt o m ​, reaching the end of the boundary cycle
    • From top to bottom : After the traversal is complete --right, if left > right ​ left > rightleft>r i g h t ​, reaching the end of the boundary cycle
    • From right to left : After the traversal is complete --bottom, if top > bottom​ top > bottomtop>b o tt o m ​, reaching the end of the boundary cycle
    • From bottom to top : After the traversal is complete ++left, if left > right ​ left > rightleft>r i g h t ​, reaching the end of the boundary cycle

Code

  • Traversal strategy: traverse to the end

class Solution(object):
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        if len(matrix) ==0 : return None
        # if not matrix or not matrix[0]:
        #     return list()

        right = len(matrix[0])-1
        bottom = len(matrix)-1
        top =0
        left=0
        res = []
        maxSize = (right+1)*(bottom+1)
        
        while(maxSize>0):
            for i in range(left,right+1):
                if maxSize>0:
                    res.append(matrix[top][i])
                    maxSize-=1
            top+=1
            for j in range(top,bottom+1):
                if maxSize>0:
                    res.append(matrix[j][right])
                    maxSize-=1
            right-=1
            for k in range(right,left-1,-1):
                if maxSize>0:
                    res.append(matrix[bottom][k])
                    maxSize-=1
            bottom-=1
            for l in range(bottom,top-1,-1):
                if maxSize>0:
                    res.append(matrix[l][left])
                    maxSize-=1
            left+=1

        return res

Method analysis - simulation by layer

  • The matrix can be seen as several layers
    • First, output the outermost element
    • Second, output the elements of the second outer layer
    • Until, the innermost element is output .

Define the kkth of the matrixThe k layer isthe distance to the nearest boundaryiskkall verticesof k .

  • For example, the outermost elements of the matrix in the figure below are all 1 1Level 1 ,the second outerelement is the2nd 22 layers, the rest of the elements are the 3rd33 floors.

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]
 

For each level, iterate over all elements in clockwise order starting from the top left.

  • Assuming that the upper left corner of the current layer is located (top,left)and the lower right corner is located (bottom,right), the elements of the current layer are traversed in the following order.
    insert image description here
  1. Traverse the top elements from left to right , from (top, left) to (top, right).
  2. Traverse the elements on the right from top to bottom, followed by (top+1,right) to (bottom,right).
  3. 如果 l e f t < r i g h t 且 t o p < b o t t o m left<right 且 top<bottom left<r i g h t and t o p<b o tt o m , thentraverse the lower elements from right to left
    • (bottom,right−1) to (bottom,left+1)
    • And traverse the elements on the left from bottom to top , in order
    • (bottom,left) to (top+1,left)。

After traversing the elements of the current layer,

  • Put left and top left and topl e f t and to p are increased by1,
  • Change right and bottom right and bottomr i g h t and b o tt o m are reduced by1,
  • Enter the next layer to continue traversing,
  • until all elements are traversed.
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

Complexity Analysis

  • Time complexity: O(mn), where m and n are the number of rows and columns of the input matrix, respectively. Each element in the matrix is ​​accessed once.
  • Space complexity: O(1). Space complexity is constant except for the output array.



Guess you like

Origin blog.csdn.net/weixin_43338969/article/details/129336823