118.杨辉三角

目标

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:

输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

示例 2:

输入: numRows = 1
输出: [[1]]

说明:

  • 1 <= numRows <= 30

思路

依题意模拟即可。

代码


/**
 * @date 2025-08-01 8:46
 */
public class Generate118 {

    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> firstRow = new ArrayList<>();
        firstRow.add(1);
        res.add(firstRow);
        for (int i = 1; i < numRows; i++) {
            List<Integer> tmp = new ArrayList<>(i + 1);
            tmp.add(1);
            List<Integer> list = res.get(i - 1);
            for (int j = 1; j < list.size(); j++) {
                tmp.add(list.get(j - 1) + list.get(j));
            }
            tmp.add(1);
            res.add(tmp);
        }
        return res;
    }

}

性能

2210.统计数组中峰和谷的数量

目标

给你一个下标从 0 开始的整数数组 nums 。如果两侧距 i 最近的不相等邻居的值均小于 nums[i] ,则下标 i 是 nums 中,某个峰的一部分。类似地,如果两侧距 i 最近的不相等邻居的值均大于 nums[i] ,则下标 i 是 nums 中某个谷的一部分。对于相邻下标 i 和 j ,如果 nums[i] == nums[j] , 则认为这两下标属于 同一个 峰或谷。

注意,要使某个下标所做峰或谷的一部分,那么它左右两侧必须 都 存在不相等邻居。

返回 nums 中峰和谷的数量。

示例 1:

输入:nums = [2,4,1,1,6,5]
输出:3
解释:
在下标 0 :由于 2 的左侧不存在不相等邻居,所以下标 0 既不是峰也不是谷。
在下标 1 :4 的最近不相等邻居是 2 和 1 。由于 4 > 2 且 4 > 1 ,下标 1 是一个峰。
在下标 2 :1 的最近不相等邻居是 4 和 6 。由于 1 < 4 且 1 < 6 ,下标 2 是一个谷。
在下标 3 :1 的最近不相等邻居是 4 和 6 。由于 1 < 4 且 1 < 6 ,下标 3 符合谷的定义,但需要注意它和下标 2 是同一个谷的一部分。
在下标 4 :6 的最近不相等邻居是 1 和 5 。由于 6 > 1 且 6 > 5 ,下标 4 是一个峰。
在下标 5 :由于 5 的右侧不存在不相等邻居,所以下标 5 既不是峰也不是谷。
共有 3 个峰和谷,所以返回 3 。

示例 2:

输入:nums = [6,6,5,5,4,1]
输出:0
解释:
在下标 0 :由于 6 的左侧不存在不相等邻居,所以下标 0 既不是峰也不是谷。
在下标 1 :由于 6 的左侧不存在不相等邻居,所以下标 1 既不是峰也不是谷。
在下标 2 :5 的最近不相等邻居是 6 和 4 。由于 5 < 6 且 5 > 4 ,下标 2 既不是峰也不是谷。
在下标 3 :5 的最近不相等邻居是 6 和 4 。由于 5 < 6 且 5 > 4 ,下标 3 既不是峰也不是谷。
在下标 4 :4 的最近不相等邻居是 5 和 1 。由于 4 < 5 且 4 > 1 ,下标 4 既不是峰也不是谷。
在下标 5 :由于 1 的右侧不存在不相等邻居,所以下标 5 既不是峰也不是谷。
共有 0 个峰和谷,所以返回 0 。

说明:

  • 3 <= nums.length <= 100
  • 1 <= nums[i] <= 100

思路

找出数组中的峰与谷的数量,如果相邻元素相等,认为属于同一个峰或者谷。

代码


/**
 * @date 2025-07-27 23:31
 */
public class CountHillValley2210 {

    public int countHillValley(int[] nums) {
        int n = nums.length;
        int res = 0;
        for (int i = 1; i < n - 1; i++) {
            int r = i + 1;
            while (r < n - 1 && nums[r] == nums[i]){
                r++;
            }
            if (nums[i] > nums[i - 1] && nums[r - 1] > nums[r]){
                res++;
            }
            if (nums[i] < nums[i - 1] && nums[r - 1] < nums[r]){
                res++;
            }
        }
        return res;
    }
}

性能

3487.删除后的最大子数组元素和

目标

给你一个整数数组 nums 。

你可以从数组 nums 中删除任意数量的元素,但不能将其变为 空 数组。执行删除操作后,选出 nums 中满足下述条件的一个子数组:

  • 子数组中的所有元素 互不相同 。
  • 最大化 子数组的元素和。

返回子数组的 最大元素和 。

子数组 是数组的一个连续、非空 的元素序列。

示例 1:

输入:nums = [1,2,3,4,5]
输出:15
解释:
不删除任何元素,选中整个数组得到最大元素和。

示例 2:

输入:nums = [1,1,0,1,1]
输出:1
解释:
删除元素 nums[0] == 1、nums[1] == 1、nums[2] == 0 和 nums[3] == 1 。选中整个数组 [1] 得到最大元素和。

示例 3:

输入:nums = [1,2,-1,-2,1,0,-1]
输出:3
解释:
删除元素 nums[2] == -1 和 nums[3] == -2 ,从 [1, 2, 1, 0, -1] 中选中子数组 [2, 1] 以获得最大元素和。

说明:

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

思路

有一个数组 nums,允许删除其中任意元素得到一个 非空 数组,使得最终数组中 不包含重复元素 并且所有 元素和最大

为了使和最大,我们应该删掉所有的负数,同时对剩余元素去重累加求和。需要注意如果数组中全是负数,需要保留最大元素。

代码


/**
 * @date 2025-07-25 8:55
 */
public class MaxSum3487 {

    public int maxSum(int[] nums) {
        int sum = Arrays.stream(nums).distinct().filter(x -> x > 0).sum();
        if (sum == 0){
            OptionalInt max = Arrays.stream(nums).max();
            return max.isPresent() ? max.getAsInt() : sum;
        }
        return sum;
    }

}

性能

1957.删除字符使字符串变好

目标

一个字符串如果没有 三个连续 相同字符,那么它就是一个 好字符串 。

给你一个字符串 s ,请你从 s 删除 最少 的字符,使它变成一个 好字符串 。

请你返回删除后的字符串。题目数据保证答案总是 唯一的 。

示例 1:

输入:s = "leeetcode"
输出:"leetcode"
解释:
从第一组 'e' 里面删除一个 'e' ,得到 "leetcode" 。
没有连续三个相同字符,所以返回 "leetcode" 。

示例 2:

输入:s = "aaabaaaa"
输出:"aabaa"
解释:
从第一组 'a' 里面删除一个 'a' ,得到 "aabaaaa" 。
从第二组 'a' 里面删除两个 'a' ,得到 "aabaa" 。
没有连续三个相同字符,所以返回 "aabaa" 。

示例 3:

输入:s = "aab"
输出:"aab"
解释:没有连续三个相同字符,所以返回 "aab" 。

说明:

  • 1 <= s.length <= 10^5
  • s 只包含小写英文字母。

思路

定义 好字符串 是不包含连续三个相同字符的字符串,给定一个字符串,删掉最少的字符使之变为好字符串。

记录连续重复字符个数,不同则重置,如果达到三个则跳过。

代码


/**
 * @date 2025-07-21 8:40
 */
public class MakeFancyString1957 {

    public String makeFancyString_v1(String s) {
        int n = s.length();
        char prev = ' ';
        int cnt = 0;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            if (prev == c) {
                if (cnt < 2) {
                    cnt++;
                    sb.append(c);
                }
            } else {
                sb.append(c);
                prev = c;
                cnt = 1;
            }
        }
        return sb.toString();
    }

}

性能

3136.有效单词

目标

有效单词 需要满足以下几个条件:

  • 至少 包含 3 个字符。
  • 由数字 0-9 和英文大小写字母组成。(不必包含所有这类字符。)
  • 至少 包含一个 元音字母 。
  • 至少 包含一个 辅音字母 。

给你一个字符串 word 。如果 word 是一个有效单词,则返回 true ,否则返回 false 。

注意:

  • 'a'、'e'、'i'、'o'、'u' 及其大写形式都属于 元音字母 。
  • 英文中的 辅音字母 是指那些除元音字母之外的字母。

示例 1:

输入:word = "234Adas"
输出:true
解释:
这个单词满足所有条件。

示例 2:

输入:word = "b3"
输出:false
解释:
这个单词的长度少于 3 且没有包含元音字母。

示例 3:

输入:word = "a3$e"
输出:false
解释:
这个单词包含了 '$' 字符且没有包含辅音字母。

说明:

  • 1 <= word.length <= 20
  • word 由英文大写和小写字母、数字、'@'、'#' 和 '$' 组成。

思路

判断字符串是否至少包含 3 个字符,且仅由英文字母与数字组成,且至少包含一个元音字母和一个辅音字母。

正则表达式,前瞻断言。

代码


/**
 * @date 2025-07-15 8:52
 */
public class IsValid3136 {

    public static Pattern p = Pattern.compile("^(?=.*[aeiouAEIOU])(?=.*[b-df-hj-np-tv-zB-DF-HJ-NP-TV-Z])[0-9a-zA-z]{3,}$");

    public boolean isValid(String word) {
        return p.matcher(word).find();
    }

}

性能

1290.二进制链表转整数

目标

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。

请你返回该链表所表示数字的 十进制值 。

示例 1:

输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)

示例 2:

输入:head = [0]
输出:0

示例 3:

输入:head = [1]
输出:1

示例 4:

输入:head = [1,0,0,1,0,0,1,1,1,0,0,0,0,0,0]
输出:18880

示例 5:

输入:head = [0,0]
输出:0

说明:

  • 链表不为空。
  • 链表的结点总数不超过 30。
  • 每个结点的值不是 0 就是 1。

思路

有一个链表的元素值为 01,求该链表表示的十进制数字。

代码


/**
 * @date 2025-07-14 8:48
 */
public class GetDecimalValue1290 {

    public int getDecimalValue(ListNode head) {
        int res = 0;
        while (head != null) {
            res = (res << 1) + head.val;
            head = head.next;
        }
        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;
    }
}

性能

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

性能