0
点赞
收藏
分享

微信扫一扫

【周赛总结】周赛354

青乌 2023-07-20 阅读 56

周赛354

半个小时过了前三题,第四题超时看了好久,没看到限制字符串的长度最大只有10

特殊元素平方和【LC2778】

  • 思路

    简单模拟

  • 实现

    class Solution {
        public int sumOfSquares(int[] nums) {
            int n = nums.length;
            int res = 0;
            for (int i = 0; i < n; i++){
                if (n % (i + 1) == 0){
                    res += nums[i] * nums[i];
                }
            }
            return res;
    
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( n ) \mathcal{O}(n) O(n)
      • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

数组的最大美丽值【LC2779】

  • 思路:差分+前缀和

    每个 nums[i] 可以替换为范围 [nums[i] - k, nums[i] + k] 内的任一整数,因此可以使用差分数组记录能被修改至每个区间的整数个数,最后将其累加,求出能修改至某个值的最大个数返回即可

  • 实现

    class Solution {
        public int maximumBeauty(int[] nums, int k) {
            // 每个数组能改变的范围[nums[i]-k, nums[i] + k]->差分统计->前缀和还原 求最大值
            int mn = Integer.MAX_VALUE, mx = Integer.MIN_VALUE;
            int n = nums.length;
            for (int i = 0; i < n; i++){
                mn = Math.min(mn, nums[i] - k);
                mx = Math.max(mx, nums[i] + k);
            }
            // mn负数-mn
            
            mx -= mn;
            
            int[] d = new int[mx + 2];//[0, mx] [mn, mx]->[0, mx-mn]
            for (int num : nums){
                int l = num - k - mn, r = num + k - mn;
                d[l] += 1;
                d[r + 1] -= 1;
            }
            int res = 0, sum = 0;
            for (int i = 0; i <= mx; i++){
                sum += d[i];
                res = Math.max(res, sum);
            }
            return res;
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( n ) \mathcal{O}(n) O(n)
      • 空间复杂度: O ( n ) \mathcal{O}(n) O(n)

合法分割的最小下标【LC2780】

  • 思路

    • 分割数组后,分割后的数组的支配元素仍和原数组相等。
    • 先遍历数组,找到数组的支配元素及其出现次数
    • 然后枚举分割位置,记录分割数组中支配元素的次数,如果分割后的数组合法,那么返回当前分割点
  • 实现

    class Solution {
        public int minimumIndex(List<Integer> nums) {
            // 分割数组使分割后数组的支配元素和原数组相等
            Map<Integer,Integer> map = new HashMap<>();
            int val = -1, mx = -1;
            int n = nums.size();
            for (int i = 0; i < n; i++){
                int num = nums.get(i); 
                map.put(num, map.getOrDefault(num, 0) + 1);
                if (map.get(num) > mx){
                    val = num;              
                    mx = map.get(num);
                }
            }
            mx = map.get(val);
            int l = 0, r = mx;
            for (int i = 0; i < n - 1; i++){
                if (nums.get(i) == val){// [0, i][i + 1, n - 1]
                    l++;
                    r--;
                }
                if (l * 2 > (i + 1) && r * 2 > (n - i - 1)){
                    return i;
                }
            }
            return -1;
    
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( n ) \mathcal{O}(n) O(n)
      • 空间复杂度: O ( n ) \mathcal{O}(n) O(n)

最长合法子字符串的长度【LC2781】

区间dp+字符串哈希[TLE]

我就是个努力优化的小废物hhh 刚开始写思路的时候,想到了用双指针找,最后直接用区间dp了

class Solution {
    int base = 7;
    public int longestValidSubstring(String word, List<String> forbidden) {
        // 字符串哈希 + 区间dp
        // dp[i][j]:字符串s[i, j]是否是合法字符串
        // 使用字符串哈希求出forbidden中的值,并快速求出子字符串的哈希值,快速判断是否存在子字符串
        // 使用双指针求出最长长度
        int n = word.length();      
        long[] h = new long[n + 1];
        long[] p = new long[n + 1];
        p[0] = 1L;
        for (int i = 1; i <= n; i++){
            h[i] = h[i - 1] * base + word.charAt(i - 1);
            p[i] = p[i - 1] * base;
        }
        Set<Long> ff = new HashSet<>();
        for (String s : forbidden){
            ff.add(hash(s));
        }
        boolean[][] dp = new boolean[n][n];
        int res = 0;
        for (int len = 1; len <= n; len++){
            for (int l = 0; l + len - 1 < n; l++){
                int r = l + len - 1;
                dp[l][r] |= r - 1 >= 0 ? dp[l][r - 1] : false;
                dp[l][r] |= l + 1 < n ? dp[l + 1][r] : false;
                if (ff.contains(hash(l, r, h, p))){
                    dp[l][r] = true;// 包含
                }
                if (!dp[l][r]){
                    res = len;
                }
                if (res == n){
                    return res;
                }
            }
        }
        return res;
    }
    private long hash(int l , int r, long[] h, long[] p){
        return h[r + 1] - h[l] * p[r - l + 1];
    }
    private long hash(String s){
        int n = s.length();
        long res = 0L;
        for (int i = 0; i < n; i++){
            res = res * base + s.charAt(i);
        }
        return res;
    }
}
  • 复杂度
    • 时间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)
    • 空间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)

哈希表+同向双指针

  • 思路:哈希表+同向双指针

    • 合法字符串:字符串中不含有forbidden中的任一字符串
    • 双指针:固定左端点,枚举右端点,判断是否存在以右端点为结尾的子字符串出现在forbidden中,如果存在,那么右移左指针至不存在的位置。
      • 判断过程:枚举以右端点为结尾的子字符串,长度从小到大枚举至10【forbidden中长度最大为10,长度为10以上的字符串肯定不在forbidden中,不需要判断】,如果 w o r d [ i , l e f t ] word[i,left] word[i,left]在forbidden中,那么合法字符串的左边界只能从 i + 1 i+1 i+1开始
  • 实现

    class Solution {
        public int longestValidSubstring(String word, List<String> forbidden) {
            var fb = new HashSet<String>();
            fb.addAll(forbidden);
            int ans = 0, left = 0, n = word.length();
            for (int right = 0; right < n; right++) {
                for (int i = right; i >= left && i > right - 10; i--) {
                    if (fb.contains(word.substring(i, right + 1))) {
                        left = i + 1; // 当子串右端点 >= right 时,合法子串一定不能包含 word[i]
                        break;
                    }
                }
                ans = Math.max(ans, right - left + 1);
            }
            return ans;
        }
    }
    
    作者:灵茶山艾府
    链接:https://leetcode.cn/problems/length-of-the-longest-valid-substring/solutions/2345796/ha-xi-biao-shuang-zhi-zhen-pythonjavacgo-bcez/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度
      • 时间复杂度: O ( n ) \mathcal{O}(n) O(n)
      • 空间复杂度: O ( m ) \mathcal{O}(m) O(m),forbidden的大小
举报

相关推荐

0 条评论