LeetCode 每日一题 Day 167-181

826. 安排工作以达到最大收益

你有 n 个工作和 m 个工人。给定三个数组: difficulty, profit 和 worker ,其中:

difficulty[i] 表示第 i 个工作的难度,profit[i] 表示第 i 个工作的收益。
worker[i] 是第 i 个工人的能力,即该工人只能完成难度小于等于 worker[i] 的工作。
每个工人 最多 只能安排 一个 工作,但是一个工作可以 完成多次 。

举个例子,如果 3 个工人都尝试完成一份报酬为 $1 的同样工作,那么总收益为 $3 。如果一个工人不能完成任何工作,他的收益为 $0 。
返回 在把工人分配到工作岗位后,我们所能获得的最大利润 。

示例 1:

输入: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
输出: 100
解释: 工人被分配的工作难度是 [4,4,6,6] ,分别获得 [20,20,30,30] 的收益。
示例 2:

输入: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25]
输出: 0

提示:

n == difficulty.length
n == profit.length
m == worker.length
1 <= n, m <= 1e4
1 <= difficulty[i], profit[i], worker[i] <= 1e5

排序+双指针(居然和灵神思路一样):

class Solution {
public:
    int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit,
                            vector<int>& worker) {
        sort(worker.begin(), worker.end());
        int n = profit.size();
        vector<pair<int, int>> jobs;
        for (int i = 0; i < n; ++i) {
            jobs.emplace_back(difficulty[i], profit[i]);
        }
        sort(jobs.begin(), jobs.end());
        int ans = 0, mx = 0, i = 0;
        for (int w : worker) {
            while (i < n && jobs[i].first <= w) {
                mx = max(mx, jobs[i++].second);
            }
            ans += mx;
        }
        return ans;
    }
};

2644. 找出可整除性得分最大的整数

给你两个下标从 0 开始的整数数组 nums 和 divisors 。

divisors[i] 的 可整除性得分 等于满足 nums[j] 能被 divisors[i] 整除的下标 j 的数量。

返回 可整除性得分 最大的整数 divisors[i] 。如果有多个整数具有最大得分,则返回数值最小的一个。

示例 1:

输入:nums = [4,7,9,3,9], divisors = [5,2,3]
输出:3
解释:divisors 中每个元素的可整除性得分为:
divisors[0] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 5 整除。
divisors[1] 的可整除性得分为 1 ,因为 nums[0] 能被 2 整除。
divisors[2] 的可整除性得分为 3 ,因为 nums[2]、nums[3] 和 nums[4] 都能被 3 整除。
因此,返回 divisors[2] ,它的可整除性得分最大。
示例 2:

输入:nums = [20,14,21,10], divisors = [5,7,5]
输出:5
解释:divisors 中每个元素的可整除性得分为:
divisors[0] 的可整除性得分为 2 ,因为 nums[0] 和 nums[3] 都能被 5 整除。
divisors[1] 的可整除性得分为 2 ,因为 nums[1] 和 nums[2] 都能被 7 整除。
divisors[2] 的可整除性得分为 2 ,因为 nums[0] 和 nums[3] 都能被5整除。
由于 divisors[0]、divisors[1] 和 divisors[2] 的可整除性得分都是最大的,因此,我们返回数值最小的一个,即 divisors[2] 。
示例 3:

输入:nums = [12], divisors = [10,16]
输出:10
解释:divisors 中每个元素的可整除性得分为:
divisors[0] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 10 整除。
divisors[1] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 16 整除。
由于 divisors[0] 和 divisors[1] 的可整除性得分都是最大的,因此,我们返回数值最小的一个,即 divisors[0] 。

提示:

1 <= nums.length, divisors.length <= 1000
1 <= nums[i], divisors[i] <= 1e9

暴力枚举即可:

class Solution {
public:
    int maxDivScore(vector<int>& nums, vector<int>& divisors) {
        int ans = divisors[0];
        int mx = 0;
        for (int div : divisors) {
            int cnt = 0;
            for (int x : nums) {
                cnt += x % div == 0;
            }
            if (mx < cnt) {
                mx = cnt;
                ans = div;
            } else if (mx == cnt) {
                ans = min(ans, div);
            }
        }
        return ans;
    }
};

1535. 找出数组游戏的赢家

给你一个由 不同 整数组成的整数数组 arr 和一个整数 k 。

每回合游戏都在数组的前两个元素(即 arr[0] 和 arr[1] )之间进行。比较 arr[0] 与 arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的 赢家 。

返回赢得比赛的整数。

题目数据 保证 游戏存在赢家。

示例 1:

输入:arr = [2,1,3,5,4,6,7], k = 2
输出:5
解释:一起看一下本场游戏每回合的情况:
在这里插入图片描述

因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。
示例 2:

输入:arr = [3,2,1], k = 10
输出:3
解释:3 将会在前 10 个回合中连续获胜。
示例 3:

输入:arr = [1,9,8,2,3,7,6,4,5], k = 7
输出:9
示例 4:

输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000
输出:99

提示:

2 <= arr.length <= 10^5
1 <= arr[i] <= 10^6
arr 所含的整数 各不相同 。
1 <= k <= 10^9

简单模拟:

class Solution {
public:
    int getWinner(vector<int>& arr, int k) {
        int cur = arr[0], win = 0;
        for (int i = 1; i < arr.size(); ++i) {
            if (arr[i] > cur) {
                cur = arr[i];
                win = 0;
            }
            if (++win == k) {
                break;
            }
        }
        return cur;
    }
};

1542. 找出最长的超赞子字符串(Hard)

给你一个字符串 s 。请返回 s 中最长的 超赞子字符串 的长度。

「超赞子字符串」需满足满足下述两个条件:

该字符串是 s 的一个非空子字符串
进行任意次数的字符交换后,该字符串可以变成一个回文字符串

示例 1:

输入:s = “3242415”
输出:5
解释:“24241” 是最长的超赞子字符串,交换其中的字符后,可以得到回文 “24142”
示例 2:

输入:s = “12345678”
输出:1
示例 3:

输入:s = “213123”
输出:6
解释:“213123” 是最长的超赞子字符串,交换其中的字符后,可以得到回文 “231132”
示例 4:

输入:s = “00”
输出:2

提示:

1 <= s.length <= 10^5
s 仅由数字组成

状压+前缀和(太数学了):

class Solution {
public:
    int longestAwesome(string s) {
        vector<int> first(1024, INT_MAX);
        int res = 0, status = 0;
        first[0] = -1;
        for (int i = 0; i < s.size(); ++i) {
            status ^= (1 << (s[i] - '0'));
            if (first[status] != INT_MAX)
                res = max(res, i - first[status]);
            else
                first[status] = i;
            for (int j = 0; j <= 9; ++j) {
                res = max(res, i - first[status ^ (1 << j)]);
            }
        }
        return res;
    }
};

2769. 找出最大的可达成数字

给你两个整数 num 和 t 。

如果整数 x 可以在执行下述操作不超过 t 次的情况下变为与 num 相等,则称其为 可达成数字 :

每次操作将 x 的值增加或减少 1 ,同时可以选择将 num 的值增加或减少 1 。
返回所有可达成数字中的最大值。可以证明至少存在一个可达成数字。

示例 1:

输入:num = 4, t = 1
输出:6
解释:最大可达成数字是 x = 6 ,执行下述操作可以使其等于 num :

  • x 减少 1 ,同时 num 增加 1 。此时,x = 5 且 num = 5 。
    可以证明不存在大于 6 的可达成数字。
    示例 2:

输入:num = 3, t = 2
输出:7
解释:最大的可达成数字是 x = 7 ,执行下述操作可以使其等于 num :

  • x 减少 1 ,同时 num 增加 1 。此时,x = 6 且 num = 4 。
  • x 减少 1 ,同时 num 增加 1 。此时,x = 5 且 num = 5 。
    可以证明不存在大于 7 的可达成数字。

提示:

1 <= num, t <= 50

最短的一次(bushi):

class Solution {
public:
    int theMaximumAchievableX(int num, int t) {
        return num + 2 * t;
    }
};

数学思维题

2225. 找出输掉零场或一场比赛的玩家

给你一个整数数组 matches 其中 matches[i] = [winneri, loseri] 表示在一场比赛中 winneri 击败了 loseri 。

返回一个长度为 2 的列表 answer :

answer[0] 是所有 没有 输掉任何比赛的玩家列表。
answer[1] 是所有恰好输掉 一场 比赛的玩家列表。
两个列表中的值都应该按 递增 顺序返回。

注意:

只考虑那些参与 至少一场 比赛的玩家。
生成的测试用例保证 不存在 两场比赛结果 相同 。

示例 1:

输入:matches = [[1,3],[2,3],[3,6],[5,6],[5,7],[4,5],[4,8],[4,9],[10,4],[10,9]]
输出:[[1,2,10],[4,5,7,8]]
解释:
玩家 1、2 和 10 都没有输掉任何比赛。
玩家 4、5、7 和 8 每个都输掉一场比赛。
玩家 3、6 和 9 每个都输掉两场比赛。
因此,answer[0] = [1,2,10] 和 answer[1] = [4,5,7,8] 。
示例 2:

输入:matches = [[2,3],[1,3],[5,4],[6,4]]
输出:[[1,2,5,6],[]]
解释:
玩家 1、2、5 和 6 都没有输掉任何比赛。
玩家 3 和 4 每个都输掉两场比赛。
因此,answer[0] = [1,2,5,6] 和 answer[1] = [] 。

提示:

1 <= matches.length <= 1e5
matches[i].length == 2
1 <= winneri, loseri<= 1e5
winneri != loseri
所有 matches[i] 互不相同

哈希排序:

class Solution {
public:
    vector<vector<int>> findWinners(vector<vector<int>>& matches) {
        map<int, int> cnt;
        for (auto& e : matches) {
            if (!cnt.contains(e[0])) {
                cnt[e[0]] = 0;
            }
            ++cnt[e[1]];
        }
        vector<vector<int>> ans(2);
        for (auto& [x, v] : cnt) {
            if (v < 2) {
                ans[v].push_back(x);
            }
        }
        return ans;
    }
};


2831. 找出最长等值子数组

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

如果子数组中所有元素都相等,则认为子数组是一个 等值子数组 。注意,空数组是 等值子数组 。

从 nums 中删除最多 k 个元素后,返回可能的最长等值子数组的长度。

子数组 是数组中一个连续且可能为空的元素序列。

示例 1:

输入:nums = [1,3,2,3,1,3], k = 3
输出:3
解释:最优的方案是删除下标 2 和下标 4 的元素。
删除后,nums 等于 [1, 3, 3, 3] 。
最长等值子数组从 i = 1 开始到 j = 3 结束,长度等于 3 。
可以证明无法创建更长的等值子数组。
示例 2:

输入:nums = [1,1,2,2,1,1], k = 2
输出:4
解释:最优的方案是删除下标 2 和下标 3 的元素。
删除后,nums 等于 [1, 1, 1, 1] 。
数组自身就是等值子数组,长度等于 4 。
可以证明无法创建更长的等值子数组。

提示:

1 <= nums.length <= 1e5
1 <= nums[i] <= nums.length
0 <= k <= nums.length

滑窗+分组(菜鸡滑窗忘了,灵神题解):

class Solution {
public:
    int longestEqualSubarray(vector<int>& nums, int k) {
        int n = nums.size();
        vector<vector<int>> pos_lists(n + 1);
        for (int i = 0; i < n; i++) {
            int x = nums[i];
            pos_lists[x].push_back(i - pos_lists[x].size());
        }

        int ans = 0;
        for (auto& pos : pos_lists) {
            int left = 0;
            for (int right = 0; right < pos.size(); right++) {
                while (pos[right] - pos[left] > k) { // 要删除的数太多了
                    left++;
                }
                ans = max(ans, right - left + 1);
            }
        }
        return ans;
    }
};

题解:分组+滑动窗口

1673. 找出最具竞争力的子序列

给你一个整数数组 nums 和一个正整数 k ,返回长度为 k 且最具 竞争力 的 nums 子序列。

数组的子序列是从数组中删除一些元素(可能不删除元素)得到的序列。

在子序列 a 和子序列 b 第一个不相同的位置上,如果 a 中的数字小于 b 中对应的数字,那么我们称子序列 a 比子序列 b(相同长度下)更具 竞争力 。 例如,[1,3,4] 比 [1,3,5] 更具竞争力,在第一个不相同的位置,也就是最后一个位置上, 4 小于 5 。

示例 1:

输入:nums = [3,5,2,6], k = 2
输出:[2,6]
解释:在所有可能的子序列集合 {[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]} 中,[2,6] 最具竞争力。
示例 2:

输入:nums = [2,4,3,3,5,4,9,6], k = 4
输出:[2,3,3,4]

提示:

1 <= nums.length <= 1e5
0 <= nums[i] <= 1e9
1 <= k <= nums.length

单调栈:

class Solution {
public:
    vector<int> mostCompetitive(vector<int>& nums, int k) {
        vector<int> stk;
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            while (stk.size() && stk.back() > nums[i] &&
                   stk.size() + n - i > k) {
                stk.pop_back();
            }
            if (stk.size() < k) {
                stk.push_back(nums[i]);
            }
        }
        return stk;
    }
};

灵神的题解讲解非常好,不会单调栈的读者可以学学:
跟着我过一遍示例 2,你就明白怎么做了

2903. 找出满足差值条件的下标 I

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,以及整数 indexDifference 和整数 valueDifference 。

你的任务是从范围 [0, n - 1] 内找出 2 个满足下述所有条件的下标 i 和 j :

abs(i - j) >= indexDifference 且
abs(nums[i] - nums[j]) >= valueDifference
返回整数数组 answer。如果存在满足题目要求的两个下标,则 answer = [i, j] ;否则,answer = [-1, -1] 。如果存在多组可供选择的下标对,只需要返回其中任意一组即可。

注意:i 和 j 可能 相等 。

示例 1:

输入:nums = [5,1,4,1], indexDifference = 2, valueDifference = 4
输出:[0,3]
解释:在示例中,可以选择 i = 0 和 j = 3 。
abs(0 - 3) >= 2 且 abs(nums[0] - nums[3]) >= 4 。
因此,[0,3] 是一个符合题目要求的答案。
[3,0] 也是符合题目要求的答案。
示例 2:

输入:nums = [2,1], indexDifference = 0, valueDifference = 0
输出:[0,0]
解释:
在示例中,可以选择 i = 0 和 j = 0 。
abs(0 - 0) >= 0 且 abs(nums[0] - nums[0]) >= 0 。
因此,[0,0] 是一个符合题目要求的答案。
[0,1]、[1,0] 和 [1,1] 也是符合题目要求的答案。
示例 3:

输入:nums = [1,2,3], indexDifference = 2, valueDifference = 4
输出:[-1,-1]
解释:在示例中,可以证明无法找出 2 个满足所有条件的下标。
因此,返回 [-1,-1] 。

提示:

1 <= n == nums.length <= 100
0 <= nums[i] <= 50
0 <= indexDifference <= 100
0 <= valueDifference <= 50

双指针,灵神题解:

class Solution {
public:
    vector<int> findIndices(vector<int>& nums, int indexDifference,
                            int valueDifference) {
        int max_idx = 0, min_idx = 0;
        for (int j = indexDifference; j < nums.size(); j++) {
            int i = j - indexDifference;
            if (nums[i] > nums[max_idx]) {
                max_idx = i;
            } else if (nums[i] < nums[min_idx]) {
                min_idx = i;
            }
            if (nums[max_idx] - nums[j] >= valueDifference) {
                return {max_idx, j};
            }
            if (nums[j] - nums[min_idx] >= valueDifference) {
                return {min_idx, j};
            }
        }
        return {-1, -1};
    }
};

题解:O(n) 做法:双指针+维护最大最小

1738. 找出第 K 大的异或坐标值

给你一个二维矩阵 matrix 和一个整数 k ,矩阵大小为 m x n 由非负整数组成。

矩阵中坐标 (a, b) 的 目标值 可以通过对所有元素 matrix[i][j] 执行异或运算得到,其中 i 和 j 满足 0 <= i <= a < m 且 0 <= j <= b < n(下标从 0 开始计数)。

请你找出 matrix 的所有坐标中第 k 大的目标值(k 的值从 1 开始计数)。

示例 1:

输入:matrix = [[5,2],[1,6]], k = 1
输出:7
解释:坐标 (0,1) 的目标值是 5 XOR 2 = 7 ,为最大的目标值。
示例 2:

输入:matrix = [[5,2],[1,6]], k = 2
输出:5
解释:坐标 (0,0) 的目标值是 5 = 5 ,为第 2 大的目标值。
示例 3:

输入:matrix = [[5,2],[1,6]], k = 3
输出:4
解释:坐标 (1,0) 的目标值是 5 XOR 1 = 4 ,为第 3 大的目标值。
示例 4:

输入:matrix = [[5,2],[1,6]], k = 4
输出:0
解释:坐标 (1,1) 的目标值是 5 XOR 2 XOR 1 XOR 6 = 0 ,为第 4 大的目标值。

提示:

m == matrix.length
n == matrix[i].length
1 <= m, n <= 1000
0 <= matrix[i][j] <= 1e6
1 <= k <= m * n

二位前缀异或和(和灵神一样思路!):

class Solution {
public:
    int kthLargestValue(vector<vector<int>>& matrix, int k) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> pre(m + 1, vector<int>(n + 1));
        vector<int> results;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                pre[i][j] = pre[i - 1][j] ^ pre[i][j - 1] ^ pre[i - 1][j - 1] ^
                            matrix[i - 1][j - 1];
                results.push_back(pre[i][j]);
            }
        }

        sort(results.begin(), results.end(), greater<int>());
        return results[k - 1];
    }
};

2028. 找出缺失的观测数据

现有一份 n + m 次投掷单个 六面 骰子的观测数据,骰子的每个面从 1 到 6 编号。观测数据中缺失了 n 份,你手上只拿到剩余 m 次投掷的数据。幸好你有之前计算过的这 n + m 次投掷数据的 平均值 。

给你一个长度为 m 的整数数组 rolls ,其中 rolls[i] 是第 i 次观测的值。同时给你两个整数 mean 和 n 。

返回一个长度为 n 的数组,包含所有缺失的观测数据,且满足这 n + m 次投掷的 平均值 是 mean 。如果存在多组符合要求的答案,只需要返回其中任意一组即可。如果不存在答案,返回一个空数组。

k 个数字的 平均值 为这些数字求和后再除以 k 。

注意 mean 是一个整数,所以 n + m 次投掷的总和需要被 n + m 整除。

示例 1:

输入:rolls = [3,2,4,3], mean = 4, n = 2
输出:[6,6]
解释:所有 n + m 次投掷的平均值是 (3 + 2 + 4 + 3 + 6 + 6) / 6 = 4 。
示例 2:

输入:rolls = [1,5,6], mean = 3, n = 4
输出:[2,3,2,2]
解释:所有 n + m 次投掷的平均值是 (1 + 5 + 6 + 2 + 3 + 2 + 2) / 7 = 3 。
示例 3:

输入:rolls = [1,2,3,4], mean = 6, n = 4
输出:[]
解释:无论丢失的 4 次数据是什么,平均值都不可能是 6 。
示例 4:

输入:rolls = [1], mean = 3, n = 1
输出:[5]
解释:所有 n + m 次投掷的平均值是 (1 + 5) / 2 = 3 。

提示:

m == rolls.length
1 <= n, m <= 105
1 <= rolls[i], mean <= 6

数学+构造:

class Solution {
public:
    vector<int> missingRolls(vector<int>& rolls, int mean, int n) {
        int m = rolls.size();
        int total = mean * (n + m);
        int sum_given = accumulate(rolls.begin(), rolls.end(), 0);
        int sum_missing = total - sum_given;

        if (sum_missing < n || sum_missing > 6 * n) {
            return {};
        }

        vector<int> missing(n, 1);
        sum_missing -= n;

        for (int i = 0; i < n; ++i) {
            int add = min(5, sum_missing);
            missing[i] += add;
            sum_missing -= add;
        }

        return missing;
    }
};

菜鸡第一次碰见这样类型的题orz

2951. 找出峰值

给你一个下标从 0 开始的数组 mountain 。你的任务是找出数组 mountain 中的所有 峰值。

以数组形式返回给定数组中 峰值 的下标,顺序不限 。

注意:

峰值 是指一个严格大于其相邻元素的元素。
数组的第一个和最后一个元素 不 是峰值。

示例 1:

输入:mountain = [2,4,4]
输出:[]
解释:mountain[0] 和 mountain[2] 不可能是峰值,因为它们是数组的第一个和最后一个元素。
mountain[1] 也不可能是峰值,因为它不严格大于 mountain[2] 。
因此,答案为 [] 。
示例 2:

输入:mountain = [1,4,3,8,5]
输出:[1,3]
解释:mountain[0] 和 mountain[4] 不可能是峰值,因为它们是数组的第一个和最后一个元素。
mountain[2] 也不可能是峰值,因为它不严格大于 mountain[3] 和 mountain[1] 。
但是 mountain[1] 和 mountain[3] 严格大于它们的相邻元素。
因此,答案是 [1,3] 。

提示:

3 <= mountain.length <= 100
1 <= mountain[i] <= 100

简单遍历:

class Solution {
public:
    vector<int> findPeaks(vector<int>& mountain) {
        vector<int> peaks;
        for (int i = 1; i < mountain.size() - 1; i++) {
            if (mountain[i] > mountain[i - 1] &&
                mountain[i] > mountain[i + 1]) {
                peaks.push_back(i);
            }
        }
        return peaks;
    }
};

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

给你一个仅由小写英文字母组成的字符串 s 。

如果一个字符串仅由单一字符组成,那么它被称为 特殊 字符串。例如,字符串 “abc” 不是特殊字符串,而字符串 “ddd”、“zz” 和 “f” 是特殊字符串。

返回在 s 中出现 至少三次 的 最长特殊子字符串 的长度,如果不存在出现至少三次的特殊子字符串,则返回 -1 。

子字符串 是字符串中的一个连续 非空 字符序列。

示例 1:

输入:s = “aaaa”
输出:2
解释:出现三次的最长特殊子字符串是 “aa” :子字符串 “aaaa”、“aaaa” 和 “aaaa”。
可以证明最大长度是 2 。
示例 2:

输入:s = “abcdef”
输出:-1
解释:不存在出现至少三次的特殊子字符串。因此返回 -1 。
示例 3:

输入:s = “abcaba”
输出:1
解释:出现三次的最长特殊子字符串是 “a” :子字符串 “abcaba”、“abcaba” 和 “abcaba”。
可以证明最大长度是 1 。

提示:

3 <= s.length <= 50
s 仅由小写英文字母组成。

灵神题解,分类讨论:

class Solution {
public:
    int maximumLength(string s) {
        vector<int> groups[26];
        int cnt = 0, n = s.length();
        for (int i = 0; i < n; i++) {
            cnt++;
            if (i + 1 == n || s[i] != s[i + 1]) {
                groups[s[i] - 'a'].push_back(cnt); // 统计连续字符长度
                cnt = 0;
            }
        }

        int ans = 0;
        for (auto& a : groups) {
            if (a.empty())
                continue;
            ranges::sort(a, greater());
            a.push_back(0);
            a.push_back(0); // 假设还有两个空串
            ans = max({ans, a[0] - 2, min(a[0] - 1, a[1]), a[2]});
        }

        return ans ? ans : -1;
    }
};

题解:非暴力做法,分类讨论

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

给你一个仅由小写英文字母组成的字符串 s 。

如果一个字符串仅由单一字符组成,那么它被称为 特殊 字符串。例如,字符串 “abc” 不是特殊字符串,而字符串 “ddd”、“zz” 和 “f” 是特殊字符串。

返回在 s 中出现 至少三次 的 最长特殊子字符串 的长度,如果不存在出现至少三次的特殊子字符串,则返回 -1 。

子字符串 是字符串中的一个连续 非空 字符序列。

示例 1:

输入:s = “aaaa”
输出:2
解释:出现三次的最长特殊子字符串是 “aa” :子字符串 “aaaa”、“aaaa” 和 “aaaa”。
可以证明最大长度是 2 。
示例 2:

输入:s = “abcdef”
输出:-1
解释:不存在出现至少三次的特殊子字符串。因此返回 -1 。
示例 3:

输入:s = “abcaba”
输出:1
解释:出现三次的最长特殊子字符串是 “a” :子字符串 “abcaba”、“abcaba” 和 “abcaba”。
可以证明最大长度是 1 。

提示:

3 <= s.length <= 5 * 1e5
s 仅由小写英文字母组成。

思路同上题:

class Solution {
public:
    int maximumLength(string s) {
        vector<int> groups[26];
        int cnt = 0, n = s.length();
        for (int i = 0; i < n; i++) {
            cnt++;
            if (i + 1 == n || s[i] != s[i + 1]) {
                groups[s[i] - 'a'].push_back(cnt);
                cnt = 0;
            }
        }

        int ans = 0;
        for (auto& a : groups) {
            if (a.empty())
                continue;
            ranges::sort(a, greater());
            a.push_back(0);
            a.push_back(0);
            ans = max({ans, a[0] - 2, min(a[0] - 1, a[1]), a[2]});
        }

        return ans ? ans : -1;
    }
};

2965. 找出缺失和重复的数字

给你一个下标从 0 开始的二维整数矩阵 grid,大小为 n * n ,其中的值在 [1, n2] 范围内。除了 a 出现 两次,b 缺失 之外,每个整数都 恰好出现一次 。

任务是找出重复的数字a 和缺失的数字 b 。

返回一个下标从 0 开始、长度为 2 的整数数组 ans ,其中 ans[0] 等于 a ,ans[1] 等于 b 。

示例 1:

输入:grid = [[1,3],[2,2]]
输出:[2,4]
解释:数字 2 重复,数字 4 缺失,所以答案是 [2,4] 。
示例 2:

输入:grid = [[9,1,7],[8,9,2],[3,4,6]]
输出:[9,5]
解释:数字 9 重复,数字 5 缺失,所以答案是 [9,5] 。

提示:

2 <= n == grid.length == grid[i].length <= 50
1 <= grid[i][j] <= n * n
对于所有满足1 <= x <= n * n 的 x ,恰好存在一个 x 与矩阵中的任何成员都不相等。
对于所有满足1 <= x <= n * n 的 x ,恰好存在一个 x 与矩阵中的两个成员相等。
除上述的两个之外,对于所有满足1 <= x <= n * n 的 x ,都恰好存在一对 i, j 满足 0 <= i, j <= n - 1 且 grid[i][j] == x 。

菜鸡又不会了,统计元素出现次数:

class Solution {
public:
    vector<int> findMissingAndRepeatedValues(vector<vector<int>>& grid) {
        int n = grid.size();
        vector<int> cnt(n * n + 1);
        for (auto& row : grid) {
            for (int x : row) {
                cnt[x]++;
            }
        }

        vector<int> ans(2);
        for (int i = 1; i <= n * n; i++) {
            if (cnt[i] == 2) {
                ans[0] = i; // 出现两次的数
            } else if (cnt[i] == 0) {
                ans[1] = i; // 出现零次的数
            }
        }
        return ans;
    }
};

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XforeverZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值