Featured image of post LeetCode第90场双周赛总结

LeetCode第90场双周赛总结

---/3624

没打

https://leetcode.cn/contest/biweekly-contest-90/

【模拟】差值数组不同的字符串

题目

给你一个字符串数组 words ,每一个字符串长度都相同,令所有字符串的长度都为 n

每个字符串 words[i] 可以被转化为一个长度为 n - 1差值整数数组 difference[i] ,其中对于 0 <= j <= n - 2difference[i][j] = words[i][j+1] - words[i][j] 。注意两个字母的差值定义为它们在字母表中 位置 之差,也就是说 'a' 的位置是 0'b' 的位置是 1'z' 的位置是 25

  • 比方说,字符串 "acb" 的差值整数数组是 [2 - 0, 1 - 2] = [2, -1]

words 中所有字符串 除了一个字符串以外 ,其他字符串的差值整数数组都相同。你需要找到那个不同的字符串。

请你返回 words差值整数数组 不同的字符串。

示例 1:

1
2
3
4
5
6
7
输入:words = ["adc","wzy","abc"]
输出:"abc"
解释:
- "adc" 的差值整数数组是 [3 - 0, 2 - 3] = [3, -1] 。
- "wzy" 的差值整数数组是 [25 - 22, 24 - 25]= [3, -1] 。
- "abc" 的差值整数数组是 [1 - 0, 2 - 1] = [1, 1] 。
不同的数组是 [1, 1],所以返回对应的字符串,"abc"。

示例 2:

1
2
3
输入:words = ["aaa","bob","ccc","ddd"]
输出:"bob"
解释:除了 "bob" 的差值整数数组是 [13, -13] 以外,其他字符串的差值整数数组都是 [0, 0] 。

提示:

  • 3 <= words.length <= 100
  • n == words[i].length
  • 2 <= n <= 20
  • words[i] 只含有小写英文字母。

解题思路

按题意模拟即可

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
    string oddString(vector<string>& words) {
        int n = words.size();
        string res,res2;
        map<string,int> tab;
        for(auto &word: words){
            char minch = *min_element(word.begin(),word.end());
            string tmp = word;
            for(auto &ch: tmp){
                ch = ch-minch+'a';
            }
            // cout<<tmp<<endl;
            tab[tmp]++;
        }
        for(auto &word: words){
            char minch = *min_element(word.begin(),word.end());
            string tmp = word;
            for(auto &ch: tmp){
                ch = ch-minch+'a';
            }
            if(tab[tmp]==1){
                res = word;
                break;
            }
        }
        return res;
    }
    
};

【枚举】距离字典两次编辑以内的单词

题目

给你两个字符串数组 queriesdictionary 。数组中所有单词都只包含小写英文字母,且长度都相同。

一次 编辑 中,你可以从 queries 中选择一个单词,将任意一个字母修改成任何其他字母。从 queries 中找到所有满足以下条件的字符串:不超过 两次编辑内,字符串与 dictionary 中某个字符串相同。

请你返回 queries 中的单词列表,这些单词距离 dictionary 中的单词 编辑次数 不超过 两次 。单词返回的顺序需要与 queries 中原本顺序相同。

示例 1:

1
2
3
4
5
6
7
8
输入:queries = ["word","note","ants","wood"], dictionary = ["wood","joke","moat"]
输出:["word","note","wood"]
解释:
- 将 "word" 中的 'r' 换成 'o' ,得到 dictionary 中的单词 "wood" 。
- 将 "note" 中的 'n' 换成 'j' 且将 't' 换成 'k' ,得到 "joke" 。
- "ants" 需要超过 2 次编辑才能得到 dictionary 中的单词。
- "wood" 不需要修改(0 次编辑),就得到 dictionary 中相同的单词。
所以我们返回 ["word","note","wood"] 。

示例 2:

1
2
3
4
5
输入:queries = ["yes"], dictionary = ["not"]
输出:[]
解释:
"yes" 需要超过 2 次编辑才能得到 "not" 。
所以我们返回空数组。

提示:

  • 1 <= queries.length, dictionary.length <= 100
  • n == queries[i].length == dictionary[j].length
  • 1 <= n <= 100
  • 所有 queries[i]dictionary[j] 都只包含小写英文字母。

解题思路

就是找不同字符的个数

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    vector<string> twoEditWords(vector<string>& queries, vector<string>& dictionary) {
        vector<string> res;
        for(auto &query: queries){
            bool flag = false;
            for(auto &words: dictionary){
                if(query.size()!=words.size()) continue;
                int diff = 0;
                for(int i=0;i<query.size();i++){
                    if(query[i]!=words[i]) diff++;
                    if(diff>2) break;
                }
                if(diff<=2) {
                    flag = true;
                    break;
                }
            }
            if(flag) res.push_back(query);
        }
        return res;
    }
};

【枚举+数学】摧毁一系列目标

题目

给你一个下标从 0 开始的数组 nums ,它包含若干正整数,表示数轴上你需要摧毁的目标所在的位置。同时给你一个整数 space

你有一台机器可以摧毁目标。给机器 输入 nums[i] ,这台机器会摧毁所有位置在 nums[i] + c * space 的目标,其中 c 是任意非负整数。你想摧毁 nums尽可能多 的目标。

请你返回在摧毁数目最多的前提下,nums[i]最小值

示例 1:

1
2
3
4
5
输入:nums = [3,7,8,1,1,5], space = 2
输出:1
解释:如果我们输入 nums[3] ,我们可以摧毁位于 1,3,5,7,9,... 这些位置的目标。
这种情况下, 我们总共可以摧毁 5 个目标(除了 nums[2])。
没有办法摧毁多于 5 个目标,所以我们返回 nums[3] 。

示例 2:

1
2
3
4
5
输入:nums = [1,3,5,2,4,6], space = 2
输出:1
解释:输入 nums[0] 或者 nums[3] 都会摧毁 3 个目标。
没有办法摧毁多于 3 个目标。
由于 nums[0] 是最小的可以摧毁 3 个目标的整数,所以我们返回 1 。

示例 3:

1
2
3
输入:nums = [6,2,5], space = 100
输出:2
解释:无论我们输入哪个数字,都只能摧毁 1 个目标。输入的最小整数是 nums[1] 。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= space <= 10^9

解题思路

nums 里的所有数按 nums[i] % space 分组。只要选择每一组里最小的数,就能摧毁整组。

和顺序无关,可以先对数组排序,第一次找到最多的即最小值

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
    int destroyTargets(vector<int>& nums, int space) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        unordered_map<int,int> tab;
        vector<int> a(nums.begin(),nums.end());
        for(auto &x: a) x = x%space;
        int maxcnt=0;
        for(int i=0;i<n;i++){
            tab[a[i]]++;
            if(tab[a[i]]>maxcnt){
                maxcnt = tab[a[i]];
            }
        }
        int res;
        for(int i=0;i<n;i++){
            if(maxcnt == tab[a[i]]){
                res = nums[i];
                break;
            }
        }
        return res;
    }
};

【单调栈+优先队列】下一个更大元素 IV

题目

给你一个下标从 0 开始的非负整数数组 nums 。对于 nums 中每一个整数,你必须找到对应元素的 第二大 整数。

如果 nums[j] 满足以下条件,那么我们称它为 nums[i]第二大 整数:

  • j > i
  • nums[j] > nums[i]
  • 恰好存在 一个 k 满足 i < k < jnums[k] > nums[i]

如果不存在 nums[j] ,那么第二大整数为 -1

  • 比方说,数组 [1, 2, 4, 3] 中,1 的第二大整数是 42 的第二大整数是 334 的第二大整数是 -1

请你返回一个整数数组 answer ,其中 answer[i]nums[i] 的第二大整数。

示例 1:

1
2
3
4
5
6
7
8
9
输入:nums = [2,4,0,9,6]
输出:[9,6,6,-1,-1]
解释:
下标为 0 处:2 的右边,4 是大于 2 的第一个整数,9 是第二个大于 2 的整数。
下标为 1 处:4 的右边,9 是大于 4 的第一个整数,6 是第二个大于 4 的整数。
下标为 2 处:0 的右边,9 是大于 0 的第一个整数,6 是第二个大于 0 的整数。
下标为 3 处:右边不存在大于 9 的整数,所以第二大整数为 -1 。
下标为 4 处:右边不存在大于 6 的整数,所以第二大整数为 -1 。
所以我们返回 [9,6,6,-1,-1] 。

示例 2:

1
2
3
4
输入:nums = [3,3]
输出:[-1,-1]
解释:
由于每个数右边都没有更大的数,所以我们返回 [-1,-1] 。

提示:

  • 1 <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^9

解题思路

如果是右侧第一个更大元素,很显然是单调栈的模板题。但之前写右侧第一个更大元素的单调栈,都是从右侧开始遍历。其实也可以从左侧遍历。从左侧遍历可能更好。

这题用单调栈的话,也需要从左侧开始遍历才好。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
    vector<int> secondGreaterElement(vector<int>& nums) {
        int n = nums.size();
        stack<int> stk;
        vector<int> R(n, -1);
        //右侧第一个更大元素的位置
        // for(int i=0;i<n;i++){
        //     while(!stk.empty() && nums[i]>nums[stk.top()]){
        //         R[stk.top()] = i;
        //         stk.pop();
        //     }
        //     stk.push(i);
        // }

        //如果是右侧第二个更大元素的位置呢
        //pq中元素 first: 值  second: 索引  堆顶元素为最小值
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
        for(int i=0;i<n;i++){
            while(!pq.empty() && nums[i]>pq.top().first){
                R[pq.top().second] = nums[i];
                pq.pop();
            }

            while(!stk.empty() && nums[i]>nums[stk.top()]){
                //nums[stk.top()]的右侧第一个更大元素为nums[i]
                //将nums[stk.top]存下来,可能有右侧第二个更大元素
                pq.emplace(nums[stk.top()],stk.top());
                stk.pop();
            }

            stk.push(i);
        }


        return R;

    }
};
Built with Hugo
Theme Stack designed by Jimmy