• weekly-contest-205


    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,即当前节点的根元素是自己。
  • 相关阅读:
    LeetCode-Letter Combinations of a Phone Number
    LeetCode-Sort Colors
    C++Memset误区
    LeetCode-Valid Palindrome
    LeetCode-Longest Consecutive Sequence
    C++豆知识索引
    C++ 哈希表
    LeetCode-Sum Root to Leaf Numbers
    LeetCode-Word LadderII
    LeetCode-Word Ladder
  • 原文地址:https://www.cnblogs.com/Yuasin/p/13622471.html
Copyright © 2020-2023  润新知