weekly-contest-205

1 / 5507. 替换所有的问号

class Solution {
public String modifyString(String s) {
StringBuilder res = new StringBuilder();
for(int i=0; i<s.length(); i++){
if(s.charAt(i)!='?'){
res.append(s.charAt(i));
}else{
boolean head = (i==0);
boolean tail = (i==s.length()-1); for(int j=0;j<26;j++){
char ap = (char)('a'+j); // 不为头部
if(!head){
// 注意此处不能使用 s.charAt(i-1),如果i-1是?则此处判断会错误
// 应该使用替换后的StringBuilder作为判断对象
if(res.charAt(i-1) == ap)
continue;
}
// 不为尾部,且后一个字符不为?(为?则没有判断的必要,当前选任意字符必然不会和?重复)
if(!tail && s.charAt(i+1)!='?'){
if(s.charAt(i+1)==ap)
continue;
}
res.append(ap);
break;
}
}
}
return res.toString();
}
}

总结:

  • 对于边界条件的判断不够灵敏,当i==0时为head,此时不应该向前判断;当i==s.length()时为tail,此时不应该向后判断;当s.charAt(i+1)!='?'时,没有向后判断的必要(此条件可以省略)
  • 变量的状态没判断清楚,将原字符串一直作为比较对象,向前判断的时候仍然使用s.charAt(i-1),这个值原先为?,但是替换并不是在s上进行替换,所以此处的判断就会导致错误。

2 / 5508. 数的平方等于两数乘积的方法数

class Solution {
// j!=k
// map(key,value) (key:j*k,value:times)
// i^2 == key result+=value
public int numTriplets(int[] nums1, int[] nums2) {
return countTri(nums1,nums2) + countTri(nums2,nums1);
} public int countTri(int[] nums1, int[] nums2){
Map<Long,Long> map = calMap(nums2);
int result=0;
for(int i=0;i< nums1.length; i++){
if(map.containsKey((long)nums1[i]*nums1[i])){
result+=map.get((long)nums1[i]*nums1[i]);
}
}
return result;
} public Map<Long,Long> calMap(int[] nums){
Map<Long,Long> map = new HashMap<>();
for(int i=0;i< nums.length-1; i++){
for(int j=i+1; j<nums.length; j++){ if(!map.containsKey((long)nums[i]*nums[j])){
map.put((long)nums[i]*nums[j],(long)1);
//map.put((long)nums[i]*nums[j],1l);
}else{
map.put((long)nums[i]*nums[j],map.get((long)nums[i]*nums[j])+1);
}
}
}
return map;
}
}
// 1 <= nums1.length, nums2.length <= 1000
// 1 <= nums1[i], nums2[i] <= 10^5

总结:

  • 数据的大小为10^5,两个数据相乘最大可达100亿,超过了int类型的上限,所以此处要将int类型转换成long

    • long的封装类型为Long
    • 在转换时如果使用(long)(nums[i]*nums[j])是不正确的, 程序会先计算括号内的数据,但是括号是两个int相乘,得到的结果也是int,此时数据已经溢出,再转换为long时无法将溢出的数据补回,(long)nums[i]*nums[j]则是先将前面的int类型强转为long,long与int类型操作,数据向上转型,此时计算结果就正确
  • (long)2333 == 2333l

3 / 5509. 避免重复字母的最小删除成本

class Solution {
//多个字符相同
public int minCost(String s, int[] cost) {
int sampP = 0;
int result=0;
for(int i=0; i<s.length()-1; i++){
while(sampP<s.length()-1 && s.charAt(sampP+1) == s.charAt(i)){
sampP++;
}
result += calCost(i,sampP,cost);
i = sampP;
}
return result;
}
public int calCost(int start, int end, int[] cost){
int result=0;
int max=-1;
for(int i=start; i<=end; i++){
result+=cost[i];
max = Math.max(max,cost[i]);
}
result -=max;
return result;
}
}

总结:

  • 此题无踩坑,需要注意到多个字符相同时留下一个字符即可,留下删除代价最高的那个字符即可。另就是需要小心sampP的边界值判断。

* 4 / 5510. 保证图可完全遍历

class Solution {
private boolean[] used;
public int maxNumEdgesToRemove(int n, int[][] edges) {
used = new boolean[edges.length];
// System.out.println(Arrays.deepToString(edges));
// 根据第一个元素倒序排序
Arrays.sort(edges, (a, b) -> Integer.compare(b[0], a[0]));
if(unionFind(n, edges, 1) != 1) return -1;
if(unionFind(n, edges, 2) != 1) return -1;
int result = 0;
for(boolean u: used){
result += u ? 0 : 1;
}
return result;
} private int unionFind(int n, int[][] edges, int excludedType){
int[] union = new int[n + 1];
for(int i = 1; i <= n ; i++){
union[i] = i;
}
for(int i = 0; i < edges.length; i++){
int[] edge = edges[i];
if(edge[0] == excludedType) continue;
int rootA = findRoot(union, edge[1]);
int rootB = findRoot(union, edge[2]); //rootA!=rootB则两个点尚未连通,将其连通
if(rootA != rootB){
union[rootA] = rootB;
used[i] = true;
}
}
int result = 0;
for(int i = 1; i <= n; i++){
if(union[i] == i) result += 1;
}
return result;
} private int findRoot(int[] union, int idx){
if(union[idx] != idx){
int root = findRoot(union, union[idx]);
union[idx] = root; // 压缩路径,否则有两个case会超时
return root;
}
return idx;
}
}

总结:

  • 并查集的关键在于find(),union数组储存了当前节点的父元素,两个节点的根元素(最顶上的父元素,union[idx]==idx)相同则代表两个元素相同,find即寻找出了节点的根元素。
  • 如果数组只储存了节点的父元素,则每次需要寻找根元素时都需要往上查找非常多次,所以这里需要进行路径压缩,让union中直接储存当前节点的根元素,这样在后续查找的时候可以直接查询到。
  • 本题根元素特征union[i] == i,即当前节点的根元素是自己。

最新文章

  1. Liferay 6.2 改造系列之十八:修改登录Portlet配置,去除无用链接
  2. AsyncTask异步交互
  3. mysql数据库入门
  4. 【转载】使用Axure制作App原型怎样设置尺寸?
  5. MYSQL- 分页存储过程
  6. 有限状态机FSM(自动售报机Verilog实现)
  7. docker学习笔记:容器的网络设置
  8. 性能测试开源小工具——http_load介绍
  9. u盘烧写后实际容量变小了
  10. 一句话搞定-phpStudy安装yaf扩展
  11. centos安装SWFtools服务(pdf2swf)
  12. JavaScript高级程序设计(二)
  13. mina statemachine解读(二)
  14. boost库在windows上的安装
  15. cxgrid属性说明,每次用的时候费时费力查找。
  16. Maven和Gradle的区别
  17. 三星450R5J windows8.1系统重装小结
  18. configparser配置文件处理
  19. ELK安装使用教程
  20. frameset,iframe框架之间如何互相调用变量、函数

热门文章

  1. linux常用命令(一)软件操作命令
  2. Python中json.dump与repr的区别
  3. 手动向Maven本地仓库添加ORACLE ojdbc6jar包
  4. C# NPOI计算Execl里面的公式
  5. day1 linux常用命令(一)
  6. 【Gin-API系列】Gin中间件之日志模块(四)
  7. Android Failed to find layer (XXX/XXX.xxActivity#0) in layer parent (no-parent).
  8. IE9知识点汇总
  9. 在laravel中遇到并发的解决方案
  10. ceph scrub error解决方案