给你一个仅包含小写英文字母和 ‘?’ 字符的字符串 s,请你将所有的 ‘?’ 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。
注意:你 不能 修改非 ‘?’ 字符。
题目测试用例保证 除 ‘?’ 字符 之外,不存在连续重复的字符。
在完成所有转换(可能无需转换)后返回最终的字符串。如果有多个解决方案,请返回其中任何一个。可以证明,在给定的约束条件下,答案总是存在的。
class Solution {
public:
char get(char x,char y) {
for(char i = 'a';i <= 'z';i++) {
if(i != x && i != y) return i;
}
return 'a';
}
string modifyString(string s) {
int n = s.size();
if(s[0] == '?') {
if(n == 1 || s[1] == 'a' || s[1] == '?') {
s[0] = 'b';
} else {
s[0] = s[1] - 1;
}
}
for(int i = 1;i < n;i++) {
if(s[i] != '?') continue;
s[i] = get(s[i - 1],s[i + 1]);
}
return s;
}
};
给你两个整数数组 nums1 和 nums2 ,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):
类型 1:三元组 (i, j, k) ,如果 nums1[i]2 == nums2[j] * nums2[k] 其中 0 <= i < nums1.length 且 0 <= j < k < nums2.length
类型 2:三元组 (i, j, k) ,如果 nums2[i]2 == nums1[j] * nums1[k] 其中 0 <= i < nums2.length 且 0 <= j < k < nums1.length
思路:
直观的想法就是固定一个数组的一个i,然后找另外一个数组j,确定有多少个对应k,这个过程可以用map维护。但是mapT了,用了unordered_map水过去了。。。如果用哈希应该可以快很多。
看着像是meet in middle,感觉可以双指针,但是数组没有单调性,不知道咋搞。
typedef long long ll;
class Solution {
public:
int numTriplets(vector<int>& nums1, vector<int>& nums2) {
int n1 = nums1.size(),n2 = nums2.size();
int ans = 0;
int cnt1 = 0,cnt2 = n2 - 1;
for(int i = 0;i < n1;i++) {
ll now = 1ll * nums1[i] * nums1[i];
whlie(n)
}
for(int i = 0;i < n2;i++) {
mp.clear();
for(int j = 0;j < n1;j++) {
mp[nums1[j]]++;
}
for(int j = 0;j < n1;j++) {
mp[nums1[j]]--;
if(1ll * nums2[i] * nums2[i] % nums1[j]) continue;
ll pre = 1ll * nums2[i] * nums2[i] / nums1[j];
if(mp[pre] > 0) ans += mp[pre];
}
}
return ans;
}
};
给你一个字符串 s 和一个整数数组 cost ,其中 cost[i] 是从 s 中删除字符 i 的代价。
返回使字符串任意相邻两个字母不相同的最小删除成本。
请注意,删除一个字符后,删除其他字符的成本不会改变。
思路:
这个确实大水题了,直接找出连续字母中最大花费那个,减去其他的字母就好了。
class Solution {
public:
int minCost(string s, vector<int>& cost) {
int n = s.length();
int ans = 0;
int now = cost[0],mx = cost[0];
for(int i = 1;i < n;i++) {
if(s[i] == s[i - 1]) {
now += cost[i];
mx = max(cost[i],mx);
} else {
ans += now - mx;
now = mx = cost[i];
}
}
ans += now - mx;
return ans;
}
};
类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。
返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。
思路:
想了好久没想到,最后发现其实类型1的边和类型2的边完全可以分开算。因为类型3的边肯定是连的越多越好,否则你某个地方能连你不连,最后还是得用类型2或者类型3的边来填,肯定不优。所以类型3的边要删多少是确定的。
假设只有类型1和类型3的边,那么直接用并查集维护就好了。实际上如果图最后能连通,结果就是边总数减去n-1。可以算出可以删掉多少类型1和类型3的边。
如果图不连通,那么就输出-1。
假设只有类型2和类型3的边,也是同样的用并查集维护,可以算出要删掉多少类型2和类型3的边。可以发现类型3的边在两次操作中都删了,所以这步可以只执行一次。
如果图不连通,同样输出-1。
const int maxn = 1e5 + 7;
class Solution {
public:
vector<vector<int> >e1,e2,e3;
int fa[maxn];
int findset(int x) {
if(fa[x] == x) return x;
return fa[x] = findset(fa[x]);
}
bool Union(int x,int y) {
int rx = findset(x),ry = findset(y);
if(rx != ry) {
fa[rx] = ry;
return true;
}
return false;
}
int init(int n) {
int res = 0;
for(int i = 1;i <= n;i++) fa[i] = i;
for(int i = 0;i < e1.size();i++) {
int x = e1[i][1],y = e1[i][2];
if(!Union(x,y)) {
res++;
}
}
return res;
}
int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
int len = edges.size();
printf("FUCK %d\n",len);
for(int i = 0;i < len;i++) {
if(edges[i][0] == 3) e1.push_back(edges[i]);
else if(edges[i][0] == 2) e2.push_back(edges[i]);
else e3.push_back(edges[i]);
}
int ans = init(n);
for(int i = 0;i < e2.size();i++) {
int x = e2[i][1],y = e2[i][2];
if(!Union(x,y)) {
ans++;
}
}
int cnt = 0;
for(int i = 1;i <= n;i++) {
if(findset(i) == i) {
cnt++;
}
}
if(cnt > 1) return -1;
init(n);
for(int i = 0;i < e3.size();i++) {
int x = e3[i][1],y = e3[i][2];
if(!Union(x,y)) {
ans++;
}
}
cnt = 0;
for(int i = 1;i <= n;i++) {
if(findset(i) == i) {
cnt++;
}
}
if(cnt > 1) return -1;
return ans;
}
};