聊一聊leetcode第156场周赛

一.  5205. 独一无二的出现次数

1.这个提示很关键,第一名用了提示的关系建立了一个对应的数组.(来自JOHNKRAM大神)

class Solution {
public:
	bool uniqueOccurrences(vector<int>& arr) {
		int s[2005];
		//memset用于清空数组.
		memset(s, 0, sizeof(s));
		//将arr里的值作为数组的键.因为数组大小不超过1000,值-1000到1000.
		for (auto i : arr)s[i + 1000]++;
		sort(s, s + 2005);//排序是为了使值连续.
		for (int i = 0; i<2004; i++)if (s[i] && s[i + 1] == s[i])return 0;
		return 1;
	}
};

2. 第2名liouzhou_101的想法很自然.

class Solution {
public:
	bool uniqueOccurrences(vector<int>& a) {
		//构建两个哈希表.
		map<int, int> F, G;
		//F统计每个值出现的个数.
		for (auto x : a) F[x] ++;
		//G统计F中每个值个数的个数.
		for (auto [x, y] : F) G[y] ++;
		//如果超过2,肯定有相同的.
		for (auto [x, y] : G) if (y >= 2) return false;
		return true;
	}
};

3. 我的其实也很自然.

class Solution {
public:
	bool uniqueOccurrences(vector<int>& arr) {
		map<int, int> res;
		for (int i = 0; i < arr.size(); i++) {
			if (res.count(arr[i]) == 0) {
				res.insert(map<int, int>::value_type(arr[i], 1));
			}
			else
				res[arr[i]]++;
		}
		set<int> tmp;
		for (auto i : res) {
			tmp.insert(i.second);
		}
		if (tmp.size() != res.size())
			return false;
		else
			return true;
	}
};

二.  5207. 尽可能使字符串相等

1. 这一题第一眼看上去绝对的dp,但是很可惜超出内存限制了.......没办法,我用的二维数组存储dp表格

\

2,提示很关键, 不过dp虽然超内存,但是思想不错,以后可以借鉴.

class Solution {
public:
	int equalSubstring(string s, string t, int maxCost) {
		int m = s.length();
		//dp[len][i]的含义是以长度为len并且以i索引结尾的字符子串的转化长度.
		//cost[len][i]的含义是长度为len并且以i索引结尾的字符子串的开销.
		vector<vector<int>> dp(m + 1, vector<int>(m, 0));
		//初始化值都为0.
		vector<vector<int>> cost(m + 1, vector<int>(m, 0));
		int maxv = -1;//求最大值,所以需要maxv变量.
		//初始化长度为1的情况.
		for (int num = 0; num <= m - 1; num++) {
			if (abs(s[num] - t[num]) <= maxCost) {
				dp[1][num] = 1;
			}
			cost[1][num] = abs(s[num] - t[num]);
			maxv = max(maxv, dp[1][num]);
		}
		for (int len = 2; len <= m; len++) {
			for (int i = len - 1; i <= m - 1; i++) {
				cost[len][i] = cost[len - 1][i - 1] + abs(s[i] - t[i]);
				if (cost[len][i] <= maxCost)
					//如果加上i的开销小于maxcost,则长度加1.
					dp[len][i] = dp[len - 1][i - 1] + 1;
				else {
					//这个容易错,注意一下,因为我们的dp含义一定以字符串i结尾,
					//所以如果本身i的开销大于maxcost,则肯定为0,跳过.
					if (abs(s[i] - t[i]) > maxCost) {
						continue;
					}
					//否则,dp[len][i]就只能就只能从前面开始判断,并且相应截断.
					for (int num = i - len + 1; num <= i - 1; num++) {
						if (cost[len][i] - cost[num - i + len][i - len + 1] <= maxCost) {
							dp[len][i] = dp[i - num][i];
						}
					}
				}
				maxv = max(maxv, dp[len][i]);
			}
		}
		return maxv;
	}
};

3. 这个时候只能参考大神代码了.(JOHNKRAM)(感觉智商被碾压)(是我想的太复杂了......看到啥都dp,但其实二维数组很耗费内存的,而且也没有必要.)

class Solution {
	int a[100005];//根据范围定义数组.长度在100000之内.
public:
	int equalSubstring(string s, string t, int maxCost) {
		int n = s.size(), i, j, ans = 0;
		//其实也是dp的思想,但是没有开辟额外空间存储.
		//其中a[i]代表以i索引结尾的字符串的总开销.
		for (i = 0; i<n; i++)a[i + 1] = a[i] + max(s[i] - t[i], t[i] - s[i]);
		//找出所有的以a[i]结尾的字符子串是否大于maxcost.
		for (i = 1, j = 0; i <= n; i++)
		{
			//这题的精髓是j可以一直前移,可以仔细想想.
			for (; a[i] - a[j]>maxCost; j++);
			ans = max(ans, i - j);
		}
		return ans;
	}
};

三.  5206. 删除字符串中的所有相邻重复项 II

1. 这一题第一眼看上去就是递归.放出我自己的代码.

class Solution {
public:
	string removeDuplicates(string s, int k) {
		int n = s.length();
		//令res等于s,如果找不到删除就直接返回.
		string res = s;
		for (int i = 0; i <= n - k; i++) {
			//找长度为k的需要删除的部分是否满足.
			int first = i, end = i + k - 1, tmp = s[first];
			while (first < end) {
				//这里尤其注意,第一次提交就bug了.
				//判断相等第一反应看前后字符是否一样,但是有可能回文串,
				//导致错误,其实也可以直接顺序判断的....不知道我怎么想的.
				if (s[first] == s[end] && s[first] == tmp) {
					first++;
					end--;
				}
				else
					break;//直接跳出.
			}
			if (first >= end) {
				//分三种情况,拼接字符串并返回.
				//递归想法.
				if (i > 0 && i < n - k)
					res = removeDuplicates(s.substr(0, i) + s.substr(i + k, n - i - k), k);
				else if (i == 0)
					res = removeDuplicates(s.substr(i + k, n - i - k), k);
				else if (i == n - k)
					res = removeDuplicates(s.substr(0, i), k);
				break;
			}
		}
		return res;
	}
};

2. 参考下上一题大神的思路.

class Solution {
	int a[100005], t;//看题目范围设定数组范围.
	char c[100005];
	string ans;
public:
	string removeDuplicates(string s, int k) {
		t = 0;
		//第1个for循环意思是,如果有新的字母.c[i]代表从1开始
		//不超过k个的需要保留的字母,a[i]统计连续相同字母的个数.
		for (auto i : s)if (i == c[t])
		{
			a[t]++;
			//t代表有效的字母,如果到k个了,则t--,这样下次就会覆盖.
			if (a[t] == k)t--;
		}
		else
		{
			c[++t] = i;
			a[t] = 1;
		}
		ans = "";
		//第二个for打印连续a[i]个c[i]中的字符.
		for (int i = 1; i <= t; i++)for (int j = 0; j<a[i]; j++)ans += c[i];
		return ans;
	}
};

3.好吧又被碾压了......

四.  5208. 穿过迷宫的最少移动次数

1.这一题第一眼看到肯定动态规划,因为需要求解一个最优问题.算了还是参考大神的代码吧.

class Solution {
	int f[105][105][2];
public:
	//动态规划,其中f前两个代表贪吃蛇的头部坐标,最后代表贪吃蛇的两种状态.
	//这个设置状态得学学,明白了含义程序不难看懂了.
	int minimumMoves(vector<vector<int>>& grid) {
		int n = grid.size(), i, j, ans;
		memset(f, 127, sizeof(f));
		f[0][0][0] = 0;
		for (i = 0; i<n; i++)for (j = 0; j<n; j++)if (!grid[i][j])
		{
			//总共六种情况,
			if (i + 1<n&&j + 1<n && !grid[i + 1][j] && !grid[i][j + 1] && !grid[i + 1][j + 1])
			{
				f[i][j][0] = min(f[i][j][0], f[i][j][1] + 1);
				f[i][j][1] = min(f[i][j][1], f[i][j][0] + 1);
				f[i + 1][j][0] = min(f[i + 1][j][0], f[i][j][0] + 1);
				f[i][j + 1][1] = min(f[i][j + 1][1], f[i][j][1] + 1);
			}
			if (j + 2<n && !grid[i][j + 1] && !grid[i][j + 2])f[i][j + 1][0] = min(f[i][j + 1][0], f[i][j][0] + 1);
			if (i + 2<n && !grid[i + 1][j] && !grid[i + 2][j])f[i + 1][j][1] = min(f[i + 1][j][1], f[i][j][1] + 1);
		}
		ans = f[n - 1][n - 2][0];
		if (ans == 2139062143)ans = -1;
		return ans;
	}
};

2.大神两个地方值得学习,第一个就是f前面两个代表贪吃蛇前面,我设置为第二点的话,就多了很多麻烦.第二个就是状态单独放在第三维坐标,省去了判断.

最后再接再厉吧..........

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值