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;
    }
}

性能

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);
    }

}

性能

3330.找到初始输入字符串I

目标

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

尽管 Alice 尽可能集中注意力,她仍然可能会犯错 至多 一次。

给你一个字符串 word ,它表示 最终 显示在 Alice 显示屏上的结果。

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

示例 1:

输入:word = "abbcccc"
输出:5
解释:
可能的字符串包括:"abbcccc" ,"abbccc" ,"abbcc" ,"abbc" 和 "abcccc" 。

示例 2:

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

示例 3:

输入:word = "aaaa"
输出:4

提示:

  • 1 <= word.length <= 100
  • word 只包含小写英文字母。

思路

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

找到相邻的重复字符,假设重复了 k 次,那么就有 k 种可能(即多输入了 0 次、1 次、……、k - 1 次)。假设总共有 l 个相邻重复字符,需要减去 l - 1,因为多录入 0 次被重复计数了。

代码


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

    public int possibleStringCount(String word) {
        int res = 0;
        int n = word.length();
        int l = 0, r = 0, cnt = 0;
        while (r < n) {
            while (r < n && word.charAt(r) == word.charAt(l)) {
                r++;
            }
            int p = r - l;
            cnt += p == 0 ? 0 : 1;
            res += p;
            l = r;
        }
        return res - cnt + 1;
    }

}

性能

594.最长和谐子序列

目标

和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。

给你一个整数数组 nums ,请你在所有可能的 子序列 中找到最长的和谐子序列的长度。

数组的 子序列 是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。

示例 1:

输入:nums = [1,3,2,2,5,2,3,7]
输出:5
解释:
最长和谐子序列是 [3,2,2,2,3]。

示例 2:

输入:nums = [1,2,3,4]
输出:2
解释:
最长和谐子序列是 [1,2],[2,3] 和 [3,4],长度都为 2。

示例 3:

输入:nums = [1,1,1,1]
输出:0
解释:
不存在和谐子序列。

说明:

  • 1 <= nums.length <= 2 * 10^4
  • -10^9 <= nums[i] <= 10^9

思路

统计数字出现次数,求相邻频次之和的最大值。

代码


/**
 * @date 2025-06-30 8:46
 */
public class FindLHS {

    public int findLHS(int[] nums) {
        int n = nums.length;
        Map<Integer, Integer> cnt = new HashMap<>();
        for (int i = 0; i < n; i++) {
            cnt.merge(nums[i], 1, Integer::sum);
        }
        int res = 0;
        for (Map.Entry<Integer, Integer> entry : cnt.entrySet()) {
            int key = entry.getKey();
            Integer nextVal = cnt.get(key + 1);
            if (nextVal != null) {
                res = Math.max(res, entry.getValue() + nextVal);
            }
        }
        return res;
    }
}

性能

2099.找到和最大的长度为K的子序列

目标

给你一个整数数组 nums 和一个整数 k 。你需要找到 nums 中长度为 k 的 子序列 ,且这个子序列的 和最大 。

请你返回 任意 一个长度为 k 的整数子序列。

子序列 定义为从一个数组里删除一些元素后,不改变剩下元素的顺序得到的数组。

示例 1:

输入:nums = [2,1,3,3], k = 2
输出:[3,3]
解释:
子序列有最大和:3 + 3 = 6 。

示例 2:

输入:nums = [-1,-2,3,4], k = 3
输出:[-1,3,4]
解释:
子序列有最大和:-1 + 3 + 4 = 6 。

示例 3:

输入:nums = [3,4,3,3], k = 2
输出:[3,4]
解释:
子序列有最大和:3 + 4 = 7 。
另一个可行的子序列为 [4, 3] 。

说明:

  • 1 <= nums.length <= 1000
  • -10^5 <= nums[i] <= 10^5
  • 1 <= k <= nums.length

思路

返回数组任意一个长度为 k 并且和最大的子序列。

将元素值与下标绑定后按元素值排序,取值最大的 k 个元素,然后再按下标排序即可。

有网友最后没有使用排序,而是记录临界元素 e 以及它在子序列中的个数 cnt,遍历原数组,如果大于 e 直接加入答案,如果等于 e 则需要判断 cnt 的剩余个数。

代码


/**
 * @date 2025-06-28 9:44
 */
public class MaxSubsequence2099 {

    public int[] maxSubsequence(int[] nums, int k) {
        int n = nums.length;
        int[][] arr = new int[n][2];
        for (int i = 0; i < n; i++) {
            arr[i] = new int[]{nums[i], i};
        }
        Arrays.sort(arr, (a, b) -> a[0] - b[0]);
        int[] res = new int[k];
        int[][] subArr = new int[k][2];
        System.arraycopy(arr, n - k, subArr, 0, k);
        Arrays.sort(subArr, (a, b) -> a[1] - b[1]);
        for (int i = 0; i < k; i++) {
            res[i] = subArr[i][0];
        }
        return res;
    }
}

性能

2200.找出数组中的所有K近邻下标

目标

给你一个下标从 0 开始的整数数组 nums 和两个整数 key 和 k 。K 近邻下标 是 nums 中的一个下标 i ,并满足至少存在一个下标 j 使得 |i - j| <= k 且 nums[j] == key 。

以列表形式返回按 递增顺序 排序的所有 K 近邻下标。

示例 1:

输入:nums = [3,4,9,1,3,9,5], key = 9, k = 1
输出:[1,2,3,4,5,6]
解释:因此,nums[2] == key 且 nums[5] == key 。
- 对下标 0 ,|0 - 2| > k 且 |0 - 5| > k ,所以不存在 j 使得 |0 - j| <= k 且 nums[j] == key 。所以 0 不是一个 K 近邻下标。
- 对下标 1 ,|1 - 2| <= k 且 nums[2] == key ,所以 1 是一个 K 近邻下标。
- 对下标 2 ,|2 - 2| <= k 且 nums[2] == key ,所以 2 是一个 K 近邻下标。
- 对下标 3 ,|3 - 2| <= k 且 nums[2] == key ,所以 3 是一个 K 近邻下标。
- 对下标 4 ,|4 - 5| <= k 且 nums[5] == key ,所以 4 是一个 K 近邻下标。
- 对下标 5 ,|5 - 5| <= k 且 nums[5] == key ,所以 5 是一个 K 近邻下标。
- 对下标 6 ,|6 - 5| <= k 且 nums[5] == key ,所以 6 是一个 K 近邻下标。
因此,按递增顺序返回 [1,2,3,4,5,6] 。 

示例 2:

输入:nums = [2,2,2,2,2], key = 2, k = 2
输出:[0,1,2,3,4]
解释:对 nums 的所有下标 i ,总存在某个下标 j 使得 |i - j| <= k 且 nums[j] == key ,所以每个下标都是一个 K 近邻下标。 
因此,返回 [0,1,2,3,4] 。

说明:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000
  • key 是数组 nums 中的一个整数
  • 1 <= k <= nums.length

思路

返回数组中元素值为 keyk 临近下标,即元素 key 的下标以及其左右 k 个下标。要求以递增顺序返回,不能包含重复下标。

遍历数组,判断 nums[i] 是否等于 k,如果相等则将左右两侧的 k 个下标加入答案。使用一个指针标记当前已经记录的最大下标,避免将重复的下标加入答案。

代码


/**
 * @date 2025-06-24 0:11
 */
public class FindKDistantIndices2200 {

    public List<Integer> findKDistantIndices(int[] nums, int key, int k) {
        List<Integer> res = new ArrayList<>();
        int n = nums.length;
        int r = -1;
        for (int i = 0; i < n; i++) {
            if (nums[i] == key) {
                int l = Math.max(r + 1, i - k);
                r = Math.min(n - 1, i + k);
                for (int j = l; j <= r; j++) {
                    res.add(j);
                }
            }
        }
        return res;
    }

}

性能

2138.将字符串拆分为若干长度为k的组

目标

字符串 s 可以按下述步骤划分为若干长度为 k 的组:

  • 第一组由字符串中的前 k 个字符组成,第二组由接下来的 k 个字符串组成,依此类推。每个字符都能够成为 某一个 组的一部分。
  • 对于最后一组,如果字符串剩下的字符 不足 k 个,需使用字符 fill 来补全这一组字符。

注意,在去除最后一个组的填充字符 fill(如果存在的话)并按顺序连接所有的组后,所得到的字符串应该是 s 。

给你一个字符串 s ,以及每组的长度 k 和一个用于填充的字符 fill ,按上述步骤处理之后,返回一个字符串数组,该数组表示 s 分组后 每个组的组成情况。

示例 1:

输入:s = "abcdefghi", k = 3, fill = "x"
输出:["abc","def","ghi"]
解释:
前 3 个字符是 "abc" ,形成第一组。
接下来 3 个字符是 "def" ,形成第二组。
最后 3 个字符是 "ghi" ,形成第三组。
由于所有组都可以由字符串中的字符完全填充,所以不需要使用填充字符。
因此,形成 3 组,分别是 "abc"、"def" 和 "ghi" 。

示例 2:

输入:s = "abcdefghij", k = 3, fill = "x"
输出:["abc","def","ghi","jxx"]
解释:
与前一个例子类似,形成前三组 "abc"、"def" 和 "ghi" 。
对于最后一组,字符串中仅剩下字符 'j' 可以用。为了补全这一组,使用填充字符 'x' 两次。
因此,形成 4 组,分别是 "abc"、"def"、"ghi" 和 "jxx" 。

说明:

  • 1 <= s.length <= 100
  • s 仅由小写英文字母组成
  • 1 <= k <= 100
  • fill 是一个小写英文字母

思路

将字符串划分为长度为 k 的组,如果长度不足则使用 fill 补全。

代码


/**
 * @date 2025-06-22 12:16
 */
public class DivideString2138 {

    public String[] divideString(String s, int k, char fill) {
        int n = s.length();
        String[] res = new String[n / k + (n % k == 0 ? 0 : 1)];
        char[] chars = s.toCharArray();
        StringBuilder sb = new StringBuilder();
        int j = 0;
        for (int i = 0; i < n; i++) {
            if (i != 0 && i % k == 0) {
                res[j++] = sb.toString();
                sb = new StringBuilder();
            }
            sb.append(chars[i]);
        }
        int cnt = k - sb.length();
        while (cnt > 0) {
            sb.append(fill);
            cnt--;
        }
        if (j == res.length - 1) {
            res[j] = sb.toString();
        }
        return res;
    }

}

性能

2016.增量元素之间的最大差值

目标

给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < n 且 nums[i] < nums[j] 。

返回 最大差值 。如果不存在满足要求的 i 和 j ,返回 -1 。

示例 1:

输入:nums = [7,1,5,4]
输出:4
解释:
最大差值出现在 i = 1 且 j = 2 时,nums[j] - nums[i] = 5 - 1 = 4 。
注意,尽管 i = 1 且 j = 0 时 ,nums[j] - nums[i] = 7 - 1 = 6 > 4 ,但 i > j 不满足题面要求,所以 6 不是有效的答案。

示例 2:

输入:nums = [9,4,3,2]
输出:-1
解释:
不存在同时满足 i < j 和 nums[i] < nums[j] 这两个条件的 i, j 组合。

示例 3:

输入:nums = [1,5,2,10]
输出:9
解释:
最大差值出现在 i = 0 且 j = 3 时,nums[j] - nums[i] = 10 - 1 = 9 。

说明:

  • n == nums.length
  • 2 <= n <= 1000
  • 1 <= nums[i] <= 10^9

思路

找出递增元素的最大差值。

遍历数组,找出当前的最小值,用当前值减去最小值即增量元素的差值,取其最大值即可。

代码


/**
 * @date 2025-06-16 0:17
 */
public class MaximumDifference2016 {

    public int maximumDifference(int[] nums) {
        int min = Integer.MAX_VALUE;
        int res = 0;
        for (int num : nums) {
            min = Math.min(min, num);
            res = Math.max(res, num - min);
        }
        return res == 0 ? -1 : res;
    }
}

性能

2566.替换一个数字后的最大差值

目标

给你一个整数 num 。你知道 Bob 会偷偷将 0 到 9 中的一个数字 替换 成另一个数字。

请你返回将 num 中 恰好一个 数字进行替换后,得到的最大值和最小值的差为多少。

注意:

  • 当 Bob 将一个数字 d1 替换成另一个数字 d2 时,Bob 需要将 nums 中所有 d1 都替换成 d2 。
  • Bob 可以将一个数字替换成它自己,也就是说 num 可以不变。
  • Bob 可以将数字分别替换成两个不同的数字分别得到最大值和最小值。
  • 替换后得到的数字可以包含前导 0 。

示例 1:

输入:num = 11891
输出:99009
解释:
为了得到最大值,我们将数字 1 替换成数字 9 ,得到 99899 。
为了得到最小值,我们将数字 1 替换成数字 0 ,得到 890 。
两个数字的差值为 99009 。

示例 2:

输入:num = 90
输出:99
解释:
可以得到的最大值是 99(将 0 替换成 9),最小值是 0(将 9 替换成 0)。
所以我们得到 99 。

说明:

  • 1 <= num <= 10^8

思路

num 中选择一个数字 d,可以将 num 中所有的 d 都替换成另一个数字(允许包含前导零),返回能够得到的最大值与最小值的差。

贪心策略,找到第一个不是 9 的数字 a,将 num 中所有 a 都替换为 9 得到最大数字。定义 num 第一个数字为 b,将 num 中的所有 b 替换为 0 即为最小数字。

代码


/**
 * @date 2025-06-14 9:49
 */
public class MinMaxDifference2566 {

    public int minMaxDifference(int num) {
        String s = String.valueOf(num);
        char[] chars = s.toCharArray();
        int n = s.length();
        int mul = (int) Math.pow(10, n - 1);
        int max = num, min = num;
        char maxReplace = '-';
        char minReplace = chars[0];
        for (int i = 0; i < n; i++) {
            if (maxReplace == '-' && chars[i] != '9') {
                maxReplace = chars[i];
            }
            if (minReplace == chars[i]) {
                min -= mul * (chars[i] - '0');
            }
            if (maxReplace == chars[i]) {
                max += mul * (9 - (chars[i] - '0'));
            }
            mul /= 10;
        }
        return max - min;
    }

}

性能

3423.循环数组中相邻元素的最大差值

目标

给你一个 循环 数组 nums ,请你找出相邻元素之间的 最大 绝对差值。

注意:一个循环数组中,第一个元素和最后一个元素是相邻的。

示例 1:

输入:nums = [1,2,4]
输出:3
解释:
由于 nums 是循环的,nums[0] 和 nums[2] 是相邻的,它们之间的绝对差值是最大值 |4 - 1| = 3 。

示例 2:

输入:nums = [-5,-10,-5]
输出:5
解释:
相邻元素 nums[0] 和 nums[1] 之间的绝对差值为最大值 |-5 - (-10)| = 5 。

说明:

  • 2 <= nums.length <= 100
  • -100 <= nums[i] <= 100

思路

依题意模拟即可。

代码


/**
 * @date 2025-06-12 0:02
 */
public class MaxAdjacentDistance3423 {

    public int maxAdjacentDistance(int[] nums) {
        int res = 0;
        int n = nums.length;
        for (int i = 1; i <= n; i++) {
            res = Math.max(res, Math.abs(nums[i % n] - nums[i - 1]));
        }
        return res;
    }
}

性能