leetcode359周赛



leetcode359周赛_第1张图片

第四题:找出最长等值数组

  • 滑动窗口

  • 总长度 - 众数 > k就需要收缩窗口了。

  • 所以需要一个数据结构统计众数:multiset维护每一个数字的个数。

这里有一个坑ms.erase(x):会把所有的等于x的数字都删除。所以需要使用auto it = ms.find(x); ms.erase(it)来进行单个删除。

class Solution {
public:
    int longestEqualSubarray(vector<int>& nums, int k) {
        int n = nums.size();
        multiset<int>ms;
        unordered_map<int, int>cnt;
        int ans = 0;
        for (int i = 0, j = 0; j < n; j++) {   
            del(ms, cnt[nums[j]]);
            cnt[nums[j]]++;
            ms.insert(cnt[nums[j]]);
            
            int c_cnt = *(ms.rbegin());
           	// 长度 - 众数 > k收缩窗口
            while (j - i + 1 - c_cnt > k) {
                del(ms, cnt[nums[i]]);
                cnt[nums[i]]--;
                ms.insert(cnt[nums[i]]);
                i++;
                c_cnt = *(ms.rbegin());
            }
            ans = max(ans, *(ms.rbegin()));
        }
        return ans;
    }
    // 单点删除
    void del(multiset<int>&ms, int target) {
        auto it = ms.find(target);
        if (it != ms.end()) {
             ms.erase(it);
        }
    }
};

第三题:销售利润最大化

  • 排序 + 二分 + dp

  • 类似于学最多的课程,按照结尾进行排序

  • 排序之后,定义f[i]:截止到i为止的最大值,f[i] = max(f[i - 1], f[pre] + g)

  • pre是前面最后一个可以购买的下标。因为排序了所以可以使用二分找到第一个ed < cur_bg的下标pre

class Solution {
    public int maximizeTheProfit(int n, List<List<Integer>> offers) {
        // 区间最大值,可以按照开始进行排序,可以按照结尾进行排序。这里选择按照结尾进行排序
        // 如果区间相交,那么就不能进行同时购买,否则就可以进行同时购买。
        // f[i]:表示截止到区间i的最大值
        // 可以二分找到前面可以购买的第一个房间lower_boudn() - 1。f[i] = f[pre] + goal[i];
        // 状态转移是否有问题。有,截止到当前的,那么就不是以当前结尾的。如果表示当前结尾的,那么需要遍历前面所有小于它的。
        // 如果表示截至到当前的, f[i] = Math.max(f[i - 1], f[pre] + offers.get(i).get(2));
        // 第二种状态:当前可以买,可以不买,买
        offers.sort(new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                return Integer.compare(o1.get(1), o2.get(1));
            }
        });
        int len = offers.size();
        int[] f = new int[len + 1];
        
        for (int i = 1; i <= len; i++) {
            int bg = offers.get(i - 1).get(0), ed = offers.get(i - 1).get(1);
            int g = offers.get(i - 1).get(2);
            int l = 0, r = len;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (offers.get(mid).get(1) >= bg) r = mid;
                else l = mid + 1;
            }
            f[i] = Math.max(f[l] + g, f[i - 1]);
            // System.out.println("l = " + l);
            // System.out.println(f[i]);
        }
        return f[len]; 
    }
}

第二题 k-avoiding

  • 小贪心
  • 为了避免会出现和为k的情况。如果出现x就不能出现k - x,由于需要的数组和最小,所以选择min(x, k - x)
  • 由于数组和最小,所以可以直接从1开始进行取数如果选则了x,就不能选择k - x,使用map或者set进行标记就行了。
class Solution {
public:
    int minimumSum(int n, int k) {
                // 什么情况下会出现和为k的情况。如果出现x就不能出现k - x。那么选择x还是k - x呢?肯定选择min(x, k - x);
        // 最小不同,所以对于每一个数字,从最小的可以选的选择。
        unordered_map<int, int>mp;
        int cur = 1;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            while (mp[cur] == 1) cur++;
            ans += cur;
            mp[k - cur] = 1;
            cur++;
        }
        return ans;
    }
};

你可能感兴趣的:(数据结构)