目录
2259. 移除指定数字得到的最大结果
给你一个表示某个正整数的字符串 number
和一个字符 digit
。
从 number
中 恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digit
在 number
中出现至少一次。
示例 1:
示例 2:
示例 3:
思路:
- 首先第一个想法,我挨个挨个试一次呗,我从头到尾遍历,只要是跟我digit相等的字符,我就把他去掉,然后把他保存,后面只要遇到我就把这个字符去掉然后跟之前保存的比较,最后谁最大我就返回谁
but!but!你有没有发现,这种效率不是很高,什么你问我为什么不是很高。很简单。
number = "12131415161",digit="1";
如果我们暴力法一次比较。我们需要比较6次!但是我们发现没有?实际上我number无论去掉哪一个字符,最终都是number.length()-1位数。既然是数学上比较大小的问题,那说明什么?肯定是高位越大的同样长度的数字更大啊。你说我去掉第一个1。我最高位就是2了,如果我去掉后面的其他的1。我的高位肯定是是1啊。这部显而易见。肯定是去掉第一个1就行了。也就是我只需要操作一次就行了啊。如此一来我们的思路↓
- 从头往后遍历
- 只要遇到number.charAt(i) == digit我就看number.charAt(i+1)是否比number.charAt(i)大,如果大,越早去掉越好。否则的话,就去掉最后一个
- 有个小细节,我们最后一个字符可能不太好比较,所以我们可以给number加一个其他字符。最后返回的时候删除就行了
代码实现:
class Solution {
public String removeDigit(String number, char digit) {
number = number + "-";//为了最后一个字符也能比较
int len = number.length();
char[] ch = number.toCharArray();
String temp = "";
for (int i = 1; i < len; i++) {
if (digit == ch[i - 1] && i != len) {
temp = number.substring(0, i - 1) + number.substring(i, len);
if (ch[i] > ch[i - 1]) {
break;
}
}
}
return temp.substring(0,len-2);//记得把最后一个字符去掉
}
}
2260. 必须拿起的最小连续卡牌数
给你一个整数数组 cards ,其中 cards[i] 表示第 i 张卡牌的 值 。如果两张卡牌的值相同,则认为这一对卡牌 匹配 。
返回你必须拿起的最小连续卡牌数,以使在拿起的卡牌中有一对匹配的卡牌。如果无法得到一对匹配的卡牌,返回 -1 。
示例 1:
示例 2:
思路:
没什么好说的,用HashMap的key不可重复的特性,保存和cards[i]相同值的前一个值的下标。那么我就知道当前这副牌有i - map.get(cards[i]) + 1
张。从前往后不断迭代更新出最短的就行
代码实现:
class Solution {
public int minimumCardPickup(int[] cards) {
int len = cards.length;
int res = Integer.MAX_VALUE;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < len; i++) {
if (map.containsKey(cards[i])) {
res = Math.min(res, 1 + i - map.get(cards[i]));
}
map.put(cards[i], i);
}
if (res == Integer.MAX_VALUE) {
return -1;
}
return res;
}
}
2261. 含最多 K 个可整除元素的子数组
给你一个整数数组 nums 和两个整数 k 和 p ,找出并返回满足要求的不同的子数组数,要求子数组中最多 k 个可被 p 整除的元素。
如果满足下述条件之一,则认为数组 nums1 和 nums2 是 不同 数组:
两数组长度 不同 ,或者
存在 至少 一个下标 i 满足 nums1[i] != nums2[i] 。
子数组 定义为:数组中的连续元素组成的一个 非空 序列。
示例 1:
示例 2:
思路:
- 这不就是排列组合吗,但是这个排列组合是有顺序的,有顺序的排列组合
- 这个组合里有重复的数字,所以记得去重==>用Set数据结构
ps:为啥Set可以去重?那我就跟你好好battle一下了。Set的主要实现类是HashSet,他继承了Set接口。拥有Set接口众多的方法。HashSet底层是用HashMap的key作为他的value的。HashMap底层是Hash表,根据他的key的hash值作为下标,下标只有一个所以key不可重复。因此HashSet的value不能重复。你可能会问,我用HashMap的key作为value值,那HashMap的value用来干嘛呢?不好意思,这个value是个特殊值,一般没用。只有当HashSet加入一个重复值时,底层发现已经有该值了,会将value返回,表示加入的值重复了。
扯那么多其实这道题没啥捷径,从前往后遍历吧。如果有好方法,希望有人可以在评论告诉我
代码实现:
class Solution {
public int countDistinct(int[] nums, int k, int p) {
HashSet<String> ans = new HashSet<>();
int len = nums.length;
for (int i = 0; i < len; i++) {
int cnt = k;
StringBuilder sb = new StringBuilder();
for (int j = i; j < len; j++) {
sb.append(nums[j]).append("+");
if (nums[j] % p == 0) {
cnt--;
}
if (cnt < 0) {
break;
}
ans.add(sb.toString());
}
}
return ans.size();
}
}
6050. 字符串的总引力
字符串的 引力 定义为:字符串中 不同 字符的数量。
例如,“abbca” 的引力为 3 ,因为其中有 3 个不同字符 ‘a’、‘b’ 和 ‘c’ 。
给你一个字符串 s ,返回 其所有子字符串的总引力 。
子字符串 定义为:字符串中的一个连续字符序列。
示例 1:
示例 2:
思路:
- 将所有子串按照其末尾字符的下标分组。
- 考虑两组相邻的子串:以 s[i-1]s[i−1] 结尾的子串、以 s[i]s[i] 结尾的子串。
- 以 s[i]s[i] 结尾的子串,可以看成是以 s[i-1]s[i−1] 结尾的子串,在末尾添加上 s[i]s[i] 组成。
上面这一串提示是思考子串统计类问题的通用技巧之一。
- 从左往右遍历 ss,考虑将 s[i]s[i] 添加到以 s[i-1]s[i−1] 结尾的子串的末尾。添加后,这些子串的引力值会增加多少?
- 分类讨论:
- 如果 s[i]s[i] 之前没有遇到过,那么这些子串的引力值都会增加 11,这些子串的引力值之和会增加 ii,再加上 11,即 s[i]s[i] 单独组成的子串的引力值;
- 如果 s[i]s[i] 之前遇到过,设其上次出现的下标为 jj,那么向子串 s[0…i-1],\ s[1…i-1],\ s[2…i-1],\cdots,s[j…i-1]s[0…i−1], s[1…i−1], s[2…i−1],⋯,s[j…i−1] 的末尾添加 s[i]s[i] 后,这些子串的引力值是不会变化的,因为 s[i]s[i] 已经在 s[j]s[j] 处出现过了;而子串 s[j+1…i-1],\ s[j+2…i-1],\cdots,s[i-1…i-1]s[j+1…i−1], s[j+2…i−1],⋯,s[i−1…i−1] 由于不包含字符 s[i]s[i],这些子串的引力值都会增加 11,因此有 i-j-1i−j−1 个子串的引力值会增加 11,这些子串的引力值之和会增加 i-j-1i−j−1,再加上 11,即 s[i]s[i] 单独组成的子串的引力值。
代码实现:
class Solution {
public long appealSum(String s) {
int len = s.length();
int[] pos = new int[26];
Arrays.fill(pos, -1);
long sum = 0;
for (int i = 0; i < s.length(); i++) {
int index = s.charAt(i) - 'a';
sum += (i - pos[index]) * (len - i);
pos[index] = i;
}
return sum;
}
}