A.替换所有的问号
解题思路:
扫一边过去,当时?时只要填一个和两边都不相等的就可以了,直接枚举要填的字母即可。
代码:
class Solution {
public:
string modifyString(string s) {
int len = s.size();
for(int i=0;i<len;i++)
{
if(s[i] == '?')
{
for(int j=0;j<26;j++)
{
if(i>0 && s[i-1]-'a' == j)continue;
if(i+1<len && s[i+1]-'a'==j)continue;
s[i] = 'a' + j;
break;
}
}
}
return s;
}
};
B.数的平方等于两数乘积的方法数
解题思路:
枚举两个元组,那么剩下的一个时可以计算出来的,预处理出每个元素的出现次数。具体来说就是:先确定第一个数组中拿的一个元素,剩下的两个从另一个数组中拿的话,就是那两个元素在数组二中出现的次数相乘再除二,特殊情况当剩下两个元素一样时,根据组合数答案是“出现次数”乘“出现次数减1”再除二。从第二个数组中拿一个同理。
代码:
比赛时候写的可能不是很美观:
class Solution {
public:
int numTriplets(vector<int>& nums1, vector<int>& nums2) {
const int maxn = 1e5+5;
int visa[maxn],visb[maxn];
memset(visa,0,sizeof(visa));
memset(visb,0,sizeof(visb));
int len1 = nums1.size();
int len2 = nums2.size();
for(int i=0;i<len1;i++)
visa[nums1[i]]++;
for(int i=0;i<len2;i++)
visb[nums2[i]]++;
long long ans = 0;
int ok[maxn];
for(int i=0;i<len1;i++)
{
memset(ok,0,sizeof(ok));
for(int j=0;j<len2;j++)
{
long long c = (long long)nums1[i]*nums1[i];
if(c % nums2[j] == 0 && c / nums2[j] < maxn)
{
if( ok[nums2[j]] == 1 || ok[c/nums2[j]] == 1)continue;
if(c / nums2[j] == nums2[j])
ans += visb[nums2[j]]*(visb[nums2[j]]-1)/2;
else
ans += visb[nums2[j]]*visb[c / nums2[j]];
ok[nums2[j]] = ok[c/nums2[j]] = 1;
}
}
}
for(int i=0;i<len2;i++)
{
memset(ok,0,sizeof(ok));
for(int j=0;j<len1;j++)
{
long long c = (long long)nums2[i]*nums2[i];
if(c % nums1[j] == 0 && c / nums1[j] < maxn)
{
if( ok[nums1[j]] == 1 || ok[c/nums1[j]] == 1)continue;
if(c / nums1[j] == nums1[j])
ans += visa[nums1[j]]*(visa[nums1[j]]-1)/2;
else
ans += visa[nums1[j]]*visa[c / nums1[j]];
ok[nums1[j]] = ok[c/nums1[j]] = 1;
}
}
}
return ans;
}
};
C.避免重复字母的最小删除成本
解题思路:
对于连续的一样的数我们要保留的是代价最大的一个,那么只要扫一遍过去,记录连续一样字符中消除代价最大的数和连续字符消除代价的和即可,剩下的注意细节就可以了。
代码:
class Solution {
public:
int minCost(string s, vector<int>& cost) {
const int maxn = 1e5+5;
int s1[maxn],s2[maxn];
//s+="#";
int len = s.size();
int ans = 0,c=1;
int ma = cost[0],sum = cost[0];
for(int i=1;i<len;i++)
{
if(s[i] == s[i-1])
{
c++;
}
else
{
if(c > 1)
{
ans += sum - ma;
c = 1;
}
sum = ma = 0;
}
sum += cost[i];
ma = max(ma,cost[i]);
}
if(c > 1)
ans += sum - ma;
return ans;
}
};
D.保证图可完全遍历
解题思路:
首先判断Alice 和 Bob 分别在不去边的情况下能否到达所有点,如果不行则返回 − 1 -1 −1,接下来我们求出Alice 能走的边数,我们知道对于 n n n个点的连通图只需要 n − 1 n-1 n−1条边即可,那么对于Alice能去的边就是“Alice 能走的边数” − ( n − 1 ) -(n-1) −(n−1),Bob同理,就是“Bob 能走的边数” − ( n − 1 ) -(n-1) −(n−1),将它们加起来,但是这有重复的,重复的就是去掉的蓝边,由于我们去的边尽量多,所以我们都是能不去蓝边就不去,蓝边实在多余的话才去除,那么只要减去有几个蓝边是"多余"的,这怎么计算呢,我们只要每次将蓝边的两点合并,当合并前发现它们已经在一起了就是多余的。
代码:
class Solution {
const int maxn = 1e5+5;
int fa[100005];
int findf(int x)
{
if(fa[x] == x)return x;
return fa[x] = findf(fa[x]);
}
void initfa(int n)
{
for(int i=0;i<=n;i++)
fa[i] = i;
}
int merge(int x,int y)
{
int fx = findf(x);
int fy = findf(y);
if(fx != fy)
{
fa[fx] = fy;
return 0;
}
return 1;
}
int check(int n)
{
int ans = 0;
for(int i=1;i<=n;i++)
if(fa[i] == i)
ans++;
return ans;
}
public:
int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
int a1,a2,a3;
a1 = a2 =a3 = 0;
int len = edges.size();
for(int i=0;i<len;i++)
{
if(edges[i][0] == 1)a1++;
if(edges[i][0] == 2)a2++;
if(edges[i][0] == 3)a3++;
}
initfa(n);
for(int i=0;i<len;i++)
if(edges[i][0] == 1 || edges[i][0] == 3)
merge(edges[i][1],edges[i][2]);
if(check(n) != 1)return -1;
initfa(n);
for(int i=0;i<len;i++)
if(edges[i][0] == 2 || edges[i][0] == 3)
merge(edges[i][1],edges[i][2]);
if(check(n) != 1)return -1;
initfa(n);
int del = 0;
for(int i=0;i<len;i++)
if(edges[i][0] == 3)
{
del += merge(edges[i][1],edges[i][2]);
}
return (a1+a3-n+1)+(a2+a3-n+1)-del;
}
};