leetcode第291场周赛总结
前言
经过将近一年的刷题和总结学习,感觉算法的基础部分算是啃下来了,但是还没有吃透,模拟、滑动窗口、集合的应用,动态规划、dfs…但是还是有很多还没有学习和掌握的,例如:图、并查集、bfs等等。怀揣着激动的心尝试了自己的第一次周赛,结果有些不尽人意,特作此复盘,希望自己和各位一样能不断学习和继续进步叭~
题目与题解
先分享一下自己的题目与题解,有更好的题解方法也可以在评论区分享一起学习!
1.移除指定数字得到最大结果(Easy)
题目:
给你一个表示某个正整数的字符串 number 和一个字符 digit 。
从 number 中 恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digit 在 number 中出现至少一次。
思路
其实第一题是简单题,按道理来说应该没那么复杂,所以我一上来就是将遍历字符串,遇到符合条件的digit时就删除这个字符然后将其转换成Integer进行比较
错误代码1
class Solution {
public String removeDigit(String number, char digit) {
int result=0;
int n=number.length();
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
//如果当前字符与所示字符相同,那么将其移除
String str=number.substring(0,i)+number.substring(i+1,n);
int temp=Integer.valueOf(str);
result=max(result,temp);
}
}
return String.valueOf(result);
}
public int max(int a,int b){
return a>b?a:b;
}
}
运行结果1
仔细看题之后发现整个字符串可以长达100位,我使用Integer会不会是远远不够了hh,所以我必须转变思路,使用字符串进行比较
于是我转变思路:能不能通过字符串的一些规律来解决此题
对于任意一个字符串str,我发现遇到的第一个匹配字符是相当重要的,例如:
示例1:
str=“3213”,digit=‘3’
去掉第一个3会使结果变成213,去掉第2个3会让结果变成321(优)
示例2:
str=“3413”,digit=‘3’
去掉第1个3会使结果变成413(优),去掉第2个3会让结果变成341
示例3:
str=“3313”,digit=‘3’
去掉第1个3或第2个3都是313,去掉最后一个3会使结果位331(优)
示例4:
str=“44443313”,digit=‘3’
如示例3,前面的数对其没有影响
因此得出结论:如果当前子串的数字为digit,那么需要结合下一位进行判断,如果下一位大于digit,那么就直接删除这个数然后返回结果即可(埋坑)
错误代码2
class Solution {
public String removeDigit(String number, char digit) {
int n=number.length();
String result="";
int nums=0;
/****
第一轮找是否只有一个字符
**/
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
nums++;
}
}
if(nums==1){
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
result=number.substring(0,i)+number.substring(i+1,n);
break;
}
}
}else{
//至少有两个符合条件的字符
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
if(i==n-1){
result=number.substring(0,n-1);
break;
}
if(number.charAt(i+1)>number.charAt(i)){
result=number.substring(0,i)+number.substring(i+1,n);
break;
}
}
}
}
return result;
}
}
运行返回的结果是:“”(空子串)
分析:
为什么返回的是空子串呢,因为到最后一个5时还没有符合条件,所以整个字符串跳过去后都进行操作,也就没有结果返回了,所以我还需要记录这是不是操作的最后一个数
正确代码
class Solution {
public String removeDigit(String number, char digit) {
int n=number.length();
String result="";
int nums=0;
/****
第一轮找是否只有一个字符
**/
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
nums++;
}
}
if(nums==1){
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
result=number.substring(0,i)+number.substring(i+1,n);
break;
}
}
}else{
//至少有两个符合条件的字符
for(int i=0;i<n;i++){
if(number.charAt(i)==digit){
nums--; //表示后面还有几个数
if(i==n-1||nums==0){
result=number.substring(0,i)+number.substring(i+1,n);
break;
}
if(number.charAt(i+1)>number.charAt(i)){
result=number.substring(0,i)+number.substring(i+1,n);
break;
}
}
}
}
return result;
}
}
第一题做成这样实属不应该,罚时了20分钟加上思考了30分钟,也就成为了拖后腿的一题.
2.必须拿起的最小连续卡牌数
题目
思路
这题我一开始是想用哈希表来存储每个数字出现的位置的,然后再遍历哈希表来计算每个key中的value差值最小值,后来一想其实不需要那么复杂,cards[i]在[0,106]之间,使用数组来实现哈希表或许会更加简单,思路清晰后也很快编写出对应的代码:
正确代码
class Solution {
public int minimumCardPickup(int[] cards) {
/****
使用数组来存储对应数和对应位置
**/
int n = cards.length;
int[] idx = new int[1000001];
for(int i=0;i<idx.length;i++){
idx[i]=-1;
}
int result=1000001;
for(int i=0;i<n;i++){
if(idx[cards[i]]!=-1){
//说明之前这个数之前出现过,那么找出上一个出现该数的位置
int subIndex=i-idx[cards[i]]+1;
result=Math.min(result,subIndex);
}
idx[cards[i]]=i;
}
return result==1000001?-1:result;
}
}
运行结果
3.含最多k个可整除元素的子数组
题目
思路
其实这题也并不复杂,像是作一个符合条件的全排列,问题就在于我对于Set集合和List集合理解不够深入,导致测试时本题卡了好久,提交本题时已经结束10分钟了,自然分数也就没有拿到,有点可惜吧
上文提到这里可以使用Set实现去重,不断比较是否可以添加进新的元素进List,然后将List放入Set中实现去重,于是第一版的错误代码便应运而生了…
错误代码1
class Solution {
/****
全排列问题,使用Set去重会更佳
***/
public int countDistinct(int[] nums, int k, int p) {
int n = nums.length;
Set<List<Integer>> set=new HashSet<>();
for(int i=0;i<n;i++){
List<Integer> list = new ArrayList<>();
int temp = k;
for(int j=i;j<n;j++){
if(nums[j]%p==0){
if(temp==0){
break;
}
temp--;
}
list.add(nums[j]);
set.add(list);
}
}
return set.size();
}
}
错误结果:
填入示例:
nums={2, 3, 3, 2, 2},k=2,p=2后结果为14,而不是正确结果11,为此我进行调试,调试时发现很多"诡异"之处:
第一次进入内层循环时:set中的list有1个,为{2}
第二次进入内层循环时:set中的list有两个,且它们都是{2,3}
由于第一次调试时心情急躁,也就没有认真仔细一步步调试,而是到最后才发现竟然有许多重复的集合,这让我一时间很无解,后来我才发现我操作的都是同一条链表,即对同一引用进行了重复的操作,原来的链表也会随着add操作而继续改变,想清楚这点时,比赛已经结束了,但是我还是提交了代码,结果真就差了亿点…
正确代码
class Solution {
/****
全排列问题,使用Set去重会更佳
***/
public int countDistinct(int[] nums, int k, int p) {
int n = nums.length;
Set<List<Integer>> set=new HashSet<>();
for(int i=0;i<n;i++){
List<Integer> list = new ArrayList<>();
int temp = k;
for(int j=i;j<n;j++){
if(nums[j]%p==0){
if(temp==0){
break;
}
temp--;
}
list.add(nums[j]);
//每次都使用新的链表来存取数据
List<Integer> temps = new ArrayList<>(list);
set.add(temps);
}
}
return set.size();
}
}
运行结果:
由于第4题题目都来不及看了,因此在此就不进行复盘了,有兴趣的同学可以去看一下.
总结
本次周赛难度还是偏低的,但是我也因为第一题而有点慌了阵脚,思维还需要继续锻炼并强化自己的数据结构方面的知识能力!本次打榜全国排名3867,其实还是很有机会能够冲击前2000名的,主要是失误+知识点不牢固,希望能够再接再厉,一起加油~