【leetcode周赛总结】LeetCode第291场周赛总结(5.1)

目录

第一题 移除指定数字得到的最大结果

思路

代码

第二题  必须拿起的最小连续卡牌数

思路

代码

第三题 含最多 K 个可整除元素的子数组

思路

代码

第四题 字符串的总引力

思路

代码1

代码2


第一题 移除指定数字得到的最大结果

自己做题的问题简单记录: 用时26分AC

简单题,一开始我的思路错了不知道为什么要把字符串转成int比较

由于移除一位数字之后字符串长度相同,所以可以直接用string比较

由于CompareTo()这个函数不熟悉导致一次WA

compareTo() 的返回值是int, 它是先比较对应字符的大小(ASCII码顺序)
1、如果字符串相等返回值0
2、如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值(ascii码值)
(负值前字符串的值小于后字符串,正值前字符串大于后字符串)
3、如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,
直至比较的字符或被比较的字符有一方全比较完,这时就比较字符的长度.

思路

暴力枚举,枚举可能的所有情况,遇见较大的情况更新结果字符串。

时间复杂度O(n)

代码

优化修改后的代码如下:

class Solution {
    public String removeDigit(String number, char digit) {
        int n = number.length();
        String res = "";
        for(int i=0;i<n;i++){
            char c = number.charAt(i);
            String t ="";
            if(c == digit){
               t = number.substring(0,i)+number.substring(i+1);
            }
            if(t.compareTo(res)>0){   //t>res
                res = t;
            }
        }
        return res;
    }
}

第二题  必须拿起的最小连续卡牌数

自己做题的问题简单记录: 用时10分AC

思路

本题题目可以转换为找两个最近的相同数字,答案即为这两个数字的距离。

所以可以用一个hashMap维护数字->idx,遍历一遍即可。

时间复杂度O(n),空间O(n)

代码

class Solution {
    public int minimumCardPickup(int[] cards) {
        int res = Integer.MAX_VALUE;
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<cards.length;i++){
            if(map.containsKey(cards[i])){
                int idx = map.get(cards[i]);
                res = Math.min(res,i-idx+1);
            }
            map.put(cards[i],i);
        }
        return res==Integer.MAX_VALUE?-1:res;
    }
}

第三题 含最多 K 个可整除元素的子数组

自己做题的问题简单记录: 用时32分 WA一次后AC

一开始一直在想子数组有没有什么不枚举的方法,好像思路跑偏了。

然后考虑如何去重,想到了把子数组拼成字符串用set去重,中间WA一次因为拼接需要加一个分符不然会出现问题,如{1,9}和{19}会生成相同的字符串最终导致错误。

思路

暴力枚举所有的子数组(考虑到题目的数据范围可以暴力),然后判断是否符合条件,拼接放入set去重,最后返回set的大小。

时间复杂度O(n^3)   //toString()时间复杂度可能是O(n) 一个不确定的地方(

代码

class Solution {
    public int countDistinct(int[] nums, int k, int p) {
        Set<String> st = new HashSet<>();
        int n = nums.length;
        for(int i=0;i<n;i++){
            int count = 0;
            StringBuilder sb = new StringBuilder();
            for(int j=i;j<n;j++){
                if(nums[j]%p==0){
                    count++;
                }
                if(count>k){
                    break;
                }
                sb.append(nums[j]).append('&');
                st.add(sb.toString());
            }
        }
        return st.size();
    }
}

第四题 字符串的总引力

自己做题的问题简单记录: 

看下数据范围显然这题暴力做会超时,想一下dp没有想出来,感觉这思路真的不是太能想到,学习一下学习一下。

思路

参考理解思路

参考题解:Easy and Concise with Explanationhttps://leetcode.com/problems/total-appeal-of-a-string/discuss/1996390/JavaC%2B%2BPython-Easy-and-Concise-with-Explanation

对于一些以s[i]结尾的字符串,计算这些字符串的总引力值 =

SUM(分别计算26个字母对于这些字符串引力值的贡献)

如何计算每个字母c对以s[i]结尾的字符串的贡献,就是记录每个字母c出现的idx

每个字母c对以s[i]结尾的字符串的贡献 = 以s[i]结尾的字符串且包含c的字符串个数 =字母c出现的idx + 1

例如 字符串abca

0 a   

1 b   

2 c  

当i=2时,考虑字母b对以s[2]结尾的所有字符串的贡献,即考虑以s[i]结尾的字符串且包含b的字符串个数  枚举出符合条件的字符串为:abc、bc  观察可知符合条件的字符串数量为idx(b)+1=1+1=2

3  a

代码1

class Solution {
    public long appealSum(String s) {
        int[] index = new int[26];  //26个字母出现的idx
        long sum = 0;
        for(int i=0;i<s.length();i++){  //枚举以s[i]结尾的字符串集合
            index[s.charAt(i)-'a'] = i+1;
            for(int j=0;j<26;j++){
                sum += index[j];//枚举26个字母
            }
        }
        return sum;
    }
}

代码2

所有子串按照其末尾字符的下标分类。

考虑两类相邻的子串:以 s[i-1]结尾的子串、以 s[i]结尾的子串,以 s[i]结尾的子串,可以看成是以s[i−1] 结尾的子串,在末尾添加上 s[i] 组成。添加后,这些子串的引力值会增加多少?

分类讨论:

1、如果 s[i]之前没有遇到过,那么每个子串的引力值都会增加 1,引力值之和会增加 i+1;
2、如果 s[i]之前遇到过,设其上次出现的下标为 j,那么向子串 s[0..i-1]、s[1..i-1]、s[2..i-1],⋯,s[j..i−1] 的末尾添加 s[i] 后,引力值是不会变化的,因为 s[i]已经在s[j] 处出现过了;而子串 s[j+1..i−1], s[j+2..i−1],⋯,s[i−1..i−1] 由于不包含字符 s[i],这些子串的引力值都会增加 1,因此有 i-j-1 个子串的引力值会增加 1,引力值之和会增加 i−j。 【(i+1)-(j+1)】

作者:endlesscheng
链接:https://leetcode-cn.com/problems/total-appeal-of-a-string/solution/by-endlesscheng-g405/
来源:力扣(LeetCode)

class Solution {
    public long appealSum(String s) {
        int[] index = new int[26];  //26个字母出现的idx
        long sum = 0;
        long total = 0;
        for(int i=0;i<s.length();i++){  //枚举以s[i]结尾的字符串集合
            total += i+1-index[s.charAt(i)-'a'];
            index[s.charAt(i)-'a'] = i+1;
            sum += total;
        }
        return sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值