【LeetCode周赛】第 390 场周赛

文章介绍了四个编程问题,涉及字符串处理(最长子串每个字符出现两次、执行操作使元素和大于等于K),数据结构(最高频率ID)以及字符串搜索(最长公共后缀查询)。展示了C++和Python两种语言的解决方案,强调了贪心策略、数据结构选择(如哈希表、优先队列)在解决这类问题中的应用。
摘要由CSDN通过智能技术生成

3090. 每个字符最多出现两次的最长子字符串 简单

3090. 每个字符最多出现两次的最长子字符串

分析:
数据量,按照题意模拟即可。
这里我是用了 前缀和 记录了 0~i 的所有字母出现的次数。

代码:

C++

class Solution {
public:
    int maximumLengthSubstring(string s) {
        int n=s.length();
        vector<vector<int>> cnt(n+1,vector<int>(26,0));
        for(int i=0;i<n;i++){
            cnt[i+1][s[i]-'a']++;
            for(int j=0;j<26;j++) cnt[i+1][j]+=cnt[i][j];
        }
        for(int i=n;i>1;i--){
            for(int j=0;j+i<=n;j++){
                int k=0;
                for(;k<26;k++){
                    if(cnt[j+i][k]-cnt[j][k]>2) break;
                }
                if(k==26) return i;
            }
        }
        return 1;
    }
};

python

class Solution:
    def maximumLengthSubstring(self, s: str) -> int:
        cnt = [[0] * 216 for i in range(len(s)+1)]
        for i in range(len(s)):
            cnt[i+1][ord(s[i]) - ord('a')]+=1
            for j in range(26):
                cnt[i+1][j] += cnt[i][j]

        for i in range(len(s),1,-1):
            for j in range(0,len(s)-i+1):
                flag = True
                for k in range(26):
                    if cnt[i+j][k] - cnt[j][k]>2:
                        flag=False
                        break
                if flag:
                    return i
        return 1


3091. 执行操作使数据元素之和大于等于 K 中等

3091. 执行操作使数据元素之和大于等于 K

分析:

法一
贪心+找规律
在固定的操作次数 l l l 下,先进行 ⌊ l / 2 ⌋ \lfloor l/2 \rfloor l/2 次操作一,再进行 l − ⌊ l / 2 ⌋ l - \lfloor l/2 \rfloor ll/2 操作二,即可得到最大的元素之和。
规律如下:

操作次数 l最大元素之和
1 1 1 1 ∗ 2 = 2 1 * 2 = 2 12=2
2 2 2 2 ∗ 2 = 4 2 * 2 = 4 22=4
3 3 3 2 ∗ 3 = 6 2 * 3 = 6 23=6
4 4 4 3 ∗ 3 = 9 3 * 3 = 9 33=9
5 5 5 3 ∗ 4 = 12 3 * 4 = 12 34=12
6 6 6 4 ∗ 4 = 16 4 * 4 = 16 44=16

最终依照此规律,寻找最小的大于 k 的操作次数。

法二
贪心+枚举
先加,后复制得到的数更大。
最多进行 k-1 次加法,此时是操作次数最大的情况,枚举 1~k-1 次加法,再计算后续还需要多少次复制,维护最小操作数即可。

代码:

法一
C++

class Solution {
public:
    int minOperations(int k) {
        if(k==0||k==1) return 0;
        int cnt=1,a=1,b=2;
        while(a*b<k){
            if(a<b) a++;
            else b++;
            cnt++;
        }
        return cnt;
    }
};

python

class Solution:
    def minOperations(self, k: int) -> int:
        if k==1 or k==0:
            return 0
        cnt,a,b=1,1,2
        while a*b<k:
            if a<b:
                a+=1
            else:
                b+=1
            cnt+=1
        return cnt

法二法二

3092. 最高频率的 ID 中等

3092. 最高频率的 ID

分析:
寻找每次操作后,出现频率最高的数即可。
题目难点在于,在每次操作之后怎么寻找当前出现频率最高的数。

  • 遍历的话,数据量大一定超时。
  • 利用语言自带的工具
    • 哈希表 + 可重复的有序集合:c++中的 multiset ,python中的 SortedList
    • 哈希表 + 优先队列 + 懒删除堆

懒删除堆:因为优先队列不能查找,因此对于并非队首或队尾的元素,我们无法操作。可以使用 哈希表 维护当前的ID出现的次数,并将修改后的ID即其出现次数放入优先队列。同时对比优先队列队首的ID出现次数,与当前不符,就弹出。

代码:

哈希表 + 可重复的有序集合
C++

class Solution {
public:
    vector<long long> mostFrequentIDs(vector<int>& nums, vector<int>& freq) {
        unordered_map<int ,long long> m;
        multiset<long long> s;
        vector<long long> ans;
        m[nums[0]]+=1LL*freq[0];
        s.emplace(1LL*freq[0]);
        ans.push_back(1LL*freq[0]);
        for(int i=1;i<nums.size();i++){
            long long t = m[nums[i]];
            m[nums[i]]+=1LL*freq[i];
            auto it = s.find(t);
            if(it != s.end()){
                s.erase(it); // 删除集合中的一个 t
            }
            s.insert(m[nums[i]]);
            ans.push_back(*s.rbegin()); // 有序集合,s.rbegin() 即为最大的出现次数
        }
        return ans;
    }
};

python

from sortedcontainers import SortedList
class Solution:
    def mostFrequentIDs(self, nums: List[int], freq: List[int]) -> List[int]:
        cnt = Counter()
        s = SortedList()
        ans = []
        for x,f in zip(nums, freq):
            t = cnt[x]
            s.discard(t)
            cnt[x]+=f
            s.add(cnt[x])
            ans.append(s[-1])
        return ans

哈希表 + 优先队列 + 懒删除堆
C++

class Solution {
public:
    vector<long long> mostFrequentIDs(vector<int>& nums, vector<int>& freq) {
        unordered_map<int ,long long> m;
        priority_queue<pair<long long, int>> q;
        vector<long long> ans;
        m[nums[0]]+=1LL*freq[0];
        q.emplace(m[nums[0]], nums[0]);
        ans.push_back(1LL*freq[0]);
        for(int i=1;i<nums.size();i++){
            long long t = m[nums[i]];
            m[nums[i]]+=1LL*freq[i];
            q.emplace(m[nums[i]], nums[i]); // 不断的将修改后的 ID 及其 对应的出现次数 加入优先队列
            // 如下循环 实现 懒删除堆
            while(m[q.top().second] != q.top().first) q.pop(); // 与当前 ID 的出现次数不符合,弹出优先队列
            ans.push_back(q.top().first);
        }
        return ans;
    }
};

python

class Solution:
    def mostFrequentIDs(self, nums: List[int], freq: List[int]) -> List[int]:
        cnt = Counter()
        h = []
        ans = []
        for x,f in zip(nums, freq):
            cnt[x]+=f
            heapq.heappush(h, (-cnt[x], x))
            while -h[0][0] != cnt[h[0][1]]:
                heapq.heappop(h)
            ans.append(-h[0][0])
        return ans


3093. 最长公共后缀查询 困难

3093. 最长公共后缀查询

分析:
构建基于字符串后缀的字典树,并且不断维护对应下标,后续不断在字典树上查找即可。
注意数组的使用,容易内存超限。
同时注意当没有后缀与其匹配是,需要填入最短字符串的下标、

构建字典树模板:CPP
构建字典树模板:Python

代码:

C++

class Node{
public:
    int index=-1;
    Node* next[26]{};
};

class Solution {
public:
    vector<int> stringIndices(vector<string>& wordsContainer, vector<string>& wordsQuery) {
        int n=wordsContainer.size(),m=wordsQuery.size(),d=1e4+5,dindex=-1;
        vector<int> ans;
        Node* root = new Node();
        for(int i=0;i<n;i++){
            int l=wordsContainer[i].length();
            if(d>l) d=l,dindex=i;
            Node* node = root;
            for(int j=l-1;j>=0;j--){
                int k = wordsContainer[i][j]-'a';
                if(!node->next[k]) node->next[k] = new Node();
                node = node->next[k];
                if(node->index==-1) node->index=i;
                else{
                    if(wordsContainer[node->index].length()>l) node->index=i;
                }
            }
        }
        for(int i=0;i<m;i++){
            Node* node = root;
            int l=wordsQuery[i].length();
            int index=-1;
            for(int j=l-1;j>=0;j--){
                int k = wordsQuery[i][j]-'a';
                if(!node->next[k])break;
                node=node->next[k];
                index=node->index;
            }
            ans.push_back(index!=-1?index:dindex);
        }
        return ans;
    }
};

python

class Node:
    def __init__(self) -> None:
        self.children = [None] * 26
        self.index = -1

class Solution:
    def stringIndices(self, wordsContainer: List[str], wordsQuery: List[str]) -> List[int]:
        n,m = len(wordsContainer), len(wordsQuery)
        d,d_index = len(wordsContainer[0]),0
        ans = []
        def build_trie() -> Node: # 构建字典树
            nonlocal wordsContainer,d,d_index
            root = Node()
            for i in range(n):
                l=len(wordsContainer[i])
                if d>l:
                    d=l
                    d_index=i
                node = root
                for j in range(l-1, -1, -1):
                    k = ord(wordsContainer[i][j]) - ord('a') # 字母转换成下标
                    if node.children[k] == None:
                        node.children[k] = Node()
                    node = node.children[k]
                    if node.index == -1: # 更新更优下标
                        node.index = i
                    else:
                        node.index = i if len(wordsContainer[node.index]) > l else node.index
            return root
        root = build_trie()
        def find_word(s: str):
            nonlocal root
            node = root
            index = -1
            for i in range(len(s)-1,-1,-1):
                k = ord(s[i]) - ord('a')
                if node.children[k]==None:
                    break
                node = node.children[k]
                index = node.index
            return index
        for i in range(m):
            t = find_word(wordsQuery[i])
            ans.append(t if t!=-1 else d_index)
        return ans
  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 第一题是个简单的两数之和问题:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 可以使用暴力枚举的方法,复杂度为 O(n^2)。 也可以使用哈希表存储数组中的数,复杂度为 O(n)。 代码如下: ``` class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hash; vector<int> res; for (int i = 0; i < nums.size(); i ++) { int complement = target - nums[i]; if (hash.count(complement)) { res.push_back(hash[complement]); res.push_back(i); break; } hash[nums[i]] = i; } return res; } }; ``` ### 回答2: LeetCode的第一题是"两数之和",题目要求给定一个整数数组和一个目标值,找出数组中和为目标值的两个整数的索引。 解决这个问题可以使用哈希表来完成,具体步骤如下: 1. 创建一个哈希表,用于存储数组中的元素及其索引。 2. 遍历数组,对于每个元素,判断目标值与当前元素的差值是否在哈希表中存在。 3. 如果存在差值,则说明当前元素与差值之和为目标值,返回这两个元素的索引。 4. 如果不存在差值,将当前元素及其索引加入哈希表中,继续遍历下一个元素。 以下是解题的示例代码: ```python def twoSum(nums, target): hashmap = {} for i, num in enumerate(nums): complement = target - num if complement in hashmap: return [hashmap[complement], i] hashmap[num] = i ``` 该方法的时间复杂度为O(n),空间复杂度也为O(n),其中n是数组的长度。 这是解决LeetCode第一题的一种简单有效的方法,通过使用哈希表来记录元素及其索引的对应关系,可以快速找到数组中是否存在和为目标值的两个整数,并返回它们的索引。 ### 回答3: 解决LeetCode的第一题,即两数之和(Two Sum)问题,可以采取以下步骤: 1. 首先,理解题目要求:给定一个整数数组nums和一个目标值target,需要在数组中找出两个数的和等于目标值,并返回这两个数的索引。 2. 接下来,可以使用一种简单的方法,即遍历数组。设置一个哈希表(字典),用于存储已经遍历过的元素和其对应的索引。 3. 在遍历数组的过程中,对于每个元素num,计算目标值target与当前元素的差值diff。 4. 检查该差值diff是否存在于哈希表中。如果存在,说明已经找到了两个数的和等于目标值,可以返回它们的索引。 5. 如果没有找到,则将当前元素及其索引添加到哈希表中,继续遍历数组。 6. 最后,如果遍历完整个数组都没有找到符合条件的两个数,则说明输入数组不满足题目要求,可以返回一个空数组或其他指定的值。 通过以上步骤,我们可以得到两数之和的解决方案。这个方法的时间复杂度为O(n),其中n是输入数组的长度,因为我们只需要遍历数组一次,并将元素存入哈希表中。空间复杂度也为O(n),用于存储哈希表中的元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值