LeetCode kickoff week 269

Keywords: Algorithm leetcode

Weekly portal

The ranking is 131. It has been quite stable recently~

2089. Find the target subscript after array sorting

Idea: traversal, counting

Time complexity: O ( n ) \mathcal{O}(n) O(n)

Space complexity: O ( 1 ) \mathcal{O}(1) O(1)

It is not hard to imagine that the subscript of the target element after sorting is affected by two factors:

  • Number of elements less than target
  • Number of elements with value target

Obviously, the above two quantities can be counted through one traversal, and then the answer can be constructed.

class Solution {
public:
    vector<int> targetIndices(vector<int>& nums, int target) {
        // cnt: number of elements with value 'target'
        // Less: number of elements less than 'target'
        int cnt = 0, less = 0;
        for (auto num : nums) {
            if (target == num) {
                cnt++;
            } else if (target > num) {
                less++;
            }
        }
        vector<int> res(cnt, 0);
        // Construct answer
        for (int i = 0 ; i < cnt; i++) {
            res[i] = i+less;
        }
        return res;
    }
};

2090. Average value of subarray with radius k

Idea 1: prefix and

Time complexity: O ( n ) \mathcal{O}(n) O(n)

Space complexity: O ( n ) \mathcal{O}(n) O(n)

With one-dimensional array pre, p r e i pre_i prei stores the cumulative sum of nums[0..i], which can obviously be O ( n ) O(n) The time complexity of O(n) is obtained.

After obtaining pre, the average value of the subarray centered on i can be expressed as:
⌊ p r e i + k − p r e i − k − 1 1 + 2 ∗ k ⌋ \lfloor\frac{pre_{i+k} - pre_{i-k-1}}{1+2*k}\rfloor ⌊1+2∗kprei+k​−prei−k−1​​⌋

Therefore, it is not difficult to write the following code:

class Solution {
public:
    vector<int> getAverages(vector<int>& nums, int k) {
        vector<int64_t> pre(nums.begin(), nums.end());
        // Calculate prefix and
        for (int i = 1; i < pre.size(); i++) {
            pre[i] += pre[i-1];
        }
        // res is used to store answers
        vector<int> res;
        for (int i = 0; i < nums.size(); i++) {
            // Calculates the bounds of the subarray
            int l = i-k, r = i+k;
            if (l < 0 || r >= nums.size()) {
                // It's out of bounds. You need to fill in - 1 according to the meaning of the question
                res.push_back(-1);
            } else {
                // Solve pre[i+k] - pre[i-k-1]
                // Note that i-k-1 is 0
                int64_t sum = pre[r] - (l == 0 ? 0 : pre[l-1]);
                res.push_back(sum/(k*2+1));
            }
        }
        return res;
    }
};

Idea 2: sliding window

Time complexity: O ( n ) \mathcal{O}(n) O(n)

Space complexity: O ( 1 ) \mathcal{O}(1) O(1)

The sliding window solution eliminates the array used to store prefix and, and only uses two variables to maintain information.

The essence of this solution is that when known i − 1 i-1 On the premise of subarray and sum centered on i − 1, the complexity can be O ( 1 ) O(1) O(1) - sum plus nums_{i+k} and subtract num {i-k-1} to update sum to i i i is the center of the subarray and.

class Solution {
public:
    vector<int> getAverages(vector<int>& nums, int k) {
        // res is used to store answers
        vector<int> res;
        // Sum represents the cumulative sum of subarrays centered on i
        // cnt represents the number of elements of the subarray centered on i
        
        int64_t sum = 0, cnt = min(decltype(nums.size())(k), nums.size());
        // Initialize sum to the value of num [I, I + k-1]
        for (int i = 0; i < k && i < nums.size(); i++) {
            sum += nums[i];
        }
        for (int i = 0; i < nums.size(); i++) {
            // At this time, sum is the value of the sub array centered on i-1,
            // Try adding num [i + k] to sum
            if (i-k-1 >= 0) {
                sum -= nums[i-k-1];
                cnt--;
            }
            // Attempt to remove nums[i-k-1] from sum
            if (i+k < nums.size()) {
                sum += nums[i+k];
                cnt++;
            }
            // sum is updated to the value of the new subarray in i
            
            // Fill in the answers according to the meaning of the question
            if (cnt == 2*k+1) {
                res.push_back(sum / cnt);
            } else {
                res.push_back(-1);
            }
        }
        return res;
    }
};

2091. Remove the maximum and minimum values from the array

Idea: greed

Time complexity: O ( n ) \mathcal{O}(n) O(n)

Space complexity: O ( 1 ) \mathcal{O}(1) O(1)

Assuming that the positions of the two target elements are known, they are recorded as P 1 P_1 P1 ^ and P 2 P_2 P2, and meet P 1 < P 2 P_1 \lt P_2 P1​<P2​. Subscripts start at 0.

There are three removal strategies available:

  • Remove from both ends - remove from front P 1 + 1 P_1+1 P1 + 1 element, removed from behind n − P 2 n-P_2 n − P2 − elements.
  • All removed from front - Total removed P 2 + 1 P_2+1 P2 + 1 element.
  • All removed from behind - Total removed n − P 1 n-P_1 n − P1 − elements.

The optimal solution of these three strategies is the answer.

class Solution {
public:
    int minimumDeletions(vector<int>& nums) {
        int maxNum = -1000000, maxPos = -1;
        int minNum = 1000000, minPos = -1;
        
        // Find the location of the minimum and maximum values
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > maxNum) {
                maxNum = nums[i];
                maxPos = i;
            }
            if (nums[i] < minNum) {
                minNum = nums[i];
                minPos = i;
            }
        }
        
        // Exchange to ensure minpos < maxpos for subsequent processing
        if (minPos > maxPos) {
            swap(minPos, maxPos);
        }
        
        // Calculate the deletion times of the three policies
        int s1 = minPos+1 + (nums.size() - maxPos);
        int s2 = nums.size() -  minPos;
        int s3 = maxPos+1;
        
        // Take the minimum as the answer.
        return min(s1, min(s2, s3));
    }
};

2092. Identify all experts who know the secret

Idea: time as edge weight

Time complexity: O ( n + e ) \mathcal{O}(n+e) O(n+e), n n n is the number of experts, e e e is the number of meetings, the same below.

Space complexity: O ( n + e ) \mathcal{O}(n+e) O(n+e)

The experts are regarded as the points in the figure. Two experts participating in the same meeting are connected to one side, and the time of the meeting is regarded as the edge right. Special, expert 0 0 0 and f i r s t P e r s o n firstPerson There is an edge between the first person, and the edge weight is 0 0 0.

It's not hard to draw a conclusion if the expert 0 0 0 and v v There is a path with monotonically increasing edge weight before v, then v v v must know the secret.

A feasible implementation is to 0 0 0 is the source point, and BFS starts along the direction of edge weight growth. The point set accessed during BFS is the answer.

Since it is BFS, how to define "breadth first"? In the shortest path algorithm, the path with the smallest edge weight accumulation in the queue will be given priority. In this problem, it is advisable to take the weight of the last edge of the path as the weight of the whole path, that is, the path with the smallest edge weight will be given priority.

Combined with the monotonic increase of path edge weight, the above practice can be understood as finding out the earliest time point when each expert knows the secret. Analogy with the shortest path algorithm is to find experts 0 0 0 to the shortest circuit of all other experts.

class Solution {
public:
    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
        // Construct edge table
        vector<vector<pair<int, int>>> edges(n);
        for (const auto &meeting : meetings) {
            int u = meeting[0];
            int v = meeting[1];
            int t = meeting[2];
            edges[u].emplace_back(v, t);
            edges[v].emplace_back(u, t);
        }
        edges[0].emplace_back(firstPerson, 0);
        edges[firstPerson].emplace_back(0, 0);
        
        // order[i] means the earliest time I knew the secret
        vector<int> order(n, -1);
        // With the help of priority queue, the "nearest" path is always processed first.
        auto cmp = [](const auto &lhs, const auto &rhs) { return lhs.second > rhs.second; };
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> q(cmp);
        
        // Put source point in queue
        q.emplace(0, 0);
        
        // Start BFS
        while (!q.empty()) {
            auto f = q.top();
            q.pop();
            
            int u = f.first;
            int t = f.second;
            
            // There's already an optimal solution. Skip
            if (order[u] != -1) {
                continue;
            }
            
            // Record optimal solution
            order[u] = t;
            
            // Find next edge
            for (auto &e : edges[u]) {
                int np = e.first;
                int nt = e.second;
                if (nt < t) { continue; }
                if (order[np] != -1) { continue; }
                q.emplace(np, nt);
            }
        }
        // Update answer
        vector<int> anw;
        for (int i = 0; i < order.size(); i++) {
            if (order[i] != -1) {
                anw.emplace_back(i);
            }
        }
        return anw;
    }
};

Posted by ThermalSloth on Fri, 03 Dec 2021 18:56:01 -0800