LeetCode周赛349

第一题 既不是最小值也不是最大值

题目大意

LeetCode 6470 既不是最小值也不是最大值

解析思路

注意到提示中说了数组中每个元素各不相同,所以前三个元素中必有一个满足条件。如果数组长度小于3,则不存在满足条件的数字。

代码实现
class Solution {
public:
    int findNonMinOrMax(vector<int>& nums) {
        if(nums.size()<3) return -1;
        // 对前三个元素排序后,第二个元素满足条件
        sort(nums.begin(), nums.begin()+3);
        return nums[1];
    }
};

第二题 执行子串操作后的字典序最小字符串

题目大意

LeetCode 2734. 执行子串操作后的字典序最小字符串

解题思路

注意几个前提:

  1. 恰好操作一次:不能不操作
  2. 子字符串:要求取一个连续的序列
  3. 字符替换为字母表前一个字符:a变成z会导致字典序变大,其他字符操作后可以让字典序变小

Q1: 如何选择操作的起始位置?
A1: 起始位置越靠前,能让字典序越小。从左往后找第一个不为a的字符的位置作为起始位置。
Q2: 如何选择操作的终止位置?
A2: 从起始位置往右,第一个为a的字符位置的前一个位置。
Q3: 全为a的字符串如何处理?
A3: 全为a的字符串无法通过A3中的方法找到起始位置。将最后一个a变为z可以得到字典序最小的字符串。

代码实现
class Solution {
public:
    string smallestString(string s) {
    	// flag=0表示未找到起始位置,1表示找到了起始位置,2表示找到了终止位置
        int flag = 0;
        for(int i=0;i<s.size();i++) {
            if(flag==0 && s[i]!='a') flag = 1;
            else if(flag==1 && s[i]=='a') flag = 2;
            if(flag==1) {
                s[i] = 'a' + (s[i]-'a'+25)%26;
            }
        }
        // 全为a的序列找不到起始位置,将最后一个a变为z
        if(flag == 0) s[s.size()-1] = 'z';
        return s;
    }
};

第三题 收集巧克力

题目大意

LeetCode 2735. 收集巧克力

解题思路

原数组为nums,变更后的数组为arr,最小代码数组为cost。

  1. 初始状态下 arr[i]=nums[i];
  2. 变更一次后 arr[i]=nums[(i+1+n)%n],此时第i个位置的巧克力有两个选择:被上一轮选中,或者被这一轮选中,取决于哪一轮的arr[i]最小;所以可以推断出cost[i]=min(nums[i], nums[(i+1+n)%n]);
  3. 变更k次后 arr[i]=nums[(i+k+n)%n], cost[i]=min(cost[i], nums[(i+k+n)%n])。
    最后将cost数组求和即为结果。
代码实现
class Solution {
public:
    long long minCost(vector<int>& nums, int x) {
        int n = nums.size();
        long long sum = 0;
        for(int i: nums) sum += i;
        vector<int> cost = nums;
        long long res = sum;
        // 依次计算变更k次所需代价,取最小的一个
        for(long long k=0;k<n;k++) {
            long long ans = k * x;
            for(int i=0;i<n;i++) {
                cost[i] = min(cost[i], nums[(i+k+n)%n]);
            }
            for(int i: cost) ans += i;
            res = min(res, ans);
        }
        return res;
    }
};

第四题 最大和查询

题目大意

请添加图片描述

解题思路

由于数组有两个,且每次查询都是二维的,可以联想到二维平面。
(num1[j], nums2[j])、(x[i], y[i])都可以视为二维平面的点,问题转化为求每个(x[i], y[i])右上方的点(num1[j], nums2[j])中最大和的点。

  1. 考虑到x[i], y[i], nums1[j], nums2[j]的范围在[1, 1e9],而nums1, nums2, queries的长度都在[1, 1e5],可以对x[i], y[i], nums1[j], nums2[j]进行离散化,使其范围落在[1, 1e5]区间。
  2. 对于y[i]=k多个点(x[i], k),可以用树状数组维护其右边的点(num1[j], nums2[j])的最大和。
  3. 按y[i]从大到小求出(x[i], y[i])右上的点(num1[j], nums2[j])的最大和。
代码实现
class Solution {
private:
    vector<int> tree;
public:
    vector<int> maximumSumQueries(vector<int>& nums1, vector<int>& nums2, vector<vector<int>>& queries) {
        // 离散化
        set<int> st;
        for(int i: nums1) st.insert(i);
        for(int i: nums2) st.insert(i);
        for(auto& q: queries) st.insert(q[0]), st.insert(q[1]);
        unordered_map<int, int> um;
        int size = st.size();
        // 此处倒序离散化,有两个原因:
        // 1. 坐标大的点排前面
        // 2. 树状数组求最大值时比较方便
        for(int i: st) um[i]=size--;
        size = um.size();

        vector<int> sum(nums1.size());
        for (int i = 0; i < nums1.size(); i++) {
            sum[i] = nums1[i] + nums2[i];
            nums1[i] = um[nums1[i]];
            nums2[i] = um[nums2[i]];
        }

        for (int i = 0; i < queries.size(); i++) {
            queries[i][0] = um[queries[i][0]];
            queries[i][1] = um[queries[i][1]];
        }

        tree = vector<int>(size+10, -1);
        vector<tuple<int, int, int>> vec;
        for(int i=0;i<nums1.size();i++) {
            vec.push_back({nums1[i], nums2[i], -sum[i]});
        }
        for(int i=0;i<queries.size();i++) {
            vec.push_back({queries[i][0], queries[i][1], i});
        }
        sort(vec.begin(), vec.end());

        vector<int> ans(queries.size());
        for (auto [x, y, v] : vec) {
            if (v < 0) modify(y, -v);
            else ans[v] = query(y);
        }
        return ans;
    }

    int query(int idx) {
        int res = -1;
        for (; idx; idx -= idx&(-idx)) 
            res = max(res, tree[idx]);
        return res;
    }

    void modify(int idx, int val) {
        for (; idx < tree.size(); idx += idx&(-idx)) 
            tree[idx] = max(tree[idx], val);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值