力扣:第 320 场周赛

180 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

第 320 场周赛 - 力扣(LeetCode)

2475. 数组中不等三元组的数目

问题解析

因为数组长度才100,直接用三层for循环枚举i,j,k,记录nums[i]和nums[j]和nums[k]都不相同的个数即可。

AC代码

class Solution {
public:
    int unequalTriplets(vector<int>& nums) {
        int n=nums.size(),cnt=0;
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
                for(int k=j+1;k<n;k++)
                    if(nums[i]!=nums[j]&&nums[j]!=nums[k]&&nums[i]!=nums[k])
                        cnt++;
        return cnt;
    }
};

2476. 二叉搜索树最近节点查询

问题解析

注意,题目说的此树是一个二叉搜索树,二叉搜索树的特点就是,root的左孩子小于root,右孩子大于root。

由于这个特点,它的中序序列是一个单调递增的数组,我们可以先中序遍历二叉搜索树并将它的中序序列记录下来,之后每次询问直接二分查找即可。

AC代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int>v;
    void dfs(TreeNode*root)
    {
        if(!root)return;
        dfs(root->left);
        v.push_back(root->val);
        dfs(root->right);
    }
    vector<vector<int>> closestNodes(TreeNode* root, vector<int>& queries) {
        dfs(root);
        vector<vector<int>>res;
        for(auto&i:queries)
        {
            vector<int>ans;
            int l=0,r=v.size()-1;
            while(l<r)
            {
                int mid=(l+r+1)/2;
                if(v[mid]<=i)l=mid;
                else r=mid-1;
            }
            if(v[l]<=i)
                ans.push_back(v[l]);
            else ans.push_back(-1);
            l=0,r=v.size()-1;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(v[mid]>=i)r=mid;
                else l=mid+1;
            }
            if(v[l]>=i)
                ans.push_back(v[l]);
            else ans.push_back(-1);
            res.push_back(ans);
        }
        return res;
    }
};

2477. 到达首都的最少油耗 - 力扣(LeetCode)

问题解析

从示例二中我们就能看出,最好的做法就是每个城市的车尽量坐满人后再前往下个城市。

  • 先按照边建树,我们以0为根dfs整个树;
  • 因为是以0为起点,所以我们先走到叶子处后,回头的路上再记录汽油;
  • 每次把一整个城市的人一起移动到下一个城市,而不是一个一个的直接送到首都。

AC代码

class Solution {
public:
    typedef long long ll;
    vector<int>tree[100050];
    ll f[100050],cnt=0,up;
    void dfs(int x,int y)
    {
        for(auto&i:tree[x])
        {
            if(i==y)continue;
            dfs(i,x);
            f[x]+=f[i];
        }
        if (x == 0)return;
        if(f[x]%up==0)cnt+=f[x]/up;
        else cnt+=f[x]/up+1;
    }
    long long minimumFuelCost(vector<vector<int>>& roads, int seats) {
        int n=roads.size();
        for(int i=1;i<=n;i++)f[i]=1;
        for(auto&i:roads)
        {
            tree[i[0]].push_back(i[1]);
            tree[i[1]].push_back(i[0]);
        }
        up=seats;
        dfs(0,-1);
        return cnt;
    }
};

2478. 完美分割的方案数 - 力扣(LeetCode)

问题解析

很容易看出的线性dp。

设立二维状态转移数组f,f[i] [j]表示:以第i个字符为结尾,且当前是分割出的第j段的方案数,结果就是f[n] [k]。

  1. 如果第i个数是一个非质数,且它后面的数字是一个质数(或者这个数就是最后一个数了),那么这个数就是一个合格的结尾。
  2. 我们在前i-minLength个数(因为切割出的字段长度要为minLength)里找所有的质数来作这一段切割的开头。
  3. 假如第x个数是质数,那么就有状态转移方程:f[i] [j]+= f[x-1] [j-1];

但是,我们枚举结尾复杂度是O(n),枚举结尾同时寻找开头复杂度也是O(n),找到了开头还要滚动k,这样总的复杂度是O(n*n *k);显然不太行,所以我们要优化一下:

可以注意到实际上,我们滚动k的过程中,就是把前i-minLength个数分割的结果加到第i个数上。那么我们可以用一个前缀和数组记录下之前的所有结果,这样就可以不用往前一个个找质数了。

AC代码

class Solution {
public:
    int MOD=1e9+7;
    long long f[1050][1050],a[1050],sum[1050][1050];
    int beautifulPartitions(string s, int k, int minLength) {
        unordered_map<int, int>mymap;
        map<int, int>pos;
        mymap[2] = mymap[3] = mymap[5] = mymap[7] = 1;
        if (!mymap.count(s[0] - '0'))return 0;
        int n = s.size();
        for (int i = 1; i <= n; i++)
            a[i] = s[i - 1] - '0';
        f[0][0] = 1;
        sum[0][0] = 1;
        for (int i = 1; i <= n; i++)
        {
            if (i>=minLength&&!mymap.count(a[i])&&(i==n||mymap.count(a[i+1])))
            {
                for(int j=1;j<=k;j++)
                    f[i][j]=(f[i][j]+sum[i-minLength][j-1])%MOD;
            }
            
            for (int j = 0; j < k; j++)
            {
                sum[i][j] = (sum[i-1][j] + f[i][j]) % MOD;
            }
        }
        return f[n][k] % MOD;
    }
};