leetcode解题思路分析(七十三)643 - 650 题

  1. 子数组最大平均数1
    给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。

规定了长度,就简单的不像话,滑动即可

class Solution {
    
    
public:
    double findMaxAverage(vector<int>& nums, int k) {
    
    
        int sum = 0;
        int n = nums.size();
        for (int i = 0; i < k; i++) {
    
    
            sum += nums[i];
        }
        int maxSum = sum;
        for (int i = k; i < n; i++) {
    
    
            sum = sum - nums[i - k] + nums[i];
            maxSum = max(maxSum, sum);
        }
        return static_cast<double>(maxSum) / k;
    }
};


  1. 错误的集合
    请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

先通过异或找到缺失的x和重复的y的异或,然后再根据二者异或第一个差异位进行分组,再次异或即可

class Solution {
    
    
public:
    vector<int> findErrorNums(vector<int>& nums) {
    
    
        int n = nums.size();
        int temp = 0;
        for (int num : nums) {
    
    
            temp ^= num;
        }
        for (int i = 1; i <= n; i++) {
    
    
            temp ^= i;
        }
        int j;
        for (j = 0; j < 32; j++) {
    
    
            if (temp >> j & 1 == 1) break;
        }
        int num1 = 0, num2 = 0;
        for (int num : nums) {
    
    
            if (num >> j & 1 == 1) num1 ^= num;
            else num2 ^= num;
        }
        for (int i = 1; i <= n; i++) {
    
    
            if (i >> j & 1 == 1) num1 ^= i;
            else num2 ^= i;
        }
        for (int num : nums) {
    
    
            if (num1 == num) return {
    
    num1, num2};
        }
        return {
    
    num2, num1};
    }
};

  1. 最长数对链
    给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。给定一个数对集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。

按区间尾部排序后贪心即可

class Solution {
    
    
public:
    int findLongestChain(vector<vector<int>>& pairs){
    
    
        if(pairs.empty())return 0;
        //区间排序:按右端点进行排序,若右端点不相等,按右端点由小到大进行排序;若右端点相等,则按左端点由小到大进行排序
        sort(pairs.begin(),pairs.end(),[](const auto& a,const auto& b){
    
    
            return (a[1]<b[1])||(a[1]==b[1]&&a[0]<b[0]);
        });
        //count初始化为1,用来统计不重复子区间个数的
        int count=1,end=pairs[0][1];
        for(const auto& p:pairs){
    
    
            if(p[0]>end){
    
    //区间不相交,需要更新边界以及不重复区间个数,注意不能有等号,即区间端点不能连续
                count++;
                end=p[1];
            }
        }
        return count;
    }
};
  1. 回文子串
    给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

马拉车算法

class Solution {
    
    
public:
    int countSubstrings(string s) {
    
    
        int n = s.size();
        string t = "$#";
        for (const char &c: s) {
    
    
            t += c;
            t += '#';
        }
        n = t.size();
        t += '!';

        auto f = vector <int> (n);
        int iMax = 0, rMax = 0, ans = 0;
        for (int i = 1; i < n; ++i) {
    
    
            // 初始化 f[i]
            f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;
            // 中心拓展
            while (t[i + f[i]] == t[i - f[i]]) ++f[i];
            // 动态维护 iMax 和 rMax
            if (i + f[i] - 1 > rMax) {
    
    
                iMax = i;
                rMax = i + f[i] - 1;
            }
            // 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
            ans += (f[i] / 2);
        }

        return ans;
    }
};


  1. 单词替换
    现在,给定一个由许多词根组成的词典和一个句子。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。

用一颗字典树即可

class Solution {
    
    
public:
    struct TrieTree {
    
    
        bool flag;
        map<char, TrieTree*> next;
        TrieTree() : flag(false) {
    
    }
    };
    TrieTree* root;
    Solution() {
    
    
        root = new TrieTree();
    }
    
    string replaceWords(vector<string>& dict, string sentence) {
    
    
        TrieTree* node;
        for (auto w : dict) {
    
    
            node = root;
            for (auto x : w) {
    
    
                if ((node->next).count(x) == 0) {
    
    
                    node->next[x] = new TrieTree();
                }
                node = node->next[x];
            }
            node->flag = true;
        }
        string res;
        int start = 0;
        int end = 0;
        for (int i = 0; i < sentence.size(); ++i) {
    
    
            if (sentence[i] == ' ') 
                continue;
            node = root;
            start = i;
            while (i < sentence.size() && sentence[i] != ' ') {
    
    
                if (node->flag || node->next.count(sentence[i]) == 0) 
                    break;
                node = node->next[sentence[i]];
                ++i;
            }
            end = i;
            while (i < sentence.size() && sentence[i] != ' ') 
                ++i;
            if (!node->flag) 
                end = i;
            res += sentence.substr(start, end - start) + " ";
        }
        if (!res.empty())
            res.pop_back();
        return res;
    }
};


  1. DOTA2 参议院
    假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 Radiant 或 Dire。

贪心算法依次比较队列头部并比较,大的出队后不入队,小的放在队尾,然后循环至一个队列空,则另一方获胜

class Solution {
    
    
public:
    string predictPartyVictory(string senate) {
    
    
        int n = senate.size();
        queue<int> radiant, dire;
        for (int i = 0; i < n; ++i) {
    
    
            if (senate[i] == 'R') {
    
    
                radiant.push(i);
            }
            else {
    
    
                dire.push(i);
            }
        }
        while (!radiant.empty() && !dire.empty()) {
    
    
            if (radiant.front() < dire.front()) {
    
    
                radiant.push(radiant.front() + n);
            }
            else {
    
    
                dire.push(dire.front() + n);
            }
            radiant.pop();
            dire.pop();
        }
        return !radiant.empty() ? "Radiant" : "Dire";
    }
};

  1. 只有两个键的键盘
    最初在一个记事本上只有一个字符 ‘A’。你每次可以对这个记事本进行两种操作:
    Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
    Paste (粘贴) : 你可以粘贴你上一次复制的字符。
    给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 ‘A’。输出能够打印出 n 个 ‘A’ 的最少操作次数。

设:dp[i]表示得到i个A所需要的操作数,则我们的目的是求dp[n]
状态转移方程:dp[i] = dp[j] + dp[i/j] (j是一个小于i的数,且能被i整除,其实就是i的因数,注意把j==1的情况排除掉)

class Solution {
    
    
public:
    int minSteps(int n) {
    
    
        vector<int> dp(n + 1, 0);

        for (int i = 2; i <= n; i++)
        {
    
    
            dp[i] = i;
            /* 这里的j不需要写成j <= i,因为判断j是不是因数只要检查到开平方的大小就好了,算是个小优化> */
            for (int j = 2; j * j <= i; j++)
            {
    
    
                if (i % j == 0)
                    dp[i] = dp[j] + dp[i / j];
            }
        }

        return dp[n];
    }
};


猜你喜欢

转载自blog.csdn.net/u013354486/article/details/115922525