Sword finger offer array topic summary (necessary for interview)

Keywords: Algorithm Interview array dfs bfs

Sword finger offer array topic summary (C + + version)
 

1. Duplicate number in array
All numbers in an array num of length n are in the range of 0 ~ n-1. Some numbers in the array are repeated, but I don't know how many numbers are repeated, or how many times each number is repeated. Find any duplicate number in the array.
Idea 1: sort first and traverse. Time complexity: O(nlog(n)), space complexity: O(1)
Idea 2: when traversing the array, query whether the hash table has this number, return if it has one, and add if not. Time complexity: O(n), space complexity: O(n)

Ideas 1 and 2 are relatively simple, and the code will not be posted. Mainly talk about the following methods.
Idea 3: hash in place. Pay attention to the topic conditions. All numbers in the array with length n are in the range of 0 to n-1. You can use the swap() function to make the numbers in numbers correspond to the subscript of the array.
Time complexity: O(n), space complexity: O(1)

Traverse the entire array:
1. When numbers[i] is equal to subscript i, judge whether the next subscript corresponds;
2. When numbers[i] is not equal to subscript i, there are two cases
(1)numbers[i]==numbers[numbers[i]], at this time, numbers[i] corresponding to subscript i has been mapped, duplicate numbers appear, and the number is returned;
(2) Otherwise, swap(numbers[numbers[i]],numbers[i]);
3. If no duplicate number is found at the end of traversal, - 1 is returned;

int findRepeatNumber(vector<int>& nums) {
        if(!nums.size()) return -1;
        for(int i = 0;i < nums.size();) {
            if(i == nums[i]) i++;
            else if(nums[i] == nums[nums[i]]) return nums[i];
            else swap(nums[i],nums[nums[i]]);
        }
        return -1;
    }

 
2. Find in 2D array
In an n * m two-dimensional array, each row is sorted in ascending order from left to right, and each column is sorted in ascending order from top to bottom. Complete an efficient function, input such a two-dimensional array and an integer, and judge whether the array contains the integer.
The number of team leaders is as follows:

Idea: using the nature of this array, we traverse the array from the number in the lower left corner, maintaining the row subscript i and column subscript j traversed by the two-dimensional array. If the number currently traversed is equal to the target, it will directly return true. If the number currently traversed is greater than the target value, make I minus one, otherwise J plus one.
Time complexity: O(n), space complexity: O(1)

bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        if(matrix.empty() || matrix[0].empty()) return false;
        int row = matrix.size(),column = matrix[0].size(),i = row-1,j = 0;
        while(i>=0 && j < column) {
            if(matrix[i][j] == target) return true;
            else if(matrix[i][j] > target) i--;
            else j++;
        }
        return false;
    }

 
3. Rotate the smallest number in the array
Moving the first elements of an array to the end of the array is called array rotation. Enter a rotation of an incrementally sorted array and output the smallest element of the rotation array. For example, if the array [3,4,5,1,2] is a rotation of [1,2,3,4,5], the minimum value of the array is 1.
Idea 1: take the first number after sorting, time complexity O(nlog(n)), space complexity O(1)
Idea 2: binary search method. Here, we analyze the target as the right endpoint, which is divided into the following three cases.

Case 1, arr [mid] > target: 4 5 6 1 2 3
arr[mid] is 6, target is the right end point 3, arr[mid] > target, indicating that [L... Mid] is > = target. Because the original array is non decreasing, it can be determined that the answer is [mid+1... r] interval, so l = mid+1

Case 2, arr [mid] < target: 5 6 1 2 3 4
arr[mid] is 1, target is the right endpoint 4, and arr[mid] < target indicates that the answer is definitely not in [mid+1... R], but arr[mid] may be the answer, so the answer is in the interval of [l, mid], so r = mid

Case 3, arr[mid] == target:
If it is 1 0 1 1, arr[mid] = target = 1, the answer is obviously on the left
If it is 1 0 1, arr [mid] = target = 1, the answer is obviously on the right
So in this case, if you can't be sure whether the answer is on the left or right, let r = r - 1 and slowly reduce the interval.
The worst time complexity is O(n), generally O(log(n))

int minArray(vector<int>& numbers) {
        if(!numbers.size()) return -1;
        int l = 0,r = numbers.size()-1;
        while(l<r) {
            int mid = l+r >> 1;
            if(numbers[mid] > numbers[r]) l = mid+1;
            else if(numbers[mid] < numbers[r]) r = mid;
            else r--;
        }
        return numbers[l];
    }

 
4. Adjust the array order so that odd numbers precede even numbers
Enter an integer array and implement a function to adjust the order of numbers in the array so that all odd numbers are in the first half of the array and all even numbers are in the second half of the array. There is no requirement for the relative position of odd and even numbers.
Idea 1: open two new vectors, traverse the original array, store the odd number in one vector and the even number in another vector, then traverse the even number vector and store the number in the odd number vector.
Time complexity O(n), space complexity O(n)
This method code is simple and not the best method, so the code will not be posted.
Idea 2: the double pointer algorithm defines the head and tail pointers and starts traversing towards the middle. If the head pointer encounters an odd number, its subscript is added by one. Similarly, the tail pointer encounters an even subscript minus one. Otherwise, the numbers pointed to by the two pointers need to be exchanged, and the head and tail pointers move one bit towards the middle.
Time complexity O(n), space complexity O(1)

vector<int> exchange(vector<int>& nums) {
        if(!nums.size()) return nums;
        int l = 0,r = nums.size()-1;
        while(l<r) {
            if(nums[l]%2 == 1) l++;
            else if(nums[r]%2 == 0) r--;
            else {
                swap(nums[l++],nums[r--]);
            }
        }
        return nums;
    }

Think: what if the topic requires to ensure the relative order of odd and odd, even and even?

 
5. A number that appears more than half the times in the array
A number in the array appears more than half the length of the array. Please find out this number. Assume that the array is non empty and that there are always many elements in a given array.
Idea 1: sort first, and then take the middle number
Time complexity O(nlog(n)), space complexity O(1)

Idea 2: change space for time, and use a hash table to record the number of occurrences
Time complexity O(n), space complexity O(n)

int majorityElement(vector<int>& nums) {
        if(!nums.size()) return -1;
        unordered_map<int,int> hash;
        for(auto t:nums) {
            hash[t]++;
            if(hash[t] > nums.size()/2) return t;
        }
        return -1;
    }

 
6. Minimum number of k
Enter the integer array arr to find the minimum number of k. For example, if you enter 8 numbers: 4, 5, 1, 6, 2, 7, 3 and 8, the minimum 4 numbers are 1, 2, 3 and 4.
Idea 1: sort first, then take the first k numbers and return
Time complexity O(nlog(n)), space complexity O(1)

Idea 2: use the large top heap to traverse the array. If the heap size is less than k, add a number to the heap. Otherwise, judge that if the heap top is greater than the number currently traversed, pop up the heap top and put the number into the heap, so that the minimum number of K is always maintained in the heap
Time complexity O(nlog(k)), space complexity O(k)

vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res;
        if(!arr.size() || k > arr.size()) return res;
        
        priority_queue<int> heap;
        for(auto t:arr) {
            if(heap.size() < k) heap.push(t);
            else if(heap.size() && heap.top() > t) {
                heap.pop();
                heap.push(t);
            }
        }
        
        while(heap.size()) {
            res.push_back(heap.top());
            heap.pop();
        }
        
        return res;
    }

 
7. Maximum sum of consecutive subarrays
Enter an integer array. One or more consecutive integers in the array form a sub array. Find the maximum value of the sum of all subarrays.
The required time complexity is O(n)
give an example:
Input: num = [- 2,1, - 3,4, - 1,2,1, - 5,4]
Output: 6
Explanation: the maximum sum of continuous subarray [4, - 1,2,1] is 6.
Idea: define two variables res and curSum, where res saves the final sum of the largest sub arrays. The initial value of curSum is 0. Each time you traverse a number t, compare the larger values in curSum + t and t and store them in curSum, and then store the larger values in res and curSum in res, and so on until you traverse the whole array

int maxSubArray(vector<int>& nums) {
        if(!nums.size()) return 0;
        int curSum = 0, res = nums[0];
        for(auto t:nums) {
            curSum = max(curSum + t, t);
            res = max(res, curSum);
        }
        return res;
    }

 
8. Find a number in a sorted array
Counts the number of times a number appears in the sorted array.
give an example:
Input: num = [5,7,7,8,8,10], target = 8
Output: 2
Direct traversal is also OK (so today's interview may be here emmm). Obviously, I want to test your dichotomy during the interview. Let's talk about the dichotomy below
It is suggested to take a look at the bisection template of cattle batch first. The portal: Binary search algorithm template (too strong, brother die!)

Idea: the array is in order, and two bisections are performed. For the first bisection, find the position l of the first > = target; The second bisection finds the position r of the last < = target. If the search is successful, it returns end - begin + 1, which is the number of times the number appears in the sorted array. Otherwise, it returns 0, which indicates that the number does not appear in the array
Time complexity O(log(n)), space complexity O(1)

int search(vector<int>& nums, int target) {
        if(!nums.size()) return 0;
        int l = search1(nums,target),r = search2(nums,target);
        if(nums[l] != target || nums[r] != target) return 0;
        return r-l+1;
    }

    int search1(vector<int>& nums, int target) {
        int l = 0,r = nums.size()-1, ans = 0;
        while(l<r) {
            int mid = l+r >> 1;
            if(nums[mid] >= target) r = mid;
            else l = mid+1;
        }
        return r;
    }
    int search2(vector<int>& nums, int target) {
        int l = 0,r = nums.size()-1;
        while(l<r) {
            int mid = (l+r+1) >> 1;
            if(nums[mid] <= target) l = mid;
            else r = mid-1;
        }
        return r;
    }

 
9. Missing number in 0~n-1
All numbers in an incremental sort array with length n-1 are unique, and each number is in the range of 0 ~ n-1. Among the N numbers in the range 0 ~ n-1, there is only one number that is not in the array. Please find this number.
give an example:
Input: [0,1,3]
Output: 2

Input: [0,1,2,3,4,5,6,7,9]
Output: 8

Idea: for an ordered array, we generally think of a binary search algorithm. The number with size I should be in the position with subscript I. if it is not, it indicates that the number is misplaced. We can use whether num [i] is equal to mid to divide the array into two parts
Time complexity O(log(n)), space complexity O(1)

int missingNumber(vector<int>& nums) {
        if(!nums.size()) return -1;
        int l = 0,r = nums.size()-1;
        while(l<r) {
            int mid = l+r >> 1;
            if(nums[mid] != mid) r = mid;
            else l = mid+1;
        }
        // If no value is missing from 0 to N - 1, n is missing
        return (l == nums.size() - 1 && nums[l] == l) ? l + 1 : l;
    }  

 
10. One of the numbers in the array
In an integer array nums, all but two numbers appear twice. Please write a program to find these two numbers that only appear once. The time complexity is O(n) and the space complexity is O(1).
Idea 1: if there is no space complexity requirement, you can use the hash table to store the occurrence times of each number, and then return the number with the occurrence times of 1.
Idea 2: bit operation
1. General idea: there is a problem similar to it. To find a number that only appears once in the array, the solution is to XOR continuously from the beginning. Because the XOR value of the same two numbers is 0, the final XOR result is the answer
2. In this question, there are two numbers a and b that only appear once. According to the XOR method, only the value of a or b can be obtained. We need to think about the characteristics of the results of these two numbers
3. It can be found that, first of all, the two numbers must be different, so the XOR result must not be 0. Then one bit in the result of a XOR b must be 1. Assuming that it is the x-th bit, it shows that the x-th bit of binary of a and b is different. According to this feature, we can divide the array into two sets, that is, the set of numbers with the x-th bit of 1 and the set of numbers with the x-th bit of 0, The two values of these two parts are the values of a and b
4. It is required that the last bit of binary 1 can be calculated with lowbit, which can quickly get the 1 of the last bit of x
Time complexity: O(n) space complexity: O(1)

vector<int> singleNumbers(vector<int>& nums) {
        if(!nums.size()) return nums;
        int s = 0;//s is the XOR result of the two numbers you are looking for
        for(auto t:nums) s ^= t;
        int flag = lowBit(s);
        int a = 0,b; //a and b are the two numbers required
        //Group all numbers according to flag. a must be one of the numbers to be found
        for(auto t:nums) {
            if(flag & t) a ^= t;
        }
        b = s ^ a;
        vector<int> res{a,b};
        return res;
    }

    //Take the lowest 1 of x (the binary is 0000 0011, and the lowest 1 bit is the first bit, so it is 0000 0001 after taking out)
    int lowBit(int x) {
        return x & -x;
    }

 
11. The number that appears in the array
In an array nums, except one number appears only once, all other numbers appear three times. Find the number that appears only once.
Idea 1: you can use a hash table to store the number of occurrences of each number, and then return the number with the number of occurrences of 1.
Time complexity: O(n) space complexity: O(n)
Idea 2: use bit operation and consider the binary form of numbers. For numbers that appear three times, the number of occurrences of each binary bit 1 is a multiple of 3. Therefore, the number of occurrences of 1 in each binary bit of all numbers is counted, and the remainder of 3 is calculated, and the result is a number that occurs only once.
Time complexity: O(n) space complexity: O(1)

int singleNumber(vector<int>& nums) {
        if(!nums.size()) return 0;
        int res = 0;
        //Create a 32-bit number to count the number of 1 occurrences on each bit
        for(int i = 0;i < 32;i++) {
            int sum = 0;
            //Count the rightmost 1 of all binary bits
            for(int j = 0;j < nums.size();j++) {
                sum += (nums[j]>>i) & 1;
            }
            res |= (sum%3) << i; //Calculate the contribution of each binary bit to the result
        }
        return res;
    }

 
12. And are two numbers of s
Enter an incrementally sorted array and a number s, and find two numbers in the array so that their sum is exactly s. If the sum of multiple pairs of numbers is equal to s, any pair can be output.
Idea 1: use the hash table to find the combination of numbers by traversing the array.
Time complexity: O(n) space complexity: O(n)
Idea 2: because the array is in ascending order, you can use its nature to use the double pointer algorithm. Define two pointers at the beginning and end. If the sum of the two pointed numbers is exactly the target value, the two numbers will be returned. If the sum is less than the target value, the head pointer will be increased by one, otherwise the tail pointer will be reduced by one
Time complexity: O(n) space complexity: O(1)

   vector<int> twoSum(vector<int>& nums, int target) {
        if(!nums.size()) return {};
        int l = 0,r = nums.size()-1;
        while(l<r) {
            if(nums[l] + nums[r] == target) return vector<int> {nums[l], nums[r]};
            else if(nums[l] + nums[r] < target) l++;
            else r--;
        }
        return {};
    }

 
13. Print matrix clockwise
Enter a matrix and print out each number in clockwise order from the outside to the inside.
give an example:

Idea 1: you can define four boundaries: top, bottom, left and right, and cycle in the four directions of "from left to right, from top to bottom, from right to left, and from bottom to top". In the printing process of each direction, you can do the following three things (see the table below for the specific information of each direction);
(1) Print according to the boundary, that is, add the elements to the end of the list res in order;
(2) The boundary shrinks inward 11 (representing that it has been printed);
(3) Judge whether the printing is completed (whether the boundary meets). If the printing is completed, it will jump out.

Time complexity: O(mn) space complexity: O(1)

vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        if(!matrix.size()) return {};
        int l = 0,r = matrix[0].size()-1,t = 0,b = matrix.size()-1;//Define left and right upper and lower boundaries
        while(true) {
            //Left to right
            for(int i = l;i <= r;i++) res.push_back(matrix[t][i]);
            if(++t > b) break;
            //top to bottom
            for(int i = t;i <= b;i++) res.push_back(matrix[i][r]);
            if(--r < l) break;
            //Right to left
            for(int i = r;i >= l;i--) res.push_back(matrix[b][i]);
            if(--b < t) break;
            //Down to up
            for(int i = b;i >= t;i--) res.push_back(matrix[i][l]);
            if(++l > r) break;
        }
        return res;
    }

Idea 2: the above code may not be elegant, because there are four for loops, and another method can be used. It needs to consume a certain space to save which points have been accessed.
Time complexity: O(mn) space complexity: O(mn)

vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        if(!matrix.size()) return res;
        int row = matrix.size(),col = matrix[0].size();
        vector<vector<bool>> flag(row, vector<bool>(col,false));
        int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1}; //Define the upper right, lower left (clockwise) of the x-axis and y-axis
        int x = 0,y = 0, d = 1; //Variable d is used for turning

        for(int k = 0;k < row*col;k++) {  //Traverse all points
            res.push_back(matrix[x][y]);
            flag[x][y] = true;  //Mark those that have been traversed

            int a = x + dx[d], b = y + dy[d]; //Possible location of the next point to traverse
            if(a<0 || a>=row || b<0 || b >= col || flag[a][b]) { //If the position of this point does not meet the regulations, you need to turn
                d = (d+1) % 4;  //turn a corner
                a = x + dx[d],b = y + dy[d]; //Location of the new point
            }

            x = a, y = b;  The exact location of the next point to traverse
        }
        
        return res;
    }

 
Think: if you want to print the matrix counterclockwise, how to modify the codes of the above two methods?

 
14. Path in matrix
Given an m x n two-dimensional character grid board and a string word word. If word exists in the grid, return true; Otherwise, false is returned.
Words must be formed alphabetically by letters in adjacent cells, where "adjacent" cells are those horizontally or vertically adjacent. Letters in the same cell cannot be reused.
give an example:
3 below × The matrix of 4 can contain the word "ABCCED"

Idea: depth first traverses DFS. The original two-dimensional array is like a maze, which can walk up, down, left and right. We take each number in the two-dimensional array as the starting point to match the given string. In the process, we need to change the used letter into a special letter to avoid repeated use of characters (you can also define a visited array as large as the original array to record whether the current location has been accessed) If the current character of the two-dimensional array board is equal to the character corresponding to the target string word, call the recursive function of DFS for its upper, lower, left and right adjacent characters respectively. As long as one of them returns true, it means that the matching character can be found, otherwise it cannot be found
Time complexity analysis: there are two starting points of words m ∗ n m*n m * n, each letter of a word can be selected in four directions: up, down, left and right. However, since there is no turning back, there are only three choices except the first letter of the word. Therefore, the total time complexity is o( m n ∗ 3 k mn*3^k mn∗3k).

bool exist(vector<vector<char>>& board, string word) {
        if(!board.size()) return false;
        for(int i = 0;i < board.size();i++) {
            for(int j = 0;j < board[0].size();j++) {
                if(dfs(board,word,0,i,j)) return true;
            }
        }
        return false;
    }

    bool dfs(vector<vector<char>>& board,string &word,int u,int x,int y) {
        if(board[x][y] != word[u]) return false; //If the current character does not match, return false directly
        if(u == word.size()-1) return true; //The current character has already matched the last character of the string
        int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; //Define four directions
        char t = board[x][y];
        board[x][y] = '*';  //The current character is modified to * to avoid repeated use of characters
        //Call recursive functions to four adjacent characters respectively. As long as one of them returns true, it means that matching characters can be found
        for (int i = 0; i < 4; i ++ ) { 
            int a = x + dx[i], b = y + dy[i];
            if (a >= 0 && a < board.size() && b >= 0 && b < board[a].size()) {
                if (dfs(board, word, u + 1, a, b)) return true;
            }
        }
        board[x][y] = t; //After the recursive call, you need to restore the previous state
        return false;
    }

 
15. Range of motion of robot
There is a grid with m rows and N columns on the ground, from coordinates [0,0] to coordinates [m-1,n-1]. A robot starts to move from the grid with coordinates [0,0], and it can move left, right, up and down one grid at a time (it cannot move outside the grid), nor can it enter the grid where the sum of the digits of row coordinates and column coordinates is greater than K. for example, when k is 18, the robot can enter the grid [35,37] , because 3 + 5 + 3 + 7 = 18. But it cannot enter the grid [35, 38], because 3 + 5 + 3 + 8 = 19. How many grids can the robot reach?

Idea: start from point (0, 0) and expand new nodes in four directions up, down, left and right each time. During expansion, note that the new nodes need to meet the following conditions:

If you haven't traversed before, you can use a bool array to judge;
Did not go out of the border;
The sum of each digit of the horizontal and vertical coordinates is less than k;

The final answer is the number of legal nodes traversed.

Time complexity analysis: because there is bool array weight judgment, each point will only be searched once. There are only O(nm) grids in total, so the total time complexity is O(nm).

class Solution {
public:
    int movingCount(int m, int n, int k) {
        vector<vector<bool>> flag(m,vector<bool>(n,false));
        int res = dfs(0,0,k,flag);
        return res;
    }

    int dfs(int x, int y, int k,vector<vector<bool>> &flag) {
        int sum = getSum(x,y);//Get the sum of coordinate digits
        //Boundary condition determination
        if(x<0 || x>=flag.size() || y<0 || y>=flag[0].size() || flag[x][y] || sum>k) return 0;
        flag[x][y] = true; //Mark that the position has passed
        return dfs(x+1,y,k,flag) + dfs(x-1,y,k,flag) + dfs(x,y+1,k,flag) + dfs(x,y-1,k,flag) + 1;
    }

    int getSum(int x,int y) {
        int sum = 0;
        while(x) {
            sum += x%10;
            x /= 10;
        }
        while(y) {
            sum += y%10;
            y /= 10;
        }
        return sum;
    }
};

 
 
 
 
Big man, point a praise and go!
 
 

Posted by j115 on Thu, 04 Nov 2021 19:06:44 -0700