Algorithm review (ten): return to the array and hash table of the basic data structure

1. Write on the front

At the beginning of this article, I am preparing to return to the review of the basic data structure, mainly including arrays, hash tables, linked lists, strings, stacks and queues. The topics here are compared to those on the previous algorithm level. Think about it a little bit better, the difficulty will decrease, and there are some very key ideas, you can usually solve the problem after you write silently. Such as double pointer method, sliding window, monotonous stack and so on. This article reviews arrays and hash tables. In fact, I feel that hash tables are an auxiliary tool to solve array problems. Common methods and ideas on arrays are: rebuilding arrays, double pointers, sliding windows, commonly used tools, dictionaries, and collections.

About Array, we need to know the knowledge points:

  1. Array common operations: add, delete, modify, check and move elements
  2. Array access to the array time complexity O(1), insert and delete time complexity O(n), continuous memory
  3. The more classic topics are generally to examine the combination, exchange, addition, deletion, etc. of elements, and the traversal of arrays
  4. Some ideas involved here:
    • The two pointers are traversed one after the other, this can be reversed for the array
    • The two pointers are traversed from the front to the back, you can filter the elements that meet specific conditions
    • Rebuild the array idea
    • Sliding window
    • Space for time
    • Hash storage
    • Reverse traversal thought
  5. The advantages and disadvantages of arrays (to master a data structure, you must know how to analyze its advantages and disadvantages)
    • The advantage of the array is that it is very simple to construct and can query an element based on the index of the array in O(1) time
    • The disadvantages of arrays are: a continuous space must be allocated during construction, the entire array needs to be traversed when querying whether an element exists, and it takes O(n) time (where n is the number of elements), deleting and adding an element Time, it also takes O(n) time

Therefore, when you are considering whether you should use an array to assist your algorithm, please be sure to consider its advantages and disadvantages, and see if its disadvantages will hinder your algorithm complexity and space complexity.

2. Question ideas and code sorting

2.1 The idea of ​​rebuilding an array

  • LeetCode283: Move zero : The idea of ​​rebuilding the array, treating the current array as an empty array, and then using a pointer to non_zero_indexalways point to the end of the new array (the initial value is 0). Then traverse the current array, if it is not 0, add it to the empty array, and non_zero_indexmove backward at the same time , always pointing to the end of the new array. After this traversal is complete, all the non_zero_indexfollowing will become 0. code show as below:
    Insert picture description here
  • LeetCode27: Remove elements : The idea of ​​rebuilding the array is still the idea of ​​rebuilding the array, treating the current array as an empty array, and then using a pointer to non_target_indexalways point to the end of the new array (initially 0). Then traverse the current array, if it is not the target, add it to the empty array, and non_target_indexmove backward at the same time , always pointing to the end of the new array. After this traversal is complete, just return non_target_index.

    Insert picture description here
  • LeetCode26: Delete duplicates in sorted array : The idea of ​​rebuilding the array is to treat the current array as an empty array, and then use a pointer to non_repeat_indexalways point to the end of the new array (the initial value is 1). Then traverse the current array (starting from 1), if it is not equal to the previous number, add it to the empty array, and non_repeat_indexmove backward at the same time , always pointing to the end of the new array. After this traversal is complete, just return non_repeat_index.

    Insert picture description here

The idea of ​​creating a new array on the original array is very important. It is very suitable for the problem of deleting unqualified elements from the sequence table, such as deleting duplicate elements and ensuring the position remains unchanged, deleting negative numbers, deleting 0 elements, and raising one level higher. What is practical is reverse thinking , isn't it letting delete 0? I don’t look for 0 directly, and then delete it. Instead, I look for something other than 0 to keep. Don’t I delete duplicates? Do not find the duplicates and delete them, but find the non-duplicated ones and keep them. Experience it well.

2.2 Double pointer

  • LeetCode11: The container that holds the most water : This violent word is a two-layer for loop. Find the area enclosed by two pillars, which is obviously too inefficient. So here is the double pointer solution. First of all, you have to know how to calculate the area enclosed by the two pillars:, The min(柱子高) * (两根柱子之间的距离)double pointer method is one left pointer and one right pointer, walking from two sides to the middle. The core of this problem is to determine the size of the area. The shortest of the two pillars (barrel effect) . After the area of ​​the pillars pointed to by the two pointers is calculated, compare their lengths and move the pointer on the shorter side (if it is i, move it to the right. j refers to shift left). why? Because the short side cannot be optimized anymore, if you don’t move the short one at this time, and then move the taller one, the distance between the two remaining pillars gets smaller and smaller, and the area becomes smaller. Only the side with the short movement, although the distance between the two is shorter, it may be able to be retrieved from the height. code show as below:

    Insert picture description here

  • LeetCode15: Sum of three numbers : The double pointer in this question is very clever. First sort the array from small to large , then set the pointer k to start traversing the elements from the beginning. For each traversal, set the i and j pointers to point to the beginning and the end of the remaining elements behind k , and then judge if the three pointers point to the elements Equal to 0, save the result. Otherwise, if the sum of the three is less than 0, then i moves backward. Because the element pointed to by i is small, the total sum is small (again, the barrel effect is constructed). If the sum of the three is greater than 0, j moves to the left, because the element pointed to by j is too large and the total sum is large. In this way, when i and j meet, all combinations of current k have been traversed, move k backward, and repeat the above steps. But the thing to pay attention to in this process is to avoid repeating elements . How to avoid repetition? Because we sort the array from small to large first, if we find that the element pointed to by the current k is equal to the previous k-1, we skip over, indicating that we have already found this situation. So the key points of this question are sorted from small to large, fix one of the extremes, and look at the other two . code show as below:

    Insert picture description here

  • LeetCode18: The sum of four numbers : Compared with the sum of three digits, the sum of four digits will add a layer of loop here, let m traverse each number, for each number traversed by m, k traverse the current m All the following numbers, then the two pointers i and j point to the beginning and the end of the array after k, and then judge according to the above logic. If the four numbers add up to be greater than target, i move backward and less than target, j move forward and equal target, save the result, move i backward and move j forward. But there must also be de-duplication operations, and de-duplication operations need to be de-duplicated wherever each pointer is required . The final code is as follows:

    Insert picture description here
    In the sum of three numbers and the sum of four numbers, sorting is very important.

  • LeetCode88: Combine two ordered arrays : This question can use two pointers to traverse the array from back to front . This is the difference between an array and a linked list. The linked list does not know the last tail, but the array knows that from back to front, if Whichever number is larger, put it at the end. At this time, if nums2 has a surplus, insert it directly to the front of nums1. If there is no surplus, it means that it has been completely inserted into nums1. code show as below:

Insert picture description here

2.3 Small fresh

  • Rotating the array : A clever way of thinking about this question is to get it in the order of three times reverse order. First, reverse the order of the overall elements, and then add 1 11 tokkThe elements of k are in reverse order, and finallykkk~ l e n ( n u m s ) len(nums) The elements of l e n ( n u m s ) can be in reverse order. But there is a small trap in this question is that ifkkk is greater than the length of the array, and the remainder needs to be taken first.

    Insert picture description here

  • Add one : Reverse the order first, add 1 to the first digit, then consider the operation of the backward carry, and then reverse it.

    Insert picture description here

  • LeetCode54: Spiral Matrix : This is a simulation process of array traversal. It does not involve any algorithm, but it examines the control ability of the code. Spiral traverses the matrix inwardly. Just like the trajectory, the tetralogy is also considered here, which are the starting position, the moving direction, the boundary and the ending conditions . Take this topic to analyze:

    1. Starting position: The starting point of this traversal is the upper left corner of the matrix, which is the position (0,0)
    2. Moving direction: Every lap is first to the right to the end, then down to the end, then to the left to the end, and then up to the end. So for each lap, the direction is the same, that is right -> down -> left -> up.
    3. Boundary: This is the core of this question, because every circle, this boundary will change. The rule is that after the current row (column) traversal is over, the boundary of this row (column) needs to be moved one square inward. , So when this question is going, it is necessary to control the boundary at all times. This is the key to the solution
    4. End condition: The end condition of spiral traversal is that all positions are traversed.

    Look at the code:
    Insert picture description here

  • LeetCode59: Spiral Matrix II : This topic is basically the same as the above one, just simply change the code, because the above problem is given a matrix, let the spiral traverse the output value, and this topic is spiral traversal to build the matrix , So there will be some differences in storing the results. code show as below:
    Insert picture description here

  • LeetCode885: Spiral Matrix III : This topic is quite different from the two above. The first one is that the starting point is not fixed, and the second one is the boundary, if it is determined by walking steps. Take the above four steps to analyze:

    1. Starting point: This is the title (r0, c0) will be given

    2. The moving direction is still right -> down -> left -> up

    3. Boundary conditions, this boundary is dynamically changed and can be divided according to the circle

      1. On the first lap, I walked 1 step to the right from (r0,c0), 1 step down, 2 steps to the left, 2 steps up, to (r1,c1)
      2. In the second circle, we walked 3 steps to the right from (r1,c1), 3 steps down, 4 steps to the left, 4 steps up, to (r2,c2)
      3. On the third lap, walk 5 steps to the right from (r2,c2), 5 steps down, 6 steps to the left, 6 steps up, to (r3,c3)

      From this we can find the rule that in each cycle, the number of steps going to the right and down is the same, and the number of steps going to the left and up is the same, and one step more than going to the right . So we need to define a step to control boundary changes.

    4. Termination condition: here can be controlled by the number of points passed

    code show as below:

    Insert picture description here

2.4 Sliding window

  • LeetCode209: The smallest length sub-array : I learned a sliding window technique. This thing is still a double pointer operation in the vernacular, but this time the double pointer is maintaining a window moving, so the sliding window sounds better some. And in solving some array and string problems, the sliding window is also a very useful tool, so how to use this sliding window? First of all, there are several questions to consider ① When moving the rightenlarged window, how should it be updated? ② Under what conditions, the window should pause to expand and start to move to leftshrink the window? ③How to leftupdate when moving the reduced window? ④Should the result we want be updated when the window is enlarged or when the window is reduced?

    With this topic, I carefully dealt with these problems, and I found that the sliding window is similar to the dichotomy, and it is also a kind of framework. As long as these problems are solved, the writing of the code framework is basically fixed .

    1. When moving the rightenlarged window, how should it be updated? For this question, when moving right to add a new element, win_sumyou need to accumulate the new element.
    2. Under what conditions, the window should pause to expand and start moving to leftshrink the window? When the elements in the window are greater than or equal to the target , try to shrink the window.
    3. leftWhat should I update when moving the reduced window? win_sumTo subtract the removed elements.
    4. Should the result we want be updated when the window is expanded or when the window is reduced? Since we want the smallest number here, we should update the result when shrinking the window, that is, in leftthe process of moving to the left.

    The code is as follows: the
    Insert picture description here
    following string topic, you will encounter this tool, and then summarize it there.

2.5 Hash table

In python, the commonly used hash tables are dictionaries and collections set(). These two are also very useful tools. In python, collections also provide defaultdict, Orderdict, etc. Let's look at a few array problems that can achieve the purpose of space-to-time by establishing dictionary mapping.

  • LeetCode242: Valid letter dyslexia: For this question, you can use a dictionary to count the number of each letter in the first string, and then traverse the second string, and the characters that appear are offset. When the number of characters in the dictionary appears If the number is negative, it means that there is a character that has not appeared in the previous string, and then return False. code show as below:

Insert picture description here

  • LeetCode349: Intersection of two arrays : This problem can use set collection, because duplicate elements can be removed here. The idea is to traverse from the short list. For each element, if it appears in another list, add it to As a result, the result is stored here as a collection, and finally it can be switched back to the list.
    Insert picture description here

  • LeetCode202: Happy Number : The infinite loop in this question is very important. If there is a repeated sum, it will loop indefinitely. So the key to this question is to see if there is a repeated sum, and to judge the repetition, the first thing that comes to mind should be It is a set collection. The idea is to first calculate the sum of the squares of the number of positions of n, and return True if it is equal to 1, otherwise, determine whether it has appeared before, and if it does, return False. Otherwise, join the set, then determine the sum of squares of the sum of squares, and repeat. code show as below:
    Insert picture description here

  • LeetCode1: The sum of two numbers : With map, this problem can be completed with O(n) time complexity. Here you first need to create a 值:索引mapping dictionary, and then traverse the array from the beginning . For the current number, check whether the target-the number is in the dictionary. If so, return the index of the number and the value corresponding to the dictionary key. Otherwise, save the number in the dictionary.

    Insert picture description here

  • LeetCode454: Addition of four numbers II : This is not the same as the sum of four numbers. The elements of this are placed in each independent array, and there is no need to consider whether to remove duplicates, as long as four elements are found The sum is equal to 0. Then this problem can be converted into the sum of two numbers, because A+B+C+D = 0, in fact, it can be seen as (A+B) + (C+D) = 0, in this way, traverse A, B, make a dictionary mapping {A+B: count}, cout represents the number of occurrences of A+B, and then traverse C, D, as long as 0 The key of -(C+D) is in the above dictionary, indicating that the count group equal to 0 is found, and the counter can be incremented by count. The specific code is as follows:

    Insert picture description here

  • LeetCode383: Ransom letter : This is another problem of offsetting the numbers. Define a dictionary to count the number of each character in the magazine, and then traverse the ransom. If the current character is not in the dictionary, return False. The number of corresponding characters in the dictionary is offset by one. When it is a negative number, it returns False. When the ransom is traversed, it returns True.

    Insert picture description here

3. Mr. General

The commonly used methods for the topic of the array are the idea of ​​rebuilding the array, the double pointer method, the hash table method, and the sliding window. The idea of ​​rebuilding arrays reflects a kind of reverse thinking. Double pointers are very important. In fact, double pointers are not only left and right pointers, but also fast and slow pointers, as well as the sliding window method. They are applicable to different scenarios. :

  • Fast and slow pointers are generally suitable for linked list problems. This kind of ring is found. This will be encountered when linking lists.
  • The left and right pointers are generally used in binary search. To the sum of three numbers and the sum of four numbers here, the left and right pointers are used to solve the problem very cleverly, provided that sorting is required. This common one is used in the problem of array operations
  • Sliding window is also the first time to learn, and I feel that it is also a very useful tool. This will generally solve the problems related to substrings, and you will encounter them in strings.

Regarding the hash table method, this commonly used scenario is to count the number of elements in a map, to determine repeated sets, to see if the elements are in a certain set, etc. The idea of character offset is also common in this.

Finally, there are some small and clear questions. There are pure array traversal simulation questions, like the spiral matrix. This kind of focus is on the basic array manipulation capabilities. Generally, the starting point, moving direction, boundary and ending conditions must be determined. , This kind of need to find the law of walking first. Other topics are the investigation of clever ideas, this has no fixed routine, and is well-informed.

While brushing the dynamic programming, I took some time to review the previous knowledge. The array section took four or five days to review, about 10 questions, summarized as follows:

The idea of ​​rebuilding the array

Double pointer

Small fresh :

Sliding window :

Hash table :

Guess you like

Origin blog.csdn.net/wuzhongqiang/article/details/114970237