LeetCode Weekly 156
5205.独一无二的出现次数
给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。
如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。
示例 1:
输入:arr = [1,2,2,1,1,3]
输出:true
解释:在该数组中,1 出现了 3 次,2 出现了 2 次,3 只出现了 1 次。没有两个数的出现次数相同。示例 2:
输入:arr = [1,2]
输出:false示例 3:
输入:arr = [-3,0,1,-3,1,1,1,-3,10,0]
输出:true提示:
1 <= arr.length <= 1000
-1000 <= arr[i] <= 100
很简单的问题而且数据范围也很小,直接用数组记出现的数字然后再判重
int num[2001];
bool vised[2001];
class Solution {
public:
bool uniqueOccurrences(vector<int>& arr)
{
memset(num,0,sizeof(num));
memset(vised,0,sizeod(vised));
int len=arr.size();
for(int i=0;i<len;i++)
{
int tmp=arr[i];
if(tmp<0)
{
tmp*=-1;
tmp+=1000;
}//将数字简单映射一下
num[tmp]++;
vised[tmp]=1;
}
for(int i=0;i<=2000;i++)
{
if(vised[i])
{
for(int j=0;j<=2000;j++)
{
if(i!=j)
{
if(num[i]==num[j])
{
return false;
}
}
}
}
}
return true;
}
};
5207. 尽可能使字符串相等
给你两个长度相同的字符串,s 和 t。
将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
示例 1:
输入:s = "abcd", t = "bcdf", cost = 3
输出:3
解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。
遇到这种区间费用问题一般用前缀数组可以使操作更加简单,记cost(i)为前i个字符的开销,这样cost(j+1)-cost(i)就是j到i这一区间的开销。同时用一个指针指向最大段的开端,每当费用超过时就将指针前移直到小于等于maxCost
再不断更新更大的答案就行了,最坏时间复杂度为O(n^2),但数据似乎没有这么毒瘤。。。更正:是O(n)哒!
long long cost[100001];
class Solution {
public:
int equalSubstring(string s, string t, int maxCost)
{
memset(cost,0,sizeof(cost));
int len=s.size();
int maxlen=0;
int pl=1;
for(int i=0;i<len;i++)
{
cost[i+1]=abs(s[i]-t[i])+cost[i];
if(cost[i+1]-cost[pl]<=maxCost)
{
maxlen=max(maxlen,i-pl+2);
}
else
{
while(cost[i+1]-cost[pl]>maxCost && pl<=i+1)
{
pl++;
}
}
}
return maxlen;
}
};
5206.删除字符串中的所有相邻重复项 II
给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。
你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。
在执行完所有删除操作后,返回最终得到的字符串。
本题答案保证唯一。
示例 1:
输入:s = "abcd", k = 2
输出:"abcd"
解释:没有要删除的内容。示例 2:
输入:s = "deeedbbcccbdaa", k = 3
输出:"aa"
解释:
先删除 "eee" 和 "ccc",得到 "ddbbbdaa"
再删除 "bbb",得到 "dddaa"
最后删除 "ddd",得到 "aa"
直接上栈,相当于在线的模拟每个字符入栈的操作,同时记录下相同字母的数量。每次进栈前检查一下是否达到k,是的话就将栈顶前k个弹出。虽然不难想但是有点难写。
stack<pair<char,int> > sta;
char tmp[100001];
class Solution {
public:
string removeDuplicates(string s, int k)
{
for(auto i:s)//依次枚举s中的字符
{
if(sta.empty())
{
sta.push(make_pair(i,1));
}
else
{
pair<char,int> now=sta.top();
if(now.first==i)
{
sta.push(make_pair(i,sta.top().second+1));//相同则次数+1
}
else
{
sta.push(make_pair(i,1));
}
}
while(!sta.empty() && sta.top().second==k)//检查是否达到k次
{
for(int j=0;j<k;j++)
{
sta.pop();
}
}
}
int num=sta.size();
tmp[num]=0;
for(int i=num-1;i>=0;i--)
{
tmp[i]=sta.top().first;
sta.pop();
}
string ans(tmp);
return ans;
}
};
5208.穿过迷宫的最少移动次数
你还记得那条风靡全球的贪吃蛇吗?
我们在一个 n*n 的网格上构建了新的迷宫地图,蛇的长度为 2,也就是说它会占去两个单元格。蛇会从左上角((0, 0) 和 (0, 1))开始移动。我们用 0 表示空单元格,用 1 表示障碍物。蛇需要移动到迷宫的右下角((n-1, n-2) 和 (n-1, n-1))。
每次移动,蛇可以这样走:
如果没有障碍,则向右移动一个单元格。并仍然保持身体的水平/竖直状态。
如果没有障碍,则向下移动一个单元格。并仍然保持身体的水平/竖直状态。
如果它处于水平状态并且其下面的两个单元都是空的,就顺时针旋转 90 度。蛇从((r, c)、(r, c+1))移动到 ((r, c)、(r+1, c))。
如果它处于竖直状态并且其右面的两个单元都是空的,就逆时针旋转 90 度。蛇从((r, c)、(r+1, c))移动到((r, c)、(r, c+1))。返回蛇抵达目的地所需的最少移动次数。
如果无法到达目的地,请返回 -1。
示例 1:
输入:grid = [[0,0,0,0,0,1],
[1,1,0,0,1,0],
[0,0,0,0,1,1],
[0,0,1,0,1,0],
[0,1,1,0,0,0],
[0,1,1,0,0,0]]
输出:11
解释:
一种可能的解决方案是 [右, 右, 顺时针旋转, 右, 下, 下, 下, 下, 逆时针旋转, 右, 下]。
方格上的最短路,不是bfs就是dp,但这道题的状态转移很多用bfs的话码量惊人(dp的也不少)。
考虑用动态规划做,用dp(i,j,k)来表示从起点到蛇尾位于(i,j)蛇身状态为k(0表示蛇身水平,1表示蛇身竖直)时的最小移动次数。虽然题面关于走法写的很清楚,但正常人也不会想到这个蛇能平移。。。
同时因为蛇是向左下移动,因此从左向下枚举。同时蛇的转动需要2X2的方格,所以2X2的情况和非2X2的情况需要分别转移。
int dp[101][101][2];
class Solution {
public:
int minimumMoves(vector<vector<int>>& grid)
{
int n=grid.size();
memset(dp,0x3f,sizeof(dp));
dp[0][0][0]=0;//初始化除0,0,0的状态其它都是无限大(非法)
for(int i=0;i<n;i++)
{
for(int 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])//先考虑2X2的情况
{
dp[i][j][0]=min(dp[i][j][0],dp[i][j][1]+1);
dp[i][j][1]=min(dp[i][j][1],dp[i][j][0]+1);
dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][0]+1);
dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+1);
}
if(j+2<n && !grid[i][j+1] && !grid[i][j+2])
{
dp[i][j+1][0]=min(dp[i][j+1][0],dp[i][j][0]+1);
}
if(i+2<n && !grid[i+1][j] && !grid[i+2][j])
{
dp[i+1][j][1]=min(dp[i+1][j][1],dp[i][j][1]+1);
}
}
}
}
if(dp[n-1][n-2][0]==0x3f3f3f3f)//如果结果无限大则表示没法到达
{
return -1;
}
else
{
return dp[n-1][n-2][0];
}
}
};
这场比赛的题目都是说难不难,但就是不好直接想出来的类型,这样的题目很有价值。