0
点赞
收藏
分享

微信扫一扫

LeetCode 第 55 场双周赛题解及思路

飞空之羽 2022-04-05 阅读 41
力扣c++

LeetCode 第 55 场双周赛 题解及思路

赛题传送门

1909. 删除一个元素使数组严格递增

赛题

我们可以遍历数组 nums 中求出第一个满足条件 nums[idx] <= nums[idx - 1] 的下标 idx ,这就意味着下标为 idxidx - 1 的元素必须删除一个才 可能 满足条件。

bool canBeIncreasing(vector<int>& nums) {
	int idx = -1;
	for (int i = 1; i < nums.size(); i++)
		if (nums[i] <= nums[i - 1])
			if (idx != -1) return false;
			else idx = i;
}

如果没有找到这样的下标则返回 true。如果找到了两个及以上这样的下标则返回 false。否则我们可以删掉下标 idx 的元素且判断 idx - 1idx + 1 的元素是否满足递增,或者我们可以删掉下标 idx - 1 的元素且判断 idx - 2idx 的元素是否满足递增。

返回值注意边界处理。

return idx == -1 || idx == 1 || idx == nums.size() - 1 || nums[idx + 1] > nums[idx - 1] || nums[idx] > nums[idx - 2];

完整代码见 GitHub。

1910. 删除一个字符串中所有出现的给定子字符串

赛题

想都没想,直接模拟就好了,不断使用 C++ 中的 find 函数对 s 查找子串 part,如果能找到则从 s 删除这个子串并重复上述过程,如果找不到就返回 s 作为答案。

string removeOccurrences(string s, string part) {
	int len = part.length();
	while (true) {
		int start_idx = s.find(part);
		if (start_idx == string::npos) break;
		else s = s.substr(0, start_idx) + s.substr(start_idx + len);
	};
	return s;
}

完整代码见 GitHub。

1911. 最大子序列交替和

看上去就像是合格的 动态规划 题,最简单的即按照 数组长度 来拆分,即我们考虑 nums 的前缀子数组 nums[0] - nums[i - 1],假设我们已经在前缀子数组中选取了 奇数 个元素用作最大交替和的子序列,则如果选取当前元素就是 奇数 下标(注意下标从 0 开始)是要被减去的。

因此我们分奇偶来分别动态规划即可, d p [ i ] [ 0 ] dp[i][0] dp[i][0] 代表在前 i i i 个元素中选取偶数个元素的最大子序列交替和, d p [ i ] [ 1 ] dp[i][1] dp[i][1] 则代表在前 i i i 个元素中选取奇数个元素的最大子序列交替和。

d p [ i ] [ 0 ] = { m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] − n u m s [ i ] ) i ≥ 1 0 i = 0 dp[i][0] = \begin{cases} max(dp[i - 1][0], dp[i - 1][1] - nums[i]) & i \geq 1 \\ 0 & i = 0 \\ \end{cases} dp[i][0]={max(dp[i1][0],dp[i1][1]nums[i])0i1i=0

d p [ i ] [ 1 ] = { m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + n u m s [ i ] ) i ≥ 1 n u m s [ i ] i = 0 dp[i][1] = \begin{cases} max(dp[i - 1][1], dp[i - 1][0] + nums[i]) & i \geq 1 \\ nums[i] & i = 0 \\ \end{cases} dp[i][1]={max(dp[i1][1],dp[i1][0]+nums[i])nums[i]i1i=0

完整代码见 GitHub。

1912. 设计电影租借系统

太复杂了题目,先好好读题 3 遍发现大致就是要实现 有优先级的查询 因此考虑使用 map,我们定义 node 结构体来存储每个 entry 并且定义优先级。

struct node {
    int shop;
    int movie;
    int price;
    node(int shop, int movie, int price): shop(shop), movie(movie), price(price) {};
    bool operator<(const node& a) const { 
        if (this->price != a.price) return this->price < a.price;
        else if (this->shop != a.shop) return this->shop < a.shop;
        else return this->movie < a.movie;
    };
};

然后我们发现 shopmovie 的上限是 3 * 10^5,那么我们就暴力地定义一个这么大的数组,数组中每个元素都是对应 shop(movie)movie(shop)map 用来快速查询。

vector< map<node, int, less<node> > > movie2shop; // 通过 movie 查询 shop
vector< map<node, int, less<node> > > shop2movie; // 通过 shop 查询 movie
map<int, map<int, int>> movieshop2price; // 通过 movie 和 shop 查询 price
map<node, node, less<node> > rentmovies;  // 已经解出的 movie

初始化 过程中,我们遍历每个 entry 来插入各个 map

for (const vector<int>& entry : entries) {
    int shop = entry[0], movie = entry[1], price = entry[2];
    movie2shop[movie].insert(pair<node, int>(node(shop, movie, price), shop));
    shop2movie[shop].insert(pair<node, int>(node(shop, movie, price), movie));
    movieshop2price[movie][shop] = price;
};

search 的话则直接根据 movie2shop 去寻找至多 5 个条目返回即可。

vector<int> search(int movie) {
    map<node, int, less<node> > m = movie2shop[movie];
    vector<int> answer;
    for (map<node, int, less<node> >::iterator iter = m.begin(); iter != m.end() && answer.size() < 5; ++iter)
        answer.push_back(iter->second);
    return answer;
}

rent 的话则需要将 shop2moviemovie2shop 中对应的 entry 删去,并且在 rentmovies 中插入方便 report 快速查找。

void rent(int shop, int movie) {
    node n = node(shop, movie, movieshop2price[movie][shop]);
    shop2movie[shop].erase(shop2movie[shop].find(n));
    movie2shop[movie].erase(movie2shop[movie].find(n));
    rentmovies.insert(pair<node, node>(n, n));
    return;
}

drop 的话则需要在 shop2moviemovie2shop 分别增加对应的 entry,并且在 rentmovies 中删去对应的 entry 以保持数据的一致性。

void drop(int shop, int movie) {
    node n = node(shop, movie, movieshop2price[movie][shop]);
    shop2movie[shop].insert(pair<node, int>(n, movie));
    movie2shop[movie].insert(pair<node, int>(n, shop));
    rentmovies.erase(rentmovies.find(n));
    return;
}

report 则直接从 rentmovies 中选取至多 5 个 entry 返回即可。

vector<vector<int> > report() {
    vector<vector<int> > answer;
    for (map<node, node, less<node> >::iterator iter = rentmovies.begin(); iter != rentmovies.end() && answer.size() < 5; ++iter) {
        node n = iter->first;
        answer.push_back({n.shop, n.movie});
    };
    return answer;
}

完整代码见 GitHub。

这场双周赛是我在比赛结束后才打的虚拟竞赛,最近虾皮挺火的就想着做做他冠名的周赛,没想到还是挺简单的,最后一道题也是更偏向于设计(而不是算法)以及思路的严谨性。

好啦,以上就是力扣第 55 场双周赛的全部思路啦。最后,欢迎关注我的 GitHub 账号。

举报

相关推荐

0 条评论