LeetCode第234场周赛

周赛地址:https://leetcode-cn.com/contest/weekly-contest-234/

第一题:字符串中不同整数的数目

用a-z的字符,将原字符串进行分割,拿到一个只包含数字的字符串数组,对每个字符串,使用自定义的removeZero()函数去除前导0,放入set,最后统计set中元素的个数即可。
比赛的时候wa了两发,不应该啊,没仔细看题,一次wa在前导0上,一次wa在数据范围上。

import java.util.HashSet;

class Solution {
    public int numDifferentIntegers(String word) {
        String[] words = word.split("[a-z]");
        HashSet<String> hashSet = new HashSet<>();
        for (String s : words) {
            if (!"".equals(s)) {
                hashSet.add(removeZero(s));
            }
        }
        return hashSet.size();
    }

    private String removeZero(String s) {
        int i = 0, length = s.length();
        while (i < length && s.charAt(i) == '0') {
            i++;
        }
        return s.substring(i);
    }
}

第二题:还原排列的最少操作步数

根据题意,对数组模拟运算即可,每次操作后,判断是否回到了初始排列。

class Solution {
    public int reinitializePermutation(int n) {
        int[] perm = new int[n];
        for (int i = 0; i < n; i++) {
            perm[i] = i;
        }
        int times = 0;
        int[] arr = perm.clone();
        while (true) {
            times++;
            for (int i = 0; i < n; i++) {
                if ((i & 1) == 1) {
                    arr[i] = perm[n / 2 + (i - 1) / 2];
                } else {
                    arr[i] = perm[i / 2];
                }
            }
            perm = arr.clone();
            if (check(perm, n)) {
                break;
            }
        }
        return times;
    }

    private boolean check(int[] arr, int n) {
        for (int i = 0; i < n; i++) {
            if (arr[i] != i) {
                return false;
            }
        }
        return true;
    }
}

其实还有更好的方法,只需要看某一位即可,没必要每位都模拟。根据例子可以看出0和length - 1下标的数值是不变的,其余位置的数字回到当前位置所需要的操作数即为答案。

class Solution {
    public int reinitializePermutation(int n) {
        int times = 0, position = 1;
        do {
            times++;
            if ((position & 1) == 1) {
                position = n / 2 + (position - 1) / 2;
            } else {
                position /= 2;
            }
        } while (position != 1);
        return times;
    }
}

第三题:替换字符串中的括号内容

直接模拟就可以了。先把knowledge里的数据放到HashMap里,后续可以直接O(1)根据key获取到value进行替换。
遍历字符串,碰到左括号记录一下下标,碰到右括号记录一下下标,取出(left, right]范围的字符串,去HashMap里查找value,如果能查找到,做替换,查找不到,替换成"?",拼接到结果里。
碰到字符,看下这个字符在不在左右括号里面,如果不在,就直接拼接到结果里。

import java.util.HashMap;
import java.util.List;

class Solution {
    public String evaluate(String s, List<List<String>> knowledge) {
        HashMap<String, String> hashMap = new HashMap<>();
        for (List<String> list : knowledge) {
            hashMap.put(list.get(0), list.get(1));
        }
        StringBuilder stringBuilder = new StringBuilder();
        int length = s.length(), left = -1, right = -1;
        String key, value;
        boolean in = false;
        for (int i = 0; i < length; i++) {
            if (s.charAt(i) == '(') {
                left = i + 1;
                in = true;
            } else if (s.charAt(i) == ')') {
                right = i;
                key = s.substring(left, right);
                value = hashMap.get(key);
                if (value == null) {
                    value = "?";
                }
                stringBuilder.append(value);
                in = false;
            } else {
                if (!in) {
                    stringBuilder.append(s.charAt(i));
                }
            }
        }
        return stringBuilder.toString();
    }
}

第四题:好因子的最大数目

根据题意,可以知道n满足: n = a 1 b 1 × a 2 b 2 × … … × a k b k n=a_{1}^{b_{1}} \times a_{2}^{b_{2}} \times …… \times a_{k}^{b_{k}} n=a1b1×a2b2××akbk,其中 a 1 , a 2 , … … , a k a_{1},a_{2},……,a_{k} a1,a2,,ak都是n的质因子,而且满足 b 1 + b 2 + … … + b k < = p r i m e F a c t o r s b_{1}+b_{2}+……+b_{k}<=primeFactors b1+b2++bk<=primeFactors
好因子:如果n的一个因子可以被n的每一个质因数整除,我们称这个因子是好因子。
在找好因子个数的时候,可以这么考虑,举个例子吧。
假设 n = a 1 b 1 × a 2 b 2 × a 3 b 3 n=a_{1}^{b_{1}} \times a_{2}^{b_{2}} \times a_{3}^{b_{3}} n=a1b1×a2b2×a3b3 b 1 , b 2 , b 3 b_{1},b_{2},b_{3} b1,b2,b3的数量都大于1, a 1 , a 2 , a 3 a_{1},a_{2},a_{3} a1,a2,a3按照从小到大排列。
那么,最小的好因子是 g o o d F a c t o r = 1 个 a 1 × 1 个 a 2 × 1 个 a 3 goodFactor=1个 a_{1} \times 1个 a_{2} \times 1个 a_{3} goodFactor=1a1×1a2×1a3,比它大一点的下一个好因子是 g o o d F a c t o r = 2 个 a 1 × 1 个 a 2 × 1 个 a 3 goodFactor=2个 a_{1} \times 1个 a_{2} \times 1个 a_{3} goodFactor=2a1×1a2×1a3,……,最大的好因子是 g o o d F a c t o r = b 1 个 a 1 × b 2 个 a 2 × b 3 个 a 3 goodFactor=b_{1} 个 a_{1} \times b_{2} 个 a_{2} \times b_{3} 个 a_{3} goodFactor=b1a1×b2a2×b3a3,也就是n本身,那么n的好因子个数为 r e s u l t = b 1 × b 2 × … … × b k result=b_{1} \times b_{2} \times …… \times b_{k} result=b1×b2××bk
于是,已知原问题变成了: b 1 + b 2 + … … + b k < = p r i m e F a c t o r s b_{1}+b_{2}+……+b_{k}<=primeFactors b1+b2++bk<=primeFactors,求解 r e s u l t = b 1 × b 2 × … … × b k result=b_{1} \times b_{2} \times …… \times b_{k} result=b1×b2××bk的最大值。
在和一定的情况下,要想商最大,就要将primeFactors按照3个3个的分隔,分隔出来若干个3,然后相乘。
为什么是3个3个的分隔,2个2个的分隔行不行?
考虑这样一个例子: 2 + 2 + 2 = 3 + 3 , 2 × 2 × 2 < 3 × 3 2+2+2=3+3,2 \times 2 \times 2 < 3 \times 3 2+2+2=3+32×2×2<3×3,因为8 < 9,所以3个3个的分隔。
primeFactors对3取余可能有3种情况:0,1,2。
如果余数是0,那么就是3个3个的分隔,正好可以分配完。
如果余数是1,那么把最后一个3和余数的1,按照2和2进行拆分,因为 2 × 2 > 1 × 3 2 \times 2 > 1 \times 3 2×2>1×3
如果余数是2,那么就把这个2乘到结果里去即可。
要求result,就要用到快速幂取模,可以在 O ( l o g 2 N ) O(log_{2}N) O(log2N)时间内求得,还要注意在计算过程中用long,防止中间结果爆int。

class Solution {
    public int maxNiceDivisors(int primeFactors) {
        if (primeFactors < 4) {
            return primeFactors;
        }
        int p = primeFactors / 3, q = primeFactors % 3, MOD = 1_000_000_007;
        long result = 0;
        if (q == 0) {
            result = powWithMod(3, p, MOD);
        } else if (q == 1) {
            result = powWithMod(3, p - 1, MOD) * 2 * 2;
        } else {
            result = powWithMod(3, p, MOD) * 2;
        }
        return (int) (result % MOD);
    }

    private long powWithMod(int a, int b, int c) {
        long result = 1, base = a % c;
        while (b > 0) {
            if ((b & 1) == 1) {
                result = result * base % c;
            }
            base = base * base % c;
            b >>= 1;
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值