跳至主要內容

分组循环

大约 3 分钟

分组循环

题目难度
2943. 最大化网格图中正方形空洞的面积open in new window中等
2948. 交换得到字典序最小的数组open in new window中等
2953. 统计完全子字符串open in new window中等
2957. 消除相邻近似相等字符open in new window中等
2982. 找出出现至少三次的最长特殊子字符串 IIopen in new window中等

模板

    int n = s.length;
    int ans = 0, i = 0;
    while (i < n) {
        // 分组循环
        int st = i;
        for (i++; i < n && Math.abs(s[i] - s[i - 1]) <= 2; i++) {
        }
        ans += ...;
    }

2943. 最大化网格图中正方形空洞的面积

组内间隔为 1。

import java.util.Arrays;

public class Solution2943 {
    public int maximizeSquareHoleArea(int n, int m, int[] hBars, int[] vBars) {
        int maxH = getMax(hBars);
        int maxV = getMax(vBars);
        int min = Math.min(maxH, maxV);
        return min * min;
    }

    private int getMax(int[] bars) {
        int n = bars.length;
        Arrays.sort(bars);
        int max = 0;
        int i = 0;
        while (i < n) {
            // 分组循环
            int st = i;
            for (i++; i < n && bars[i] - bars[i - 1] == 1; i++) {
            }
            max = Math.max(max, i - st + 1);
        }
        return max;
    }
}

2948. 交换得到字典序最小的数组

组内间隔小于等于 limit。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Solution2948 {
    // 时间复杂度 O(nlogn)
    public int[] lexicographicallySmallestArray(int[] nums, int limit) {
        int n = nums.length;
        Integer[] ids = new Integer[n];
        for (int i = 0; i < n; i++) ids[i] = i;
        Arrays.sort(ids, Comparator.comparingInt(o -> nums[o]));

        int[] ans = new int[n];
        int i = 0;
        while (i < n) {
            // 分组循环
            int st = i;
            for (i++; i < n && nums[ids[i]] - nums[ids[i - 1]] <= limit; i++) {
            }
            Integer[] subIds = Arrays.copyOfRange(ids, st, i);
            Arrays.sort(subIds);
            for (int j = 0; j < subIds.length; j++) {
                ans[subIds[j]] = nums[ids[st + j]];
            }
        }
        return ans;
    }
}

2953. 统计完全子字符串

组内 字母表中的位置相差 至多 为 2。

public class Solution2953 {
    private char[] s;
    private int k;

    public int countCompleteSubstrings(String word, int k) {
        this.s = word.toCharArray();
        this.k = k;

        int n = s.length;
        int ans = 0, i = 0;
        while (i < n) {
            // 分组循环
            int st = i;
            for (i++; i < n && Math.abs(s[i] - s[i - 1]) <= 2; i++) {
            }
            ans += getSubAns(st, i);
        }
        return ans;
    }

    private int getSubAns(int st, int end) {
        int len = end - st;
        int res = 0;
        for (int m = 1; m <= 26 && m * k <= len; m++) {
            int span = m * k;
            // 滑动窗口
            int[] cnt = new int[26];
            for (int i = 0; i < span; i++) {
                cnt[s[st + i] - 'a']++;
            }
            if (checkAllEqK(cnt)) res++;
            for (int i = span; i < len; i++) {
                cnt[s[st + i] - 'a']++;
                cnt[s[st + i - span] - 'a']--;
                if (checkAllEqK(cnt)) res++;
            }
        }
        return res;
    }

    private boolean checkAllEqK(int[] cnt) {
        for (int i = 0; i < 26; i++) {
            if (cnt[i] > 0 && cnt[i] != k) {
                return false;
            }
        }
        return true;
    }
}

2957. 消除相邻近似相等字符

组内 在字母表中是相邻的。

public class Solution2957 {
    public int removeAlmostEqualCharacters(String word) {
        int n = word.length();
        char[] s = word.toCharArray();
        int ans = 0;
        int i = 0;
        while (i < n) {
            // 分组循环
            int st = i;
            for (i++; i < n && Math.abs(s[i] - s[i - 1]) <= 1; i++) {
            }
            ans += (i - st) / 2;
        }
        return ans;
    }
}

2982. 找出出现至少三次的最长特殊子字符串 II

组内 字母是相同的。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Solution2982 {
    public int maximumLength(String s) {
        int n = s.length();
        char[] cs = s.toCharArray();
        int[] cnt = new int[26];
        Map<Character, List<Integer>> mp = new HashMap<>();
        int i = 0;
        while (i < n) {
            int st = i;
            for (i++; i < n && cs[i] == cs[i - 1]; i++) {
            }
            mp.computeIfAbsent(cs[st], e -> new ArrayList<>()).add(i - st);
            cnt[cs[st] - 'a'] += i - st;
        }
        int ans = -1;
        for (Map.Entry<Character, List<Integer>> entry : mp.entrySet()) {
            List<Integer> list = entry.getValue();
            list.sort(Comparator.reverseOrder());
            if (cnt[entry.getKey() - 'a'] < 3) continue;

            // top1 三等分
            int res = list.get(0) - 2;
            ans = Math.max(ans, res);
            // top1 二等分 + top2
            if (list.size() >= 2) {
                res = Math.min(list.get(0) - 1, list.get(1));
                ans = Math.max(ans, res);
            }
            // top1 + top2 + top3
            if (list.size() >= 3) {
                res = list.get(2);
                ans = Math.max(ans, res);
            }
        }
        return ans;
    }
}

(全文完)