3169.无需开会的工作日

目标

给你一个正整数 days,表示员工可工作的总天数(从第 1 天开始)。另给你一个二维数组 meetings,长度为 n,其中 meetings[i] = [start_i, end_i] 表示第 i 次会议的开始和结束天数(包含首尾)。

返回员工可工作且没有安排会议的天数。

注意:会议时间可能会有重叠。

示例 1:

输入:days = 10, meetings = [[5,7],[1,3],[9,10]]
输出:2
解释:
第 4 天和第 8 天没有安排会议。

示例 2:

输入:days = 5, meetings = [[2,4],[1,3]]
输出:1
解释:
第 5 天没有安排会议。

示例 3:

输入:days = 6, meetings = [[1,6]]
输出:0
解释:
所有工作日都安排了会议。

说明:

  • 1 <= days <= 10^9
  • 1 <= meetings.length <= 10^5
  • meetings[i].length == 2
  • 1 <= meetings[i][0] <= meetings[i][1] <= days

思路

在区间 [1, days] 上有一些区间 [si, ei],求没有被这些区间覆盖的正整数个数。

将区间按起点排序,记录已访问区间的最大终点 prevEndsi - prevEnd - 1 即为当前区间与上一个区间之间的整数个数。注意特殊处理开头与结尾。

网友题解则是合并相交的区间,用总数减去区间覆盖的整数即为答案。

代码


/**
 * @date 2025-07-11 18:53
 */
public class CountDays3169 {

    public int countDays(int days, int[][] meetings) {
        Arrays.sort(meetings, (a, b) -> a[0] - b[0]);
        int res = 0;
        int prevEnd = 0;
        for (int[] meeting : meetings) {
            int interval = meeting[0] - prevEnd - 1;
            res += Math.max(interval, 0);
            prevEnd = Math.max(prevEnd, meeting[1]);
        }
        return res + Math.max(0, days - prevEnd);
    }

}

性能

3440.重新安排会议得到最多空余时间II

目标

给你一个整数 eventTime 表示一个活动的总时长,这个活动开始于 t = 0 ,结束于 t = eventTime 。

同时给你两个长度为 n 的整数数组 startTime 和 endTime 。它们表示这次活动中 n 个时间 没有重叠 的会议,其中第 i 个会议的时间为 [startTime[i], endTime[i]] 。

你可以重新安排 至多 一个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。

请你返回重新安排会议以后,可以得到的 最大 空余时间。

注意,会议 不能 安排到整个活动的时间以外,且会议之间需要保持互不重叠。

注意:重新安排会议以后,会议之间的顺序可以发生改变

示例 1:

输入:eventTime = 5, startTime = [1,3], endTime = [2,5]
输出:2
解释:
将 [1, 2] 的会议安排到 [2, 3] ,得到空余时间 [0, 2] 。

示例 2:

输入:eventTime = 10, startTime = [0,7,9], endTime = [1,8,10]
输出:7
解释:
将 [0, 1] 的会议安排到 [8, 9] ,得到空余时间 [0, 7] 。

示例 3:

输入:eventTime = 10, startTime = [0,3,7,9], endTime = [1,4,8,10]
输出:6
解释:
将 [3, 4] 的会议安排到 [8, 9] ,得到空余时间 [1, 7] 。

示例 4:

输入:eventTime = 5, startTime = [0,1,2,3,4], endTime = [1,2,3,4,5]
输出:0
解释:
活动中的所有时间都被会议安排满了。

说明:

  • 1 <= eventTime <= 10^9
  • n == startTime.length == endTime.length
  • 2 <= n <= 10^5
  • 0 <= startTime[i] < endTime[i] <= eventTime
  • endTime[i] <= startTime[i + 1] 其中 i 在范围 [0, n - 2] 之间。

思路

有一个活动有 n 个时间不重叠的会议,重新安排 1 个会议议程,使得空余时间最大。

3439.重新安排会议得到最多空余时间I 相比,本题只能重新安排一个会议,但是允许打乱原有的会议顺序。

对于当前会议,如果除了其左右两侧的空余位置之外存在空余位置大于会议时间,那么空余时间是其左右两侧的空余时间加上会议时间。否则,可以将会议左移或者右移到边界,空余时间为左右空余时间之和。

因此可以求出前三大的空余时间,如果会议时间小于等于第三大的空余时间,说明总是可以移到左右空余之外。否则就需要判断当前空余时间是否大于第二、第一大的空余时间,以及是否恰好是其左右空余。

代码


/**
 * @date 2025-07-10 22:15
 */
public class MaxFreeTime3440 {

    public int maxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        int n = startTime.length;
        int[] gap = new int[n + 1];
        int[] intervals = new int[n];
        Arrays.setAll(intervals, i -> endTime[i] - startTime[i]);
        int[] a = new int[]{0, 0};
        int[] b = new int[]{0, 0};
        int[] c = new int[]{0, 0};
        for (int i = 0; i <= n; i++) {
            if (i == 0) {
                gap[i] = startTime[i];
            } else if (i == n) {
                gap[i] = eventTime - endTime[i - 1];
            } else {
                gap[i] = startTime[i] - endTime[i - 1];
            }
            if (gap[i] >= a[0]) {
                c = b;
                b = a;
                a = new int[]{gap[i], i};
            } else if (gap[i] >= b[0]) {
                c = b;
                b = new int[]{gap[i], i};
            } else if (gap[i] >= c[0]) {
                c = new int[]{gap[i], i};
            }
        }
        int res = a[0];
        for (int i = 0; i < n; i++) {
            int g = gap[i] + gap[i + 1];
            if (intervals[i] > a[0]) {
                res = Math.max(res, g);
            } else if (intervals[i] <= c[0]) {
                res = Math.max(res, g + intervals[i]);
            } else if (intervals[i] <= b[0] && (b[1] != i && b[1] != i + 1)) {
                res = Math.max(res, g + intervals[i]);
            } else if (a[1] != i && a[1] != i + 1) {
                res = Math.max(res, g + intervals[i]);
            } else {
                res = Math.max(res, g);
            }
        }
        return res;
    }

}

性能

3439.重新安排会议得到最多空余时间I

目标

给你一个整数 eventTime 表示一个活动的总时长,这个活动开始于 t = 0 ,结束于 t = eventTime 。

同时给你两个长度为 n 的整数数组 startTime 和 endTime 。它们表示这次活动中 n 个时间 没有重叠 的会议,其中第 i 个会议的时间为 [startTime[i], endTime[i]] 。

你可以重新安排 至多 k 个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。

移动前后所有会议之间的 相对 顺序需要保持不变,而且会议时间也需要保持互不重叠。

请你返回重新安排会议以后,可以得到的 最大 空余时间。

注意,会议 不能 安排到整个活动的时间以外。

示例 1:

输入:eventTime = 5, k = 1, startTime = [1,3], endTime = [2,5]
输出:2
解释:
将 [1, 2] 的会议安排到 [2, 3] ,得到空余时间 [0, 2] 。

示例 2:

输入:eventTime = 10, k = 1, startTime = [0,2,9], endTime = [1,4,10]
输出:6
解释:
将 [2, 4] 的会议安排到 [1, 3] ,得到空余时间 [3, 9] 。

示例 3:

输入:eventTime = 5, k = 2, startTime = [0,1,2,3,4], endTime = [1,2,3,4,5]
输出:0
解释:
活动中的所有时间都被会议安排满了。

说明:

  • 1 <= eventTime <= 10^9
  • n == startTime.length == endTime.length
  • 2 <= n <= 10^5
  • 1 <= k <= n
  • 0 <= startTime[i] < endTime[i] <= eventTime
  • endTime[i] <= startTime[i + 1] 其中 i 在范围 [0, n - 2] 之间。

思路

有一个活动有 n 个时间不重叠的会议,重新安排 k 个会议议程,使得空余时间最大。

先根据会议时间排序,滑动窗口计算 k 个会议的总时间,以及 [end[l - 1], start[r + 1]],相减即为窗口内的最大空余时间。

代码


/**
 * @date 2025-07-09 8:52
 */
public class MaxFreeTime3439 {

    public int maxFreeTime(int eventTime, int k, int[] startTime, int[] endTime) {
        int n = startTime.length;
        int[][] interval = new int[n + 2][2];
        interval[0][1] = 0;
        for (int i = 1; i <= n; i++) {
            interval[i] = new int[]{startTime[i - 1], endTime[i - 1]};
        }
        interval[n + 1][0] = eventTime;
        int l = 1;
        int res = 0, sum = 0;
        for (int r = 1; r <= n; r++) {
            sum += interval[r][1] - interval[r][0];
            if (r - l == k - 1) {
                res = Math.max(res, interval[r + 1][0] - interval[l - 1][1] - sum);
                sum -= interval[l][1] - interval[l][0];
                l++;
            }
        }
        return res;
    }

}

性能

1751.最多可以参加的会议数目II

目标

给你一个 events 数组,其中 events[i] = [startDayi, endDayi, valuei] ,表示第 i 个会议在 startDayi 天开始,第 endDayi 天结束,如果你参加这个会议,你能得到价值 valuei 。同时给你一个整数 k 表示你能参加的最多会议数目。

你同一时间只能参加一个会议。如果你选择参加某个会议,那么你必须 完整 地参加完这个会议。会议结束日期是包含在会议内的,也就是说你不能同时参加一个开始日期与另一个结束日期相同的两个会议。

请你返回能得到的会议价值 最大和 。

示例 1:

输入:events = [[1,2,4],[3,4,3],[2,3,1]], k = 2
输出:7
解释:选择绿色的活动会议 0 和 1,得到总价值和为 4 + 3 = 7 。

示例 2:

输入:events = [[1,2,4],[3,4,3],[2,3,10]], k = 2
输出:10
解释:参加会议 2 ,得到价值和为 10 。
你没法再参加别的会议了,因为跟会议 2 有重叠。你 不 需要参加满 k 个会议。

示例 3:

输入:events = [[1,1,1],[2,2,2],[3,3,3],[4,4,4]], k = 3
输出:9
解释:尽管会议互不重叠,你只能参加 3 个会议,所以选择价值最大的 3 个会议。

说明:

  • 1 <= k <= events.length
  • 1 <= k * events.length <= 10^6
  • 1 <= startDayi <= endDayi <= 10^9
  • 1 <= valuei <= 10^6

思路

n 个会议中选择 k 个日期不冲突的参加,求参加会议的最大价值之和。

1353.最多可以参加的会议数目 不同之处在于必须从头到尾全程参会,并且最多参加 k 个。

定义 dp[i][k] 表示前 i - 1 个会议至多参加 k 个所能获得的最大价值。i == 0 表示没有参加任何会议。

按照结束时间排序,如果选择当前会议,则需要找到最后一个结束时间小于当前开始时间的下标 j,可以使用二分查找。

代码


/**
 * @date 2025-07-08 8:47
 */
public class MaxValue1751 {

    public int maxValue(int[][] events, int k) {
        Arrays.sort(events, (a, b) -> a[1] - b[1]);
        int n = events.length;
        int[][] dp = new int[n + 1][k + 1];
        for (int i = 0; i < n; i++) {
            int prev = find(events, events[i][0]);
            for (int j = 1; j <= k; j++) {
                dp[i + 1][j] = Math.max(dp[i][j], dp[prev + 1][j - 1] + events[i][2]);
            }
        }
        return dp[n][k];
    }

    public int find(int[][] events, int target) {
        int r = events.length - 1;
        int l = 0;
        int mid = l + (r - l) / 2;
        while (l <= r) {
            if (events[mid][1] < target) {
                l = mid + 1;
            } else {
                r = mid - 1;
            }
            mid = l + (r - l) / 2;
        }
        return r;
    }

}

性能

1353.最多可以参加的会议数目

目标

给你一个数组 events,其中 events[i] = [startDayi, endDayi] ,表示会议 i 开始于 startDayi ,结束于 endDayi 。

你可以在满足 startDayi <= d <= endDayi 中的任意一天 d 参加会议 i 。在任意一天 d 中只能参加一场会议。

请你返回你可以参加的 最大 会议数目。

示例 1:

输入:events = [[1,2],[2,3],[3,4]]
输出:3
解释:你可以参加所有的三个会议。
安排会议的一种方案如上图。
第 1 天参加第一个会议。
第 2 天参加第二个会议。
第 3 天参加第三个会议。

示例 2:

输入:events= [[1,2],[2,3],[3,4],[1,2]]
输出:4

说明:​​​​​​

  • 1 <= events.length <= 10^5
  • events[i].length == 2
  • 1 <= startDayi <= endDayi <= 10^5

思路

二维数组 events 表示会议的开始与结束时间,每天最多参加一次会议求最多可以参加几个会议。

按开始时间分组,记录结束时间列表,优先参加结束时间最小的会议。遍历每一天,去掉过期的会议结束时间,将当前的结束时间列表加入优先队列,取最小的结束时间,如果大于等于开始时间则计入答案。

代码


/**
 * @date 2025-07-07 9:07
 */
public class MaxEvents1353 {

    public int maxEvents(int[][] events) {
        int max = 0;
        for (int[] event : events) {
            max = Math.max(max, event[1]);
        }
        List<Integer>[] groups = new List[max + 1];
        Arrays.setAll(groups, x -> new ArrayList<>());
        for (int[] event : events) {
            groups[event[0]].add(event[1]);
        }
        PriorityQueue<Integer> q = new PriorityQueue<>();
        int res = 0;
        for (int i = 1; i <= max; i++) {
            while (!q.isEmpty() && q.peek() < i) {
                q.poll();
            }
            q.addAll(groups[i]);
            if (!q.isEmpty()) {
                res++;
                q.poll();
            }
        }
        return res;
    }

}

性能

1865.找出和为指定值的下标对

目标

给你两个整数数组 nums1 和 nums2 ,请你实现一个支持下述两类查询的数据结构:

  1. 累加 ,将一个正整数加到 nums2 中指定下标对应元素上。
  2. 计数 ,统计满足 nums1[i] + nums2[j] 等于指定值的下标对 (i, j) 数目(0 <= i < nums1.length 且 0 <= j < nums2.length)。

实现 FindSumPairs 类:

  • FindSumPairs(int[] nums1, int[] nums2) 使用整数数组 nums1 和 nums2 初始化 FindSumPairs 对象。
  • void add(int index, int val) 将 val 加到 nums2[index] 上,即,执行 nums2[index] += val 。
  • int count(int tot) 返回满足 nums1[i] + nums2[j] == tot 的下标对 (i, j) 数目。

示例:

输入:
["FindSumPairs", "count", "add", "count", "count", "add", "add", "count"]
[[[1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]], [7], [3, 2], [8], [4], [0, 1], [1, 1], [7]]
输出:
[null, 8, null, 2, 1, null, null, 11]
解释:
FindSumPairs findSumPairs = new FindSumPairs([1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]);
findSumPairs.count(7);  // 返回 8 ; 下标对 (2,2), (3,2), (4,2), (2,4), (3,4), (4,4) 满足 2 + 5 = 7 ,下标对 (5,1), (5,5) 满足 3 + 4 = 7
findSumPairs.add(3, 2); // 此时 nums2 = [1,4,5,4,5,4]
findSumPairs.count(8);  // 返回 2 ;下标对 (5,2), (5,4) 满足 3 + 5 = 8
findSumPairs.count(4);  // 返回 1 ;下标对 (5,0) 满足 3 + 1 = 4
findSumPairs.add(0, 1); // 此时 nums2 = [2,4,5,4,5,4]
findSumPairs.add(1, 1); // 此时 nums2 = [2,5,5,4,5,4]
findSumPairs.count(7);  // 返回 11 ;下标对 (2,1), (2,2), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,4) 满足 2 + 5 = 7 ,下标对 (5,3), (5,5) 满足 3 + 4 = 7

说明:

  • 1 <= nums1.length <= 1000
  • 1 <= nums2.length <= 10^5
  • 1 <= nums1[i] <= 10^9
  • 1 <= nums2[i] <= 10^5
  • 0 <= index < nums2.length
  • 1 <= val <= 10^5
  • 1 <= tot <= 10^9
  • 最多调用 add 和 count 函数各 1000 次

思路

统计元素出现次数,针对每一个 count 操作,遍历 cnt1,累加 cnt1.get(x) * cnt2.get(tot - x) 即可。

代码


/**
 * @date 2025-07-06 16:48
 */
public class FindSumPairs1865 {

    class FindSumPairs {

        int[] nums1;
        int[] nums2;
        Map<Integer, Integer> cnt1 = new HashMap<>();
        Map<Integer, Integer> cnt2 = new HashMap<>();

        public FindSumPairs(int[] nums1, int[] nums2) {
            this.nums1 = nums1;
            this.nums2 = nums2;
            for (int num : nums1) {
                cnt1.merge(num, 1, Integer::sum);
            }
            for (int num : nums2) {
                cnt2.merge(num, 1, Integer::sum);

            }
        }

        public void add(int index, int val) {
            int key = nums2[index];
            cnt2.merge(key, -1, Integer::sum);
            if (cnt2.get(key) <= 0) {
                cnt2.remove(key);
            }
            nums2[index] += val;
            cnt2.merge(key + val, 1, Integer::sum);
        }

        public int count(int tot) {
            int res = 0;
            for (Map.Entry<Integer, Integer> entry : cnt1.entrySet()) {
                int key = entry.getKey();
                int value = entry.getValue();
                res += value * cnt2.getOrDefault(tot - key, 0);
            }
            return res;
        }
    }
}

性能

1394.找出数组中的幸运数

目标

在整数数组中,如果一个整数的出现频次和它的数值大小相等,我们就称这个整数为「幸运数」。

给你一个整数数组 arr,请你从中找出并返回一个幸运数。

  • 如果数组中存在多个幸运数,只需返回 最大 的那个。
  • 如果数组中不含幸运数,则返回 -1 。

示例 1:

输入:arr = [2,2,3,4]
输出:2
解释:数组中唯一的幸运数是 2 ,因为数值 2 的出现频次也是 2 。

示例 2:

输入:arr = [1,2,2,3,3,3]
输出:3
解释:1、2 以及 3 都是幸运数,只需要返回其中最大的 3 。

示例 3:

输入:arr = [2,2,2,3,3]
输出:-1
解释:数组中不存在幸运数。

示例 4:

输入:arr = [5]
输出:-1

示例 5:

输入:arr = [7,7,7,7,7,7,7]
输出:7

说明:

  • 1 <= arr.length <= 500
  • 1 <= arr[i] <= 500

思路

统计元素频次,从大到小找到频次与元素值相等的元素即可。

代码


/**
 * @date 2025-07-05 20:37
 */
public class FindLucky1394 {

    public int findLucky(int[] arr) {
        int[] cnt = new int[501];
        for (int num : arr) {
            cnt[num]++;
        }
        for (int i = 500; i > 0; i--) {
            if (cnt[i] == i) {
                return i;
            }
        }
        return -1;
    }
}

性能

3307.找出第K个字符II

目标

Alice 和 Bob 正在玩一个游戏。最初,Alice 有一个字符串 word = "a"。

给定一个正整数 k 和一个整数数组 operations,其中 operations[i] 表示第 i 次操作的类型。

现在 Bob 将要求 Alice 按顺序执行 所有 操作:

  • 如果 operations[i] == 0,将 word 的一份 副本追加 到它自身。
  • 如果 operations[i] == 1,将 word 中的每个字符 更改 为英文字母表中的 下一个 字符来生成一个新字符串,并将其 追加 到原始的 word。例如,对 "c" 进行操作生成 "cd",对 "zb" 进行操作生成 "zbac"。

在执行所有操作后,返回 word 中第 k 个字符的值。

注意,在第二种类型的操作中,字符 'z' 可以变成 'a'。

示例 1:

输入:k = 5, operations = [0,0,0]
输出:"a"
解释:
最初,word == "a"。Alice 按以下方式执行三次操作:
将 "a" 附加到 "a",word 变为 "aa"。
将 "aa" 附加到 "aa",word 变为 "aaaa"。
将 "aaaa" 附加到 "aaaa",word 变为 "aaaaaaaa"。

示例 2:

输入:k = 10, operations = [0,1,0,1]
输出:"b"
解释:
最初,word == "a"。Alice 按以下方式执行四次操作:
将 "a" 附加到 "a",word 变为 "aa"。
将 "bb" 附加到 "aa",word 变为 "aabb"。
将 "aabb" 附加到 "aabb",word 变为 "aabbaabb"。
将 "bbccbbcc" 附加到 "aabbaabb",word 变为 "aabbaabbbbccbbcc"。

说明:

  • 1 <= k <= 10^14
  • 1 <= operations.length <= 100
  • operations[i] 可以是 0 或 1。
  • 输入保证在执行所有操作后,word 至少有 k 个字符。

思路

开始的时候有一个字符 a,根据操作数组 operations 执行以下操作:

  • operations[i] == 0 时,将现有的所有字母拼接到当前字符后面。
  • operations[i] == 1 时,将现有的所有字母替换为它在字母表中的下一个字母(z 的下一个字母为 a),拼接到当前字符后面。

返回执行所有操作之后的第 k 个字母。

计算 tail = ceil(log2(k)) 表示操作次数的上界,如果 k <= 1 << tail,说明在左半边无需操作,否则在右半边,需要操作,它是从左半边的第 k - (1 << tail) 个元素转移而来,需要根据 operations[tail] 来确定字母是否变化。按照这个逻辑递归,直到 tail < 0,返回字母 a

代码


/**
 * @date 2025-07-04 9:19
 */
public class KthCharacter3307 {

    public char kthCharacter(long k, int[] operations) {
        return kthCharacter(k, operations, 63 - Long.numberOfLeadingZeros(k - 1));
    }

    public char kthCharacter(long k, int[] operations, int tail) {
        if (tail < 0) {
            return 'a';
        }
        long p = 1L << tail;
        if (k <= p) {
            return (char) ('a' + ((kthCharacter(k, operations, tail - 1) - 'a') % 26));
        }
        return (char) ('a' + (kthCharacter(k - p, operations, tail - 1) - 'a' + operations[tail]) % 26);
    }

}

性能

3304.找出第K个字符I

目标

Alice 和 Bob 正在玩一个游戏。最初,Alice 有一个字符串 word = "a"。

给定一个正整数 k。

现在 Bob 会要求 Alice 执行以下操作 无限次 :

  • 将 word 中的每个字符 更改 为英文字母表中的 下一个 字符来生成一个新字符串,并将其 追加 到原始的 word。

例如,对 "c" 进行操作生成 "cd",对 "zb" 进行操作生成 "zbac"。

在执行足够多的操作后, word 中 至少 存在 k 个字符,此时返回 word 中第 k 个字符的值。

注意,在操作中字符 'z' 可以变成 'a'。

示例 1:

输入:k = 5
输出:"b"
解释:
最初,word = "a"。需要进行三次操作:
生成的字符串是 "b",word 变为 "ab"。
生成的字符串是 "bc",word 变为 "abbc"。
生成的字符串是 "bccd",word 变为 "abbcbccd"。

示例 2:

输入:k = 10
输出:"c"

说明:

  • 1 <= k <= 500

思路

开始的时候有一个字符 a,可以反复执行以下操作:将现有的所有字母替换为它在字母表中的下一个字母(z 的下一个字母为 a),拼接到当前字符后面。返回第 k 个字母。

暴力模拟操作过程。

代码


/**
 * @date 2025-07-03 8:48
 */
public class KthCharacter3304 {

    public char kthCharacter(int k) {
        StringBuilder sb = new StringBuilder();
        sb.append('a');
        while (sb.length() < k) {
            String s = sb.toString();
            int length = s.length();
            for (int i = 0; i < length; i++) {
                char c = (char) ('a' + (s.charAt(i) - 'a' + 1) % 26);
                sb.append(c);
            }
        }
        return sb.toString().charAt(k - 1);
    }

}

性能

3333.找到初始输入字符串II

目标

Alice 正在她的电脑上输入一个字符串。但是她打字技术比较笨拙,她 可能 在一个按键上按太久,导致一个字符被输入 多次 。

给你一个字符串 word ,它表示 最终 显示在 Alice 显示屏上的结果。同时给你一个 正 整数 k ,表示一开始 Alice 输入字符串的长度 至少 为 k 。

请你返回 Alice 一开始可能想要输入字符串的总方案数。

由于答案可能很大,请你将它对 10^9 + 7 取余 后返回。

示例 1:

输入:word = "aabbccdd", k = 7
输出:5
解释:
可能的字符串包括:"aabbccdd" ,"aabbccd" ,"aabbcdd" ,"aabccdd" 和 "abbccdd" 。

示例 2:

输入:word = "aabbccdd", k = 8
输出:1
解释:
唯一可能的字符串是 "aabbccdd" 。

示例 3:

输入:word = "aaabbb", k = 3
输出:8

说明:

  • 1 <= word.length <= 5 * 10^5
  • word 只包含小写英文字母。
  • 1 <= k <= 2000

思路

有一个字符串,其中可能存在字符由于按键失灵没有及时抬起,导致该字符被输入多次。求原始字符串的总方案数,已知原字符串长度至少为 k

3330.找到初始输入字符串I 相比取消了至多一个错误的限制,增加了原始字符的长度限制。

// todo

代码

性能