Leetcode - 周赛416

目录

一,3295. 举报垃圾信息

二,3296. 移山所需的最少秒数

三,3297. 统计重新排列后包含另一个字符串的子字符串数目 I

四,3298. 统计重新排列后包含另一个字符串的子字符串数目 II


一,3295. 举报垃圾信息

本题就是求message中是否至少存在2两个单词在banndedWord中,我们可以直接使用hash记录banndedWord中的字符串,再枚举message,使用cnt记录有几个单词在哈希表中,最后返回 cnt > 1.

代码如下:

class Solution {
    public boolean reportSpam(String[] message, String[] bannedWords) {
        Set<String> set = new HashSet<>();
        for(String x : bannedWords){
            set.add(x);
        }
        int cnt = 0;
        for(String x : message){
            if(set.contains(x)) 
                cnt++;
        }
        return cnt > 1;
    }
}

二,3296. 移山所需的最少秒数

本题有两种做法:

1.最小堆

维护每个工人降低山的高度 x 所花费的时间,直到山的高度为0,返回堆顶的元素。

class Solution {
    public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {
        PriorityQueue<long[]> que = new PriorityQueue<>((x,y)->Long.compare(x[0], y[0]));
        for(long x : workerTimes){
            que.offer(new long[]{x, 1L, x});//时间,降低h,倍率
        }
        long ans = 0;
        while(mountainHeight-- > 0){
            long[] t = que.poll();
            long x = t[0], h = t[1], base = t[2];
            ans = x;
            que.offer(new long[]{x+(h+1)*base, h+1, base});
        }
        return ans;
    }
}

2.二分答案

给的时间越长,工人就越可能完成移山,具有单调性,可以二分,接下来就是如何判断二分的时间 t 是否能完成移山,假设 x = workertimes[i],能减低的山的高度为 h,我们可以得到这个方程 (h+1)*h/2*x = t,化简得到 h^2 + h - 2*t/x = 0,通过一元二次方程求根公式x = -b+sqrt(b^2-4ac)/2a 或者-b-sqrt(b^2-4ac)/2a(由于答案为正整数,舍去), 求解 h = -1 + sqrt(1+8*t/x))/2,然后将所有工人在 t 时间内所能降低的山的高度加起来,如果 < mountainHeight,l = mid + 1,否则 r = mid - 1.

class Solution {
    public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {
        long ans = 0;
        long l = 1, r = (long)(mountainHeight+1)*mountainHeight / 2 * workerTimes[0]; 
        while(l <= r){
            long mid = (l + r) / 2;
            if(check(mid, mountainHeight, workerTimes))
                r = mid - 1;
            else
                l = mid + 1;
        }
        return r + 1;
    }
    boolean check(long t, int h, int[] w){
        int ans = 0;
        for(int x : w){
            ans += Math.max(0, (int)(-1 + (int)Math.sqrt(1+8*t/x))/2);
        }
        return ans >= h;
    }
}

三,3297. 统计重新排列后包含另一个字符串的子字符串数目 I

本题题意就是找word1中有多少个子字符串,且都要包含word2中的每个字符。直接使用滑动窗口来做。先使用一个数组cnt记录word2中每个字符出现的次数。枚举word1中子字符串的右端点,如果[L,R]的字符串中包含word2中的每个字符,我们就可以移动左端点,直到不满足条件为止,也就是说以L为左端点时,右端点[R,n)都满足条件,这时将 ans += n - R,代码如下:

class Solution {
    public long validSubstringCount(String word1, String word2) {
        char[] w1 = word1.toCharArray();
        char[] w2 = word2.toCharArray();
        int[] cnt = new int[26];
        for(char c : w2){
            cnt[c-'a']++;
        }
        long ans = 0;
        for(int l=0, r=0; r<w1.length; r++){
            boolean flg = false;
            char c = w1[r];
            cnt[c-'a']--;
            for(int i=0; i<26; i++){
                if(cnt[i] > 0) 
                    flg = true; 
            }
            if(flg) continue;
            while(cnt[w1[l]-'a'] <= 0){
                ans += w1.length - r;
                if(++cnt[w1[l++]-'a'] > 0) break;
            }
        }
        return ans;
    }
}

四,3298. 统计重新排列后包含另一个字符串的子字符串数目 II

本题与T3相同,不过数据范围更大,这里我们再讲一个O(n)做法,T3的做法是O(26n),也就是判断子字符串是否包含所有word2需要枚举cnt数组,其实我们可以额外添加一个变量less,记录word2中几个不同的字符。当word1子字符串中包含了n个x字符(word2中存在n个x字符)时,即cnt[x-'a']=0时,less--,那么 less = 0 说明该字符串满足条件。

代码如下:

class Solution {
    public long validSubstringCount(String word1, String word2) {
        char[] w1 = word1.toCharArray();
        char[] w2 = word2.toCharArray();
        int[] cnt = new int[26];
        for(char c : w2){
            cnt[c-'a']++;
        }
        int less = 0;
        for(int x : cnt){
            if(x > 0){
                less++;
            }
        }
        long ans = 0;
        for(int l=0, r=0; r<w1.length; r++){
            char c = w1[r];
            if(--cnt[c-'a'] == 0) less--;//只有原来cnt[x]>0(即删去的全是word2中存在的字符时),less--
            while(less == 0){  
                ans += w1.length - r; 
                if(++cnt[w1[l++]-'a'] > 0){
                    less++;
                }   
            }
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶祇秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值