Leetcode kicking week 257

Weekly portal

There are two more questions, but the supplementary questions in the afternoon are very smooth. It's probably because I slept all afternoon, ha ha ha

5863. Statistical special Quads

Idea: hash

Time complexity: O ( n 3 + n ∗ l i m i t ) O(n^3 + n*limit) O(n3+n∗limit), l i m i t limit limit is n u m s nums The value range of num.

With two-dimensional array m a r k mark mark. m a r k i , j mark_{i,j} marki,j , stored n u m s [ i . . n − 1 ] nums[i..n-1] Within nums[i..n − 1] interval j j Quantity of j.

Available in O ( n ∗ l i m i t ) O(n*limit) O(n * limit) m a r k mark The initialization code of mark is as follows:

int mark[51][101] = {0};
for (int i = nums.size()-1; i >= 0; i--) {
    memcpy(mark[i], mark[i+1], sizeof(mark[i]));
    mark[i][nums[i]]++;
}

Next, enumerate the coordinates a , b , c a,b,c a,b,c. Let the cumulative sum of the three elements be s u m sum sum, which can be accumulated m a r k c + 1 , s u m mark_{c+1, sum} Mark C + 1, sum , get the final answer. The complete code is as follows:

class Solution {
public:
    int countQuadruplets(vector<int>& nums) {
        int mark[51][101] = {0};
        for (int i = nums.size()-1; i >= 0; i--) {
            memcpy(mark[i], mark[i+1], sizeof(mark[i]));
            mark[i][nums[i]]++;
        }
        int anw = 0;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = i+1; j < nums.size(); j++) {
                for (int k = j+1; k < nums.size(); k++) {
                    int sum = nums[i] + nums[j] + nums[k];
                    if (sum <= 100) {
                        anw += mark[k+1][sum];
                    }
                }
            }
        }
        return anw;
    }
};

5864. Number of weak characters in the game

Idea: sort, double pointer

Time complexity: O ( n ∗ lg ⁡ n ) O(n*\lg n) O(n∗lgn)

First will p r o p prop prop according to a t t a c k attack attack is sorted in descending order.

After sorting, for p r o p i prop_i propi to quickly determine a t t a c k attack attack higher than p r o p i prop_i The maximum subscript of propi , is marked as p i p_i pi​. Will interval [ 0 , p i ] [0, p_i] The highest defense in [0,pi] is recorded as d e f i def_i defi​.

If d e f i def_i defi above p r o p i prop_i propi's defense, then p r o p i prop_i propi , is a weak role, and vice versa.

because p r o p prop prop is a t t a c k attack In descending order of attack, there must be:

  • p i − 1 ≤ p i p_{i-1} \le p_i pi−1​≤pi​
  • d e f i = m a x ( d e f e n s e p i , d e f i − 1 ) def_i = max(defense_{p_i}, def_{i-1}) defi​=max(defensepi​​,defi−1​)

Therefore, you can O ( n ) O(n) The time complexity of O(n) recursively deduces all p i p_i pi , and d e f i def_i defi​.

class Solution {
public:
    int numberOfWeakCharacters(vector<vector<int>>& p) {
        sort(p.begin(), p.end(), [](const auto &l, const auto &r) {
            return l[0] > r[0];
        });
        
        int anw = 0;
        
        for (int limit = 0, i = -1, j = 0; j < p.size(); j++) {
            while (i+1 < j && p[i+1][0] != p[j][0]) {
                i++;
                limit = max(limit, p[i][1]);
            }
            if (limit > p[j][1]) {
                anw++;
            }
        }
        return anw;
    }
};

5865. The first day after visiting all rooms

Idea: recursion, disassembly

Time complexity: O ( n ) O(n) O(n)

Considering that each room has two states:

  • Has been accessed an odd number of times
  • Has been accessed an even number of times

You might as well use two arrays f 1 f1 f1, f 2 f2 f2 represents the number of days to arrive at the room for the first and second time, respectively.

f 1 i f1_i f1i is easy to calculate: f 1 i = f 2 i − 1 + 1 f1_i = f2_{i-1} + 1 f1i​=f2i−1​+1.

f 2 i f2_i f2i# can be disassembled into three parts:

  • First arrival at the room i i i. Time consuming f 1 i f1_i f1i# days.
  • from i i i return n e x t i next_i nexti, 1 day.
  • from n e x t i next_i nexti , back again i i i. Time consuming f 1 i − f 1 n e x t i f1_i - f1_{next_i} f1i − f1nexti − days.

The first two parts are easy to understand, no nonsense. Just the third part.

Back in n e x t i next_i After nexti, n e x t i next_i nexti has been accessed an odd number of times, [ n e x t i + 1 , i − 1 ] [next_i+1, i-1] The rooms in [nexti + 1,i − 1] were visited an even number of times.

Not hard to find, [ n e x t i , i − 1 ] [next_i, i-1] The state of the room in [nexti, i − 1] is equivalent to the first arrival n e x t i next_i The state when nexti , so from n e x t i next_i nexti , back again i i The time taken for i is f 1 i − f 1 n e x t i f1_i - f1_{next_i} f1i​−f1nexti​​.

in summary:

  • f 1 i = f 2 i − 1 + 1 f1_i = f2_{i-1} + 1 f1i​=f2i−1​+1
  • f 2 i = f 1 i + 1 + f 1 i − f 1 n e x t i f2_i = f1_{i} + 1 + f1_{i} - f1_{next_i} f2i​=f1i​+1+f1i​−f1nexti​​
class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& next) {
        vector<int64_t> f1(next.size());
        vector<int64_t> f2(next.size());
        f2[0] = 1; 
        const int64_t mod = 1e9+7;
        for (int i = 1; i < next.size(); i++) {
            f1[i] = (f2[i-1] + 1)%mod;
            f2[i] = (f1[i] + 1 + (mod+f1[i] - f1[next[i]]))%mod;
        }

        return f1.back();
    }
};

5866. Maximum common factor sorting of arrays

Idea: joint search set, prime sieve

Time complexity: O ( n + l i m i t ∗ l i m i t ) O(n+limit*\sqrt {limit}) O(n+limit∗limit ​), l i m i t limit limit is the value range.

set up p o s i pos_i posi = after sorting n u m s i nums_i The location of numsi , can be found in O ( l i m i t + n ) O(limit+n) The time complexity of O(limit+n) is obtained, and the code is as follows:

int cnt[100001] = {0};
int pos[30001] = {0};
// Count the number of occurrences of each array
for (auto n : nums) {
  cnt[n]++;
}
// Calculate the prefix and of cnt
for (int i = 1; i <= 100000; i++) {
  cnt[i] += cnt[i-1];
}
// The position of each array is obtained by prefix and
for (int i = 0; i < nums.size(); i++) {
  pos[i] = --cnt[nums[i]];
}

Now the problem becomes "location" i i Can i reach the position through several transformations p o s i pos_i posi​」.

Consider three locations a a a, b b b, c c c. If a a a and b b b exchangeable, b b b and c c c is exchangeable, then with the help of b b b, a a a and c c c also interchangeable positions. The old fellow who has familiarity with and searched for it should have thought that it can help and check the relationship between the maintenance locations.

With a length of n + l i m i t n+limit Array of n+limit f a fa fa, used to store and query sets:

  • front n n n elements represent n u m s nums In nums n n n locations
  • after l i m i t limit limit elements represent divisors

Therefore, we can find the prime numbers that can be filtered by enumeration similar to prime sieve p p p is the position of the division, and these positions are compared with n + p n+p n+p merge together.

Finally, enumeration i ∈ [ 0 , n − 1 ] i∈[0,n-1] i ∈ [0,n − 1], with the help of f a fa fa judgment i i i and p o s i pos_i posi# whether it is connected. If all are connected, return t r u e true true, otherwise return f a l s e false false.

class Solution {
public:
    int fa[130001] = {0};
    int find(int x) {
        int t = x;
        while(t != fa[t]) {
            t = fa[t];
        }
        while(x != fa[x]) {
            int tmp = fa[x];
            fa[x] = t;
            x = tmp;
        }
        return x;
    }
    void merge(int u, int v) {
        int fu = find(u);
        int fv = find(v);
        fa[fu] = fv;
    }
    bool gcdSort(vector<int>& nums) {
        int cnt[100001] = {0};
        int pos[30001] = {0};
        // Count the number of occurrences of each array
        for (auto n : nums) {
            cnt[n]++;
        }
        // Calculate the prefix and of cnt
        for (int i = 1; i <= 100000; i++) {
            cnt[i] += cnt[i-1];
        }
        // The position of each array is obtained by prefix and
        for (int i = 0; i < nums.size(); i++) {
            pos[i] = --cnt[nums[i]];
        }

        // Initialize and query set
        for (int i = 0; i <= 130000; i++) {
            fa[i] = i;
        }

        // Reuse cnt. cnt[i] represents the position where the number I first appears
        memset(cnt, -1, sizeof(cnt));

        for (int i = 0; i < nums.size(); i++) {
            if (cnt[nums[i]] != -1) {
                // The same array must be connected and can be merged first
                merge(cnt[nums[i]], i);
            } else {
                // Update cnt
                cnt[nums[i]] = i;
            }
        }

        // Prime sieve
        bool mark[100001] = {0};
        for (int i = 2; i <= 100000; i++) {
            if (mark[i]) { continue; }
            mark[i] = true;
            for (int j = i; j <= 100000; j += i) {
                // j has appeared in nums. Obviously j is divisible by i.
                // So merge j with n+i
                if (cnt[j] != -1) {
                    merge(i+30000, cnt[j]);
                }
            }
        }

        // Judge whether I and pos[i] are connected.
        for (int i = 0; i < nums.size(); i++) {
            if (find(i) != find(pos[i])) {
                return false;
            }
        }

        return true;
    }
};

Tags: Algorithm leetcode

Posted on Sun, 05 Sep 2021 19:34:12 -0400 by crackerjax