LeetCode冲刺:Day17

发布于 2022-11-24  1067 次阅读


1. 不同的平均值数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

模拟即可。

代码

class Solution {
public:
    int distinctAverages(vector<int>& nums) {
        map<double,int> mp;
        sort(nums.begin(),nums.end());
        int ans=0;
        for (int i = 0, j = nums.size() - 1; i < j; ++i, --j) {
            if (mp[double(nums[i]+nums[j])/2.0]!=1) {
                mp[double(nums[i]+nums[j])/2.0]=1;
                ++ans;
            }
        }
        return ans;
    }
};

2. 统计构造好字符串的方案数

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

先试了下暴力回溯,果然超时。

然后画了会儿草稿发现,这不就是背包问题吗!zero和one是物品,可以无限取用,字符串长度是容量,只要遍历0到high每个容量下装满背包的方案数,再把low到high区间的方案数累加,就得到答案。且这是一个完全背包求排列数的问题。于是使用 一维数组,先遍历背包容量,再遍历物品,且都是从前向后遍历。

看了题解才发现,准确来说这是个爬楼梯问题……一次遍历即可。

代码

class Solution {
public:
    int countGoodStrings(int low, int high, int zero, int one) {
        vector<long> dp(high+1, 0);
        vector<int> item(2);
        int MOD=1e9+7;
        item[0] = zero;
        item[1] = one;
        dp[zero] += 1;
        dp[one] += 1;
        for (int i = 1; i <= high; ++i) {
            for (int j = 0; j < 2; ++j) {
                if(i >= item[j]) {
                    dp[i] += dp[i-item[j]]%MOD;
                }
            }
        }
        int ans = 0;
        for (int i = low; i <= high; ++i) ans=(ans + dp[i])%MOD;
        return ans;
    }
};

3. 树上最大得分和路径

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

参考这篇

代码

class Solution {
private:
    bool findBob(vector<int>& bobInfo, vector<vector<int>>& pic, int cur, int before, int bobTime) {
        if (cur==0) {
            bobInfo[cur]=0;
            return true;
        }
        bool found=false;
        int n=pic.size();
        // 遍历图,找到bob到0的路径
        for (int i = 0; i < pic[cur].size(); ++i) {
            int index=pic[cur][i];
            if (index!=before&&findBob(bobInfo, pic, index, cur, bobTime+1)) {
                found=true;
                break;
            }
        }
        if (found) bobInfo[cur] = bobTime;
        return found;
    }

    void dfs(int cur, int before, int score, int& maxScore, vector<vector<int>>& pic, int aliceTime, vector<int>& bobInfo, vector<int>& amount) {
        if (bobInfo[cur]==aliceTime) {
            score += amount[cur] / 2;
        } else if (bobInfo[cur] > aliceTime) {
            score += amount[cur];
        }
        if (pic[cur].size() == 1) maxScore = max(maxScore, score);
        for (int i = 0; i < pic[cur].size(); ++i) {
            int index = pic[cur][i];
            if (index != before) {
                dfs(index, cur, score, maxScore, pic, aliceTime + 1, bobInfo, amount);
            }
        }
    }
public:
    int mostProfitablePath(vector<vector<int>>& edges, int bob, vector<int>& amount) {
        vector<vector<int>> pic(amount.size());
        for (auto& edge:edges) {
            pic[edge[0]].push_back(edge[1]);
            pic[edge[1]].push_back(edge[0]);
        }

        vector<int> bobInfo(amount.size(),amount.size());
        findBob(bobInfo, pic, bob, -1, 0);

        pic[0].push_back(-1);
        int ans = INT_MIN;
        dfs(0, -1, 0, ans, pic, 0, bobInfo, amount);
        return ans;
    }
};

4. 矩阵中的局部最大值

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

前两层遍历是确定左上角元素的行列值,内部两层循环是遍历方才确定的33矩阵。

代码

class Solution {
public:
    vector<vector<int>> largestLocal(vector<vector<int>>& grid) {
        vector<vector<int>> ans;
        vector<int> row;
        int n = grid.size();
        for (int i = 0; i < n - 2; ++i) {
            row.clear();
            for (int j = 0; j < n - 2; ++j) {
                int maxNum=INT_MIN;
                for (int k = i; k < i + 3; ++k) {
                    for (int l = j; l < j + 3; ++l) {
                        maxNum=max(maxNum, grid[k][l]);
                    }
                }
                row.push_back(maxNum);
                maxNum=INT_MIN;
            }
            ans.push_back(row);
        }
        return ans;
    }
};

5. 边积分最高的节点

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

积分用LL防止溢出,实际难度应该是Easy。

代码

class Solution {
public:
    int edgeScore(vector<int>& edges) {
        int n = edges.size();
        vector<long long> score(n,0);
        for (int i = 0; i < n; ++i) score[edges[i]] += i;
        int ans=-1;
        long long maxScore=LONG_LONG_MIN;
        for (int i = n - 1; i >= 0; --i) {
            if (score[i] >= maxScore) {
                maxScore = score[i];
                ans = i;
            }
        }
        return ans;
    }
};

6. 根据模式串构造最小数字

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

代码

class Solution {
public:
    string smallestNumber(string pattern) {
        int i = 0, n = pattern.length();
        char cur = '1';
        string ans(n + 1, 0);
        while (i < n) {
            if (i && pattern[i] == 'I') ++i;
            for (; i < n && pattern[i] == 'I'; ++i) ans[i] = cur++;
            int i0 = i;
            while (i < n && pattern[i] == 'D') ++i;
            for (int j = i; j >= i0; --j) ans[j] = cur++;
        }
        return ans;
    }
};

7. 算术三元组的数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

确定第一个元素之后,第二三个元素值就确定了,用map保存元素的存在情况。

代码

class Solution {
public:
    int arithmeticTriplets(vector<int>& nums, int diff) {
        map<int,int> mp;
        for (auto& num : nums) mp[num] = 1;
        int ans = 0;
        for (auto& num : nums) if (mp[num + diff] == 1 && mp[num + diff*2] == 1) ++ans;
        return ans;
    }
};

8. 受限条件下可到达节点的数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

这类图的题目有基本的方法概念了。

代码

class Solution {
private:
    int ans=0;
    void dfs(vector<vector<int>>& pic, int cur, int before, map<int,int>& mp) {
        // 受限则直接返回
        if (mp[cur] == 1) return;
        // 不受限,说明可达,计数加一
        ++ans;
        // 如果是叶子结点,返回
        if (pic[cur].size() == 1) return;
        else {
            // 非叶子结点,遍历连接的其他结点
            for (int i = 0; i < pic[cur].size(); ++i) {
                int index = pic[cur][i];
                if (index != before) dfs(pic, index, cur, mp);
            }
        }
    }
public:
    int reachableNodes(int n, vector<vector<int>>& edges, vector<int>& restricted) {
        // 建图
        vector<vector<int>> pic(n);
        for (auto& edge : edges) {
            pic[edge[0]].push_back(edge[1]);
            pic[edge[1]].push_back(edge[0]);
        }
        // 将受限结点存入map,便于查询
        map<int,int> mp;
        for (auto& elem : restricted) mp[elem] = 1;
        // 防止首结点被识别为叶子
        pic[0].push_back(-1);
        ans = 0;
        dfs(pic, 0, -1, mp);
        return ans;
    }
};

9. 检查数组是否存在有效划分

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

看到划分就想到子问题,于是想到DP。

代码

class Solution {
public:
    bool validPartition(vector<int>& nums) {
        int n = nums.size();
        vector<bool> dp (n+1,false);
        dp[0] = true;

        for (int i = 1; i <= n; ++i) {
            if (i >= 2 && dp[i - 2] && nums[i - 1] == nums[i - 2]) dp[i] = true;
            if (i >= 3 && dp[i - 3] && ((nums[i - 1] == nums[i-2] && nums[i -2] == nums[i - 3])||(nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1))) dp[i] = true;
        }
        return dp[n];
    }
};

10. 最长理想子序列

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

一眼认出来是DP,但自己写的n的平方的DP超时了。看了这篇才知道,原来对于字符串的题目,有一个枚举套路。对于本题,可以将每个位置间递推,抽象成每个字母递推。即将DP数组设定为以下标为结尾的最长序列,变成以某字符为结尾的最长序列。前者依赖于字符串长,而后者是依据可取字符串的范围,即k。

代码

class Solution {
public:
    int longestIdealString(string s, int k) {
        // int n = s.size();
        // vector<int> dp(n, 1);
        // int ans = INT_MIN;
        // for (int i = 1; i < n; ++i) {
        //     for (int j = 0; j < i; ++j) {
        //         if (s[i] - s[j] <= k && s[i] - s[j] >= -k) dp[i] = dp[i] > dp[j] + 1 ? dp[i] : dp[j] + 1;
        //         ans = ans > dp[i] ? ans : dp[i];
        //     }
        // }
        // return ans;
        vector<int> dp(26);
        int ans = INT_MIN;
        for (char ch : s) {
            ch -= 'a';
            dp[ch] = 1 + *max_element(dp.begin() + max(ch - k, 0), dp.begin() + min(ch + k + 1, 26));
            ans = ans > dp[ch] ? ans : dp[ch];
        }
        return ans;

    }
};