2259. 移除指定数字得到的最大结果
给你一个表示某个正整数的字符串 number
和一个字符 digit
。
从 number
中 恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digit
在 number
中出现至少一次。
示例 1:
输入:number = “123”, digit = “3”
输出:“12”
解释:“123” 中只有一个 ‘3’ ,在移除 ‘3’ 之后,结果为 “12” 。
示例 2:
输入:number = “1231”, digit = “1”
输出:“231”
解释:可以移除第一个 ‘1’ 得到 “231” 或者移除第二个 ‘1’ 得到 “123” 。
由于 231 > 123 ,返回 “231” 。
示例 3:
输入:number = “551”, digit = “5”
输出:“51”
解释:可以从 “551” 中移除第一个或者第二个 ‘5’ 。
两种方案的结果都是 “51” 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-digit-from-number-to-maximize-result
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
- 首先第一个想法,我挨个挨个试一次呗,我从头到尾遍历,只要是跟我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:
输入:cards = [3,4,2,3,4,7]
输出:4
解释:拿起卡牌 [3,4,2,3] 将会包含一对值为 3 的匹配卡牌。注意,拿起 [4,2,3,4] 也是最优方案。
示例 2:
输入:cards = [1,0,5,3]
输出:-1
解释:无法找出含一对匹配卡牌的一组连续卡牌。
思路:
没什么好说的,用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:
输入:nums = [2,3,3,2,2], k = 2, p = 2
输出:11
解释:
位于下标 0、3 和 4 的元素都可以被 p = 2 整除。
共计 11 个不同子数组都满足最多含 k = 2 个可以被 2 整除的元素:
[2]、[2,3]、[2,3,3]、[2,3,3,2]、[3]、[3,3]、[3,3,2]、[3,3,2,2]、[3,2]、[3,2,2] 和 [2,2] 。
注意,尽管子数组 [2] 和 [3] 在 nums 中出现不止一次,但统计时只计数一次。
子数组 [2,3,3,2,2] 不满足条件,因为其中有 3 个元素可以被 2 整除。
示例 2:
输入:nums = [1,2,3,4], k = 4, p = 1
输出:10
解释:
nums 中的所有元素都可以被 p = 1 整除。
此外,nums 中的每个子数组都满足最多 4 个元素可以被 1 整除。
因为所有子数组互不相同,因此满足所有限制条件的子数组总数为 10 。
思路:
- 这不就是排列组合吗,但是这个排列组合是有顺序的,有顺序的排列组合
- 这个组合里有重复的数字,所以记得去重==>用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:
输入:s = “abbca”
输出:28
解释:“abbca” 的子字符串有:
- 长度为 1 的子字符串:“a”、“b”、“b”、“c”、“a” 的引力分别为 1、1、1、1、1,总和为 5 。
- 长度为 2 的子字符串:“ab”、“bb”、“bc”、“ca” 的引力分别为 2、1、2、2 ,总和为 7 。
- 长度为 3 的子字符串:“abb”、“bbc”、“bca” 的引力分别为 2、2、3 ,总和为 7 。
- 长度为 4 的子字符串:“abbc”、“bbca” 的引力分别为 3、3 ,总和为 6 。
- 长度为 5 的子字符串:“abbca” 的引力为 3 ,总和为 3 。
引力总和为 5 + 7 + 7 + 6 + 3 = 28 。
示例 2:
输入:s = “code”
输出:20
解释:“code” 的子字符串有:
- 长度为 1 的子字符串:“c”、“o”、“d”、“e” 的引力分别为 1、1、1、1 ,总和为 4 。
- 长度为 2 的子字符串:“co”、“od”、“de” 的引力分别为 2、2、2 ,总和为 6 。
- 长度为 3 的子字符串:“cod”、“ode” 的引力分别为 3、3 ,总和为 6 。
- 长度为 4 的子字符串:“code” 的引力为 4 ,总和为 4 。
引力总和为 4 + 6 + 6 + 4 = 20 。
思路:
- 将所有子串按照其末尾字符的下标分组。
- 考虑两组相邻的子串:以 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;
}
}