leetcode 235周赛

竞赛链接:第 235 场周赛 - 力扣(LeetCode) (leetcode-cn.com)

 

题目一:

1816. 截断句子

题目描述及示例:

句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

例如,"Hello World""HELLO""hello world hello world" 都是句子。
给你一个句子 s​​​​​​ 和一个整数 k​​​​​​ ,请你将 s​​ 截断 ​,​​​使截断后的句子仅含 前 k​​​​​​ 个单词。返回 截断 s​​​​​​ 后得到的句子。

 

示例 1:

输入:s = "Hello how are you Contestant", k = 4
输出:"Hello how are you"
解释:
s 中的单词为 ["Hello", "how" "are", "you", "Contestant"]
前 4 个单词为 ["Hello", "how", "are", "you"]
因此,应当返回 "Hello how are you"
示例 2:

输入:s = "What is the solution to this problem", k = 4
输出:"What is the solution"
解释:
s 中的单词为 ["What", "is" "the", "solution", "to", "this", "problem"]
前 4 个单词为 ["What", "is", "the", "solution"]
因此,应当返回 "What is the solution"
示例 3:

输入:s = "chopper is not a tanuki", k = 5
输出:"chopper is not a tanuki"
 

提示:

1 <= s.length <= 500
k 的取值范围是 [1,  s 中单词的数目]
s 仅由大小写英文字母和空格组成
s 中的单词之间由单个空格隔开
不存在前导或尾随空格

 

代码:

class Solution {
public:
    string truncateSentence(string s, int k) {
        int n = 1;
        string ans;
        for(char x : s)
        {
            if(x == ' ')
            {
                if(n < k)
                    n++;
                else
                    break;
            }
            ans += x;     
        }
        return ans;
    }
};

 

 

 

 

题目二:

1817. 查找用户活跃分钟数

 

题目描述及示例:

给你用户在 LeetCode 的操作日志,和一个整数 k 。日志用一个二维整数数组 logs 表示,其中每个 logs[i] = [IDi, timei] 表示 ID 为 IDi 的用户在 timei 分钟时执行了某个操作。

多个用户 可以同时执行操作,单个用户可以在同一分钟内执行 多个操作 。

指定用户的 用户活跃分钟数(user active minutes,UAM) 定义为用户对 LeetCode 执行操作的 唯一分钟数 。 即使一分钟内执行多个操作,也只能按一分钟计数。

请你统计用户活跃分钟数的分布情况,统计结果是一个长度为 k 且 下标从 1 开始计数 的数组 answer ,对于每个 j(1 <= j <= k),answer[j] 表示 用户活跃分钟数 等于 j 的用户数。

返回上面描述的答案数组 answer 。

 

示例 1:

输入:logs = [[0,5],[1,2],[0,2],[0,5],[1,3]], k = 5
输出:[0,2,0,0,0]
解释:
ID=0 的用户执行操作的分钟分别是:525 。因此,该用户的用户活跃分钟数为 2(分钟 5 只计数一次)
ID=1 的用户执行操作的分钟分别是:23 。因此,该用户的用户活跃分钟数为 2
2 个用户的用户活跃分钟数都是 2 ,answer[2] 为 2 ,其余 answer[j] 的值都是 0
示例 2:

输入:logs = [[1,1],[2,2],[2,3]], k = 4
输出:[1,1,0,0]
解释:
ID=1 的用户仅在分钟 1 执行单个操作。因此,该用户的用户活跃分钟数为 1
ID=2 的用户执行操作的分钟分别是:23 。因此,该用户的用户活跃分钟数为 2
1 个用户的用户活跃分钟数是 11 个用户的用户活跃分钟数是 2 
因此,answer[1] = 1 ,answer[2] = 1 ,其余的值都是 0
 

提示:

1 <= logs.length <= 104
0 <= IDi <= 109
1 <= timei <= 105
k 的取值范围是 [用户的最大用户活跃分钟数, 105]

 

题目分析:

用哈希表找人和分钟的对应关系使用集合记录活跃人数

 

代码:

class Solution {
public:
    vector<int> findingUsersActiveMinutes(vector<vector<int>>& logs, int k) {
        unordered_map<int,unordered_set<int>> record;
        for(vector<int> us : logs){
            record[us[0]].insert(us[1]);
        }
        
        vector<int> res(k,0);
        for(auto it = record.begin();it!=record.end();it++){
            res[it->second.size()-1]++;
        }
        return res;
    }
};

 

 

 

 

 

题目三:

1818. 绝对差值和

 

题目描述及示例:

给你两个正整数数组 nums1 和 nums2 ,数组的长度都是 n 。

数组 nums1 和 nums2 的 绝对差值和 定义为所有 |nums1[i] - nums2[i]|(0 <= i < n)的 总和(下标从 0 开始)。

你可以选用 nums1 中的 任意一个 元素来替换 nums1 中的 至多 一个元素,以 最小化 绝对差值和。

在替换数组 nums1 中最多一个元素 之后 ,返回最小绝对差值和。因为答案可能很大,所以需要对 109 + 7 取余 后返回。

|x| 定义为:

如果 x >= 0 ,值为 x ,或者
如果 x <= 0 ,值为 -x
 

示例 1:

输入:nums1 = [1,7,5], nums2 = [2,3,5]
输出:3
解释:有两种可能的最优方案:
- 将第二个元素替换为第一个元素:[1,7,5] => [1,1,5] ,或者
- 将第二个元素替换为第三个元素:[1,7,5] => [1,5,5]
两种方案的绝对差值和都是 |1-2| + (|1-3| 或者 |5-3|) + |5-5| = 3
示例 2:

输入:nums1 = [2,4,6,8,10], nums2 = [2,4,6,8,10]
输出:0
解释:nums1 和 nums2 相等,所以不用替换元素。绝对差值和为 0
示例 3:

输入:nums1 = [1,10,4,4,2,7], nums2 = [9,3,5,1,7,4]
输出:20
解释:将第一个元素替换为第二个元素:[1,10,4,4,2,7] => [10,10,4,4,2,7]
绝对差值和为 |10-9| + |10-3| + |4-5| + |4-1| + |2-7| + |7-4| = 20
 

提示:

n == nums1.length
n == nums2.length
1 <= n <= 105
1 <= nums1[i], nums2[i] <= 105

 

题目分析:

使用 数列一 中的的一个数 替换 数列一中的一个数,只允许替换一次。要求|nums1[i] - nums2[i]|0 <= i < n)的 总和(下标从 0 开始)最小。

首先替换数列一中最大的数不一定结果最小。

要找数列一对应数列二中的数,在数列一中最接近的数。而且要求其差值最大话,才能使结果最小。

可以使用set中内置的二分查找方法lower_bound(),寻找nums1中最接近的nums2[i]的数;

时间复杂度:O(nlogn)

代码:

class Solution {
    typedef long long ll;
    const int mod = 10e9 + 7;
public:
    int minAbsoluteSumDiff(vector<int>& nums1, vector<int>& nums2) {
    
    set<ll>a;
    ll n = nums1.size(), max_n = 0;
    ll ans = 0;
    ll tem1, tem2;
    set<ll>::iterator flag1;
    for (int i = 0;i < n;i++)
    {
        ans = ans + abs(nums1[i] - nums2[i]);
        a.emplace(nums1[i]);
    }
    for (int i = 0;i < n;i++)
    {
        flag1 = a.lower_bound(nums2[i]);
        tem1 = abs(nums1[i] - nums2[i]);
        tem2 = abs(nums2[i] - *flag1);
        if (flag1 != a.end())
            max_n = max(tem1 - tem2, max_n);
        if (flag1 != a.begin())
            max_n = max(tem1 - abs(nums2[i] - *--flag1), max_n);
    }
    return (ans - max_n) %mod;
    }
};

 

 

 

 

 

题目四:

1819. 序列中不同最大公约数的数目

 

题目描述及示例:

给你一个由正整数组成的数组 nums 。

数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。

例如,序列 [4,6,16] 的最大公约数是 2 。
数组的一个 子序列 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。

例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。
计算并返回 nums 的所有 非空 子序列中 不同 最大公约数的 数目 。

 

示例 1:


输入:nums = [6,10,3]
输出:5
解释:上图显示了所有的非空子序列与各自的最大公约数。
不同的最大公约数为 610321 。
示例 2:

输入:nums = [5,15,40,5,6]
输出:7
 

提示:

1 <= nums.length <= 105
1 <= nums[i] <= 2 * 105

 

题目分析:

首先需要找到数列中最大的数,应标记所有数,让结果ANS++(单个数的最大公因数一定是自己) 

题目是要求所有子序列的最大公约数去重后的个数,观察数量级,肯定不能枚举所有子序列,因此我们可以从另一个角度出发,枚举所有可能的最大公约数,判断是否为某个子序列的公约数。
因此,我们要解决的问题就是如何判断一个数是否为某个子序列的公约数。
我们可以采用类似素数筛的方式,枚举每一个数i,判断 “数列中存在的” 2i、3i、4*i…..的公约数是否为i,如果为i,则贡献加一。
筛法的复杂度为n/1 + n/2 + n/3 + … + n/n,渐进为O(n * logn),而gcd的复杂度为O(logn),所以总复杂度为O(n * logn * logn)。

作者:simpleqin

代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>
#include <set>
using namespace std;
int gcd(int a, int b)//a < b
{
    while (a % b)
        b ^= a ^= b ^= a %= b;
    return b;
}
int main()
{
    vector<int>nums = { 6, 10, 3 };
    int max = 0;
    int ans = 0;
    bool temp[1000];
    fill(temp, temp + 1000, false);
    for (int x : nums)//找出nums中的最大值并标记所有值
    {
        if (max < x)
            max = x;
        if(temp[x] == false)
        {
            ans++;
            temp[x] = true;
        }
    }

    for (int i = 1;i <= max;i++)
    {
        if (temp[i])
            continue;
        int n = 0;
        for (int j = i;j <= max;j+=i)//i和数组的数不断比较判断是否为最小公倍数
        {
            if(temp[j])
            {
                n = gcd(n, j);
                if (n == i)
                    break;
            }

        }
        if (n == i) ans++;
    }
    cout << ans;
}

 

posted @ 2021-04-05 21:40  Carrout  阅读(83)  评论(0编辑  收藏  举报