LeetCode第 73 场双周赛题解


6024. 数组中紧跟 key 之后出现最频繁的数字

题目描述:给你一个数组\(nums\)和一个数字\(val\),求下标中满足\(1 \leq i < n , nums_{i - 1} = val\),对于所有满足条件的\(i\),求出现次数最多的\(nums_i\)

思路:根据题意模拟即可

时间复杂度:\(O(nlogn)\)

参考代码:

class Solution {
public:
    int mostFrequent(vector& nums, int key) {
        vectorcnt(1001 , 0);
        for(int i = 1 ; i < nums.size() ; ++i) if(nums[i - 1] == key) cnt[nums[i]]++;
        int res = -1 , ct = 0;
        for(int i = 1 ; i <= 1000 ; ++i) if(cnt[i] > ct) ct = cnt[i] , res = i;
        return res;
    }
};

5217. 将杂乱无章的数字排序

题目描述:将给定数组按照给定排序规则进行稳定的排序。

思路:可以使用map嵌套vector实现稳定排序,也可以记录下标直接使用sort

时间复杂度:\(O(nlogn)\)

参考代码:

class Solution {
public:
    vector sortJumbled(vector& mapping, vector& nums) {
        map>mp;
        auto f = [&](int x){
             int a = 0;
            string s = to_string(x);
            for(auto& c : s) a = a * 10 + mapping[c - '0'];
            return a;
        };
        for(auto& num : nums) mp[f(num)].push_back(num);
        vectorres;
        for(auto& iter : mp) 
            for(auto& v : iter.second) res.push_back(v);
        return res;
    }
};

5300. 有向无环图中一个节点的所有祖先

题目描述:给你一个有向无环图,对于每一个顶点,求所有能到达它的顶点的集合。

思路:比较裸的拓扑排序,然后过程中用set维护一下父结点集合即可。

时间复杂度:\(O(n^2logn)\)

参考代码:

class Solution {
public:
    vector> getAncestors(int n, vector>& edges) {
        vector>graph(n);
        vectorincome(n, 0);
        for (auto& edge : edges) {
            int u = edge[0], v = edge[1];
            graph[u].push_back(v);
            income[v]++;
        }
        for (int i = 0; i < n; ++i) sort(begin(graph[i]), end(graph[i]));
        vector>a(n);
        queueq;
        for (int i = 0; i < n; ++i) {
            if (income[i] != 0) continue;
            q.push(i);
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (auto& v : graph[u]) {
                a[v].insert(u);
                for (auto& t : a[u]) a[v].insert(t);
                if (--income[v] == 0) q.push(v);
            }
        }
        vector>res(n);
        for (int i = 0; i < n; ++i) {
            for (auto& t : a[i]) res[i].push_back(t);
        }
        return res;
    }
};

5237. 得到回文串的最少操作次数

题目描述:给定一个字符串,每次操作可以交换相邻两个字符,问最少经过多少次操作可以使得字符串变回文,保证题目有解。

思路:比较明显的贪心,可以记录一下每个字符出现的位置,然后遍历枚举,对于当前的枚举的字符,取离他最远的相同字符移动到对称位置会最优。注意特判奇回文的情况。可以使用树状数组维护。

时间复杂度:\(O(nlogn)\)

参考代码:

class Solution {
private:
    vectortr;
    vector>g;
    vectorused;
    string str;
    int n;
    int lowbit(int x){ return x & -x;}
    int sum(int idx){
        int ans=0;
        while(idx){
            ans+=tr[idx];
            idx-=lowbit(idx);
        }
        return ans;
    }

    void add(int idx ,int val){
        while(idx <= n){
            tr[idx] += val;
            idx += lowbit(idx);
        }
        return ;
    }

    int solve(){
        for(int i=1; i<=n+1; i++) add(i,1);
        int res = 0;
        for(int i=1; i<=n; i++){
            if(!used[i]){
                int idx = str[i] - 'a';
                int u = g[idx].back();
                if(i == u) res += (sum(n) - sum(i))/2;
                else res += sum(n) - sum(u);
                add(u, -1);
                add(i, -1);
                used[i] = used[u] = 1;
                g[idx].pop_back();
            }
        }
    return res;
    }
public:
    int minMovesToMakePalindrome(string s) {
        n = s.size();
        s = ' ' + s;
        str = s;
        tr = vector(n + 1 , 0);
        used = vector(n + 1 , false);
        g = vector>(26);
        for(int i=1; i<=n; i++) g[s[i] - 'a'].push_back(i);
        return solve();  
    }
};