跳至主要內容

力扣第 80 场双周赛

大约 2 分钟

力扣第 80 场双周赛

比赛时间 2022-06-11。本场周赛国服共 929 人 AK。

T1. 强密码检验器 II(3 分)

解题思路

模拟。可用 bit mask 来简洁编码。

时间复杂度:O(n)

参考代码

class Solution {
    public boolean strongPasswordCheckerII(String password) {
        // 它有至少 8 个字符
        if (password.length() < 8) {
            return false;
        }

        // 它 不 包含 2 个连续相同的字符
        for (int i = 1; i < password.length(); i++) {
            if (password.charAt(i) == password.charAt(i - 1)) {
                return false;
            }
        }

        // 至少包含 一个小写英文 字母。
        // 至少包含 一个大写英文 字母。
        // 至少包含 一个数字 。
        // 至少包含 一个特殊字符 。
        int mask = 0;
        for (char ch : password.toCharArray()) {
            if (Character.isLowerCase(ch)) {
                mask |= 1;
            } else if (Character.isUpperCase(ch)) {
                mask |= 2;
            } else if (Character.isDigit(ch)) {
                mask |= 4;
            } else if ("!@#$%^&*()-+".contains(String.valueOf(ch))) {
                mask |= 8;
            }
        }
        return mask == 15;
    }
}

T2. 咒语和药水的成功对数(4 分)

解题思路

potions 排序后二分查找 相乘 大于等于 success 的最小下标,即能求出 能成功组合的 药水 数目。

时间复杂度:O(nlogn)

参考代码

class Solution {
    public int[] successfulPairs(int[] spells, int[] potions, long success) {
        int n = spells.length;
        int m = potions.length;
        Arrays.sort(potions);

        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            int left = 0;
            int right = m;
            while (left < right) {
                int mid = left + (right - left) / 2;
                // 边界二分 F, F,..., F, [T, T,..., T]
                // ----------------------^
                if ((long) spells[i] * potions[mid] >= success) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            res[i] = m - left;
        }
        return res;
    }
}

T3. 替换字符后匹配(6 分)

解题思路

逆向模拟,枚举 s 中的每个与 sub 等长的子串,判断其能否由 sub 生成。

时间复杂度:O(n^2)

参考代码

class Solution {
    private Map<Character, Set<Character>> mappingsMap;

    public boolean matchReplacement(String s, String sub, char[][] mappings) {
        int sLen = s.length();
        int subLen = sub.length();

        mappingsMap = new HashMap<>();
        for (char[] mapping : mappings) {
            // new -> [old]
            mappingsMap.computeIfAbsent(mapping[1], key -> new HashSet<>()).add(mapping[0]);
        }

        for (int i = 0; i + subLen <= sLen; i++) {
            String subStr = s.substring(i, i + subLen);
            if (check(subStr, sub)) {
                return true;
            }
        }
        return false;
    }

    private boolean check(String subStr, String sub) {
        for (int j = 0; j < subStr.length(); j++) {
            char newi = subStr.charAt(j);
            char oldi = sub.charAt(j);
            if (newi != oldi) {
                if (!mappingsMap.containsKey(newi) || !mappingsMap.get(newi).contains(oldi)) {
                    return false;
                }
            }
        }
        return true;
    }
}

T4. 统计得分小于 K 的子数组数目(6 分)

解题思路

枚举每个 i(左边界),二分查找求 j(右边界),使得 [i,j] 的分数严格小于 k。每个 i 的贡献为 j-i+1。时间复杂度:O(nlogn)

也可用双指针在 时间复杂度:O(n) 内求解。

参考代码

class Solution {
    public long countSubarrays(int[] nums, long k) {
        int len = nums.length;

        // 前缀和
        long[] preSum = new long[len + 1];
        for (int i = 0; i < len; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }

        long cnt = 0L;
        // 枚举每个 i
        for (int i = 0; i < len; i++) {
            int left = i;
            int right = len;
            while (left < right) {
                int mid = left + (right - left) / 2;
                // 边界二分 F, F,..., F, [T, T,..., T]
                // ----------------------^
                if ((preSum[mid + 1] - preSum[i]) * (mid - i + 1L) >= k) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            // 每个 i 的贡献
            cnt += left - i + 1;
        }
        return cnt - len;
    }
}

(全文完)