携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
刷题的日常
一天一题,保持脑子清爽
# 裁剪数字后查询第 K 小的数字
来自leetcode的2343题,题意如下:
给你一个下标从 0开始的字符串数组nums,其中每个字符串 长度相等且只包含数字。再给你一个下标从0开始的二维整数数组queries,其中queries[i] = [ki, trimi]。对于每个queries[i],你需要:
- 将nums中每个数字 裁剪到剩下 最右边trimi个数位。
- 在裁剪过后的数字中,找到 nums中第ki小数字对应的 下标。如果两个裁剪后数字一样大,那么下标 更小的数字视为更小的数字。
- 将 nums中每个数字恢复到原本字符串。
- 请你返回一个长度与 queries相等的数组answer,其中answer[i]是第i次查询的结果。
示例如下:
输入:nums = ["102","473","251","814"], queries = [[1,1],[2,3],[4,2],[1,2]]
输出:[2,2,1,0]
解释:
1. 裁剪到只剩 1 个数位后,nums = ["2","3","1","4"] 。最小的数字是 1 ,下标为 2 。
2. 裁剪到剩 3 个数位后,nums 没有变化。第 2 小的数字是 251 ,下标为 2 。
3. 裁剪到剩 2 个数位后,nums = ["02","73","51","14"] 。第 4 小的数字是 73 ,下标为 1 。
4. 裁剪到剩 2 个数位后,最小数字是 2 ,下标为 0 。
注意,裁剪后数字 "02" 值为 2 。
理解题意
由题意我们可以将条件整理如下:
- 题目会给出两个数组,第一个数组是数字,由字符串进行表示
- 第二个数组里面套着数组,第二层的数组固定有两个值,第二个值代表裁剪的位数,第一个值代表裁剪过后排名
- 将所有裁剪方法的结果返回
做题思路
这边采取暴力解的方法:
- 循环便利queries数组,将所有可能枚举出来
- 然后将裁剪过后的数组进行排序
- 获取第 i 大的元素
- 将所有获取到的排名返回
根据题目给出的用例,可以发现可能会重复裁剪,所以可以用Map存储已经计算过的数据,无需重复计算,直接从以前的数据获取排名即可。
代码实现
public class Solution {
static final Comparator<Pair> c = Comparator.comparing(o -> o.str);
public int[] smallestTrimmedNumbers(String[] nums, int[][] queries) {
Map<Integer, List<Pair>> trimMap = new HashMap<>();
int[] result = new int[queries.length];
int idx = 0;
for (int[] query : queries) {
List<Pair> pairs = trimMap.computeIfAbsent(query[1], o -> calc(query[1], nums));
result[idx++] = pairs.get(query[0] - 1).idx;
}
return result;
}
private List<Pair> calc(int trimNum, String[] nums) {
List<Pair> result = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
String num = nums[i];
num = num.substring(num.length() - trimNum);
result.add(new Pair(num, i));
}
result.sort(c);
return result;
}
static class Pair {
public Pair(String str, Integer idx) {
this.str = str;
this.idx = idx;
}
String str;
Integer idx;
}
}