Leetcode--2021.8.8周赛

我又回来了,上周周赛也做了,但是因为比较忙,所以没有更新博客。这周周赛虽然简单,但仍然只做出了两题,第三题一直卡在倒数第二个测试用例,因为竞赛是不给看测试用例的具体内容的,所以一致没找到自己的错误在哪里。。

第一题–5838. 检查字符串是否为数组前缀

在这里插入图片描述
在这里插入图片描述

思路

这一题还是非常简单的,使用words中的元素顺序拼接,当拼接字符串的长度等于s的长度时,比较两个字符串是否相等,相等则返回true,否则返回false;因为可能拼接失败——拼接字符串的长度直接大于s的长度,此时直接返回false即可。

代码

class Solution {
    public boolean isPrefixString(String s, String[] words) {
        int len = words.length;
        
        String cur = "";
        for (int i= 0;i<len;i++)
        {
            cur += words[i];
            if (cur.length() == s.length())
            {
                return cur.equals(s);
            }
            if(cur.length() > s.length())
            	return false;
        }
        
        return false;
    }
}

第二题–5839. 移除石子使总数最小

在这里插入图片描述
在这里插入图片描述

思路

因为数据的范围为10的5次方,所以最多可以使用O(n* logn)时间复杂度的算法。
因为需要求的是石子的总数最小,所以我们每次找到总数最大的石子堆,对其进行减少即可达到要求。
这里使用优先队列来保证每次取的都是当前数量最多的石子堆;

代码

class Solution {
    public int minStoneSum(int[] piles, int k) {
        int len = piles.length;

        int ans = 0;
		//使用优先队列,让数量最大的石子堆始终在堆顶
        PriorityQueue<Integer>  p = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer i1, Integer t1) {
                return t1-i1;
            }
        });

        for (int i : piles)
        {
            p.add(i);
        }
		
		//重复k次,每次都把堆顶的石子堆取出来,按照要求进行减少,然后再放回优先队列内,因为优先队列的性质,会对其中的元素自动进行排序,所以放入后,优先队列的堆顶还是数量最大的石子堆
        for (int i=0;i<k;i++)
        {
            int cur = p.poll();
            cur = cur - (int) Math.floor(cur/2);
            p.add(cur);
        }
		
		//优先队列内的元素一次出队,计算石子总数
        while (!p.isEmpty())
            ans += p.poll();


        return ans;
    }
}

第三题–5840. 使字符串平衡的最小交换次数

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

思路

因为数据范围的要求,所以时间复杂度只能等于或低于O(n)才不会超时。
原本我的思路是:

  1. 使用队列消除当前字符串中所有满足条件的“[”和"]";
  2. 然后把队列内剩余的元素存为新的字符串,交换第一个和最后一个元素,交换次数加一,再次使用队列消除满足条件的“[”和"]";
  3. 重复第二步操作,直至当前字符串的长度为0。

但是在57/58测试用例超时了。。。

比赛结束后,看了其他大佬的代码后发现,根本不需要模拟替换过程。。。。,而我代码超时的原因是因为:

在使用队列消除满足条件的“[”和"]“后,此时队列的内容一定是形如”]]]]…[[[[“的,所以,每次将第一个和最后一个字符进行交换,一次可以消除四个字符。
我的方法因为重复循环的原因,在数据非常大,且原本就是”]]]]…[[[["格式时,就会超时。

因此得到如下的代码

代码

class Solution {
    public int minSwaps(String s) {
    	//使用队列消除满足条件的“[”和"]"
        Deque<Character> d = new LinkedList<>();
        for (int i=0;i<s.length();i++)
        {
            if (s.charAt(i)==']' && !d.isEmpty() && d.peekLast()=='[')
                d.pollLast();
            else
                d.addLast(s.charAt(i));
        }
		//获取当前队列的长度
        int size = d.size();
		//因为一次交换会消除四个字符,所以size/4;当size不是4的整数倍时,需要额外的一次交换,所以加一
        return size%4==0?size/4:size/4+1;
    }
}

第四题–5841. 找出到每个位置为止最长的有效障碍赛跑路线

在这里插入图片描述
在这里插入图片描述

思路

emm这个题在竞赛时因为第三题卡住了,所以根本没看。。
比赛结束后回来看一下

emmm,其实这个题挺简单的,早知道做不成来第三题先做这个了。
简单来说,问题可以转换为

对于数组obstacles中的第i个元素,在前i-1个元素中有多少个不大于obstacles[i]的元素个数,再加一,即为最终答案ans[i]对应的值。

因为数据范围为 1 0 5 10^5 105,所以时间复杂度最高为 O ( n l o g n ) O(nlogn) O(nlogn),正好可以使用二分查找来依次寻找每一个元素对应的答案。
得到如下代码

代码

在这里插入图片描述

class Solution {
    public int[] longestObstacleCourseAtEachPosition(int[] obstacles) {
        int len = obstacles.length;

		//设置结果数组
        int ans[] = new int[len];

		//使用List存储当前元素之前的出现过的元素,按照从小到大的顺序排列,方便后续的二分查找
        List<Integer> list = new ArrayList<>();
        for (int i=0;i<len;i++)
        {
            int cur = obstacles[i];
			
			//因为list始终维持其升序的状态,所以可以使用二分查找寻找第一个大于cur的索引位置
            int l=0, r=list.size();
            while (l<r)
            {
                int mid = l + (r-l)/2;
                if (list.get(mid)<=cur)
                    l = mid +1;
                else
                    r=mid;
            }
            //如果cur是当前所有一出现元素的最大值,则直接放在链表的最后,否则的话插在对应的位置
            if (l==list.size())
                list.add(cur);
            else
                list.set(l,cur);
			//因为二分查找寻找第一个大于cur的索引位置,因为索引位置是从0开始的,所以后面记录ans时需要额外加1
            ans[i] += (l+1);
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值