[LeetCode]-[周赛]-282

前言

赛题链接

统计包含给定前缀的字符串 (字典树)

直接用字典树建模

class Solution {
    public int prefixCount(String[] words, String pref) {
        Trie t = new Trie();
        int l = words.length;
        //将words放入字典树中
        for(int i = 0;i < l;i++){
            String s = words[i];
            int sl = s.length();
            Trie tmp = t;
            for(int j = 0;j <  sl;j++){
                char c = s.charAt(j);
                if(tmp.sons[c - 'a'] == null){
                    tmp.sons[c - 'a'] = new Trie();
                }
                tmp = tmp.sons[c - 'a'];
                tmp.count += 1;
            }
        }
        //直接在字典树中找指定前缀有多少个串
        Trie tmp = t;
        int pl = pref.length();
        for(int i = 0;i < pl;i++){
            char c = pref.charAt(i);
            if(tmp.sons[c - 'a'] == null){
                return 0;   
            }    
            tmp = tmp.sons[c - 'a'];
        }
        return tmp.count;
    }
    static class Trie{
        int count;
        Trie[] sons;
        public Trie(){
            sons = new Trie[26];
            count = 0;
        }
    }
}

使两字符串互为字母异位词的最少步骤数

做这道题的时候用的做法是直接对两个字符串排序,然后同时遍历两个排序后的字符串,记录不一样的字符的个数,就是所求答案,想法应该没错,可惜超时了。最后没有做出来。下面答案的思路来自评论区

public int minSteps(String s, String t) {
    int count[] = new int[26];
    int sL = s.length();
    int tL =  t.length();
    //用数组记录每个字符串各自含各种字母的个数以及差值,相差的部分就是要添加的内容
    for(int i = 0;i < sL;i++){
        count[s.charAt(i) - 'a'] += 1;
    }
    for(int i = 0;i < tL;i++){
        count[t.charAt(i) - 'a'] -= 1;
    }
    int res = 0;
    for(int i = 0;i < 26;i++){
        res += Math.abs(count[i]);
    }
    return res;
}

完成旅途的最少时间 (贪心 + 二分)

思路来自评论区
二分查找的做法,首先,让完成一趟旅途所需时间最少的车独自完成所有的行程,这种情况下算出来的所需的时间就是完成旅途的最长时间,那么就可以以 0 跟这个最长时间为左右边界进行二分查找最优解

public long minimumTime(int[] time, int totalTrips) {
	//使用Arrays.sort()方法进行排序。不过这个排序操作不是必需的,因为我们只需要找到最小值
	//但下面的算法时间复杂度为O(nlogn),所以排序的话也不影响整个代码最终的渐进复杂度
    Arrays.sort(time);
    //二分模板
    long left = -1;
    //提前转化为long类型,否则会溢出
    long right = ((long)time[0] * totalTrips) + 1;
    while(left + 1 < right){
        long mid = (left + right) >> 1;
        long trips = 0L;
        //二分出mid后,判断mid时间内能否完成旅程
        for(int i : time){
        	//当遍历到某一辆车完成一趟旅程所需时间大于mid,
        	//说明它不可能在mid时间内对能完成的旅途数做出贡献,
        	//那么后面比他大的就更不能了
            if(mid < i) break;
            //计算mid时间内能完成的旅途数
            trips += mid / i;
        }
        //如果mid时间内能完成的旅途数大于等于totalTrips,说明这个时间mid符合条件
        //但它又不一定是最优解,可能比它还小的时间中也能完成totalTrips
        //所以往左边查找
        if(trips >= totalTrips){
            right = mid;
        }else{
        	//如果trips小于totalTrips,说明min时间内不可能完成totalTrips,
        	//需要更多时间,往右边查找
            left = mid;
        }
    }
    //只有到最后不能继续拆分区间了得到的才是最优解
    return right;
}

完成比赛的最少时间 (先提取题意信息,再动态规划)

看了评论区的思路,然后自己总结:

  1. 每个轮胎不能连续使用很多次,因为连续使用的话,每圈所需耗费时间是呈指数增长,如果每圈耗费时间大到比停下来换一个新的同类轮胎 (changeTime + tire[i][0]) 还久的话就应该停止继续使用了。根据数据规模预测所有轮胎中能连续使用的最大圈数为 17 圈
  2. 计算使用每个轮胎连续跑 i 圈所能耗费的最短时间 minTime[i],这个数组的含义可以进一步抽象成:当要连续跑 i 圈时,在这些轮胎中,选取某一个轮胎,所能耗费的最少时间即为 minTime[i]。在计算 minTime 数组的过程中可以记录以下这些轮胎中最多能连续使用 maxRound 圈 (17 只是上界)
  3. 状态转移:dp[i] 表示跑到第 i 圈时耗费的最少时间,那么在这 i 圈中,枚举 j (1 <= j <= min(i,maxRound)),表示这 i 圈中的后面 j 圈经过一次换胎后连续使用同一个轮胎,那么就可以得到转移方程:
    dp[i] = Math.min(dp[i],dp[i - j] + minTime[j] + changeTime);
public int minimumFinishTime(int[][] tires, int changeTime, int numLaps) {
    int[] minTime = new int[18];
    Arrays.fill(minTime,Integer.MAX_VALUE);
    int maxRound = -1,f,r,time;
    for(int[] tire : tires){
        f = tire[0];
        r = tire[1];
        time = f; //time 维护每个轮胎每一圈所需耗时,当time > threshold即达到该轮胎连续使用的最大圈数
        int threshold = changeTime + f;
        for(int i = 1,sum = f;time <= threshold;i++){
            minTime[i] = Math.min(sum,minTime[i]);
            time *= r;
            sum += time; //sum 维护每个轮胎连续使用 i 圈的总耗时
            maxRound = Math.max(maxRound,i); //更新轮胎中能连续使用的最大圈数
        }
    }
    int[] dp = new int[numLaps + 1];
    //注意到状态转移方程中,当 j 等于 i ,dp[i] = Math.min(dp[i],dp[0] + minTime[i] + changeTime)
    //这表示这i圈都使用同一个轮胎 (当然此时 i小于轮胎中所能连续使用的最大圈数maxRound),那么换胎次数就为0,所以dp[0]应等于 -changeTime
    dp[0] = -changeTime; 
    int jThreshold; //枚举j的最大值应当是 i 跟 maxRound中的较小值
    for(int i = 1;i <= numLaps;i++){
        dp[i] = Integer.MAX_VALUE;    //不能设为 minTime[i],minTime数组中下标最大只能到17,而numLaps可以很大
        jThreshold = Math.min(i,maxRound);
        for(int j = 1;j <= jThreshold;j++){
            dp[i] = Math.min(dp[i],dp[i - j] + minTime[j] + changeTime);
        }
    }
    return dp[numLaps];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值