Leetcode 第400场周赛 问题和解法

问题

候诊室中的最少椅子数

给你一个字符串s,模拟每秒钟的事件i:

如果s[i]‘E’,表示有一位顾客进入候诊室并占用一把椅子。
如果s[i]
‘L’,表示有一位顾客离开候诊室,从而释放一把椅子。
返回保证每位进入候诊室的顾客都能有椅子坐的最少椅子数,假设候诊室最初是空的。

示例1:

输入:s=“EEEEEEE”

输出:7

解释:

每秒后都有一个顾客进入候诊室,没有人离开。因此,至少需要7把椅子。

解题思路

依次判断,然后使用一个中间变量记录当前所使用的椅子数。

class Solution {
    public int minimumChairs(String s) {
        int len=s.length();
        int result=0;
        int mid=0;
        for(int i=0;i<len;i++){
            if (s.charAt(i)=='E'){
                mid++;
                result=Math.max(result,mid);
            }else{
                mid--;
            }
        }
        return result;
    }
}

无需开会的工作日

给你一个正整数days,表示员工可工作的总天数(从第1天开始)。另给你一个二维数组meetings,长度为n,其中meetings[i]=[start_i,end_i]表示第i次会议的开始和结束天数(包含首尾)。

返回员工可工作且没有安排会议的天数。

注意:会议时间可能会有重叠。

示例1:

输入:days=10,meetings=[[5,7],[1,3],[9,10]]

输出:2

解释:

第4天和第8天没有安排会议。

解题思路

排序后依次判断即可。

class Solution {
    public int countDays(int days, int[][] meetings) {
        Arrays.sort(meetings, (p, q) -> p[0] - q[0]); // 按照左端点从小到大排序
        int start = 1, end = 0; // 当前合并区间的左右端点
        for (int[] p : meetings) {
            if (p[0] > end) { // 不相交
                days -= end - start + 1; // 当前合并区间的长度
                start = p[0]; // 下一个合并区间的左端点
            }
            end = Math.max(end, p[1]);
        }
        days -= end - start + 1; // 最后一个合并区间的长度
        return days;
    }
}

删除星号以后字典序最小的字符串

给你一个字符串s。它可能包含任意数量的’‘字符。你的任务是删除所有的’'字符。

当字符串还存在至少一个’*'字符时,你可以执行以下操作:

删除最左边的’‘字符,同时删除该星号字符左边一个字典序最小的字符。如果有多个字典序最小的字符,你可以删除它们中的任意一个。
请你返回删除所有’
'字符以后,剩余字符连接而成的
字典序最小
的字符串。

示例1:

输入:s=“aaba*”

输出:“aab”

解释:

删除’*'号和它左边的其中一个’a’字符。如果我们选择删除s[3],s字典序最小。

解题思路

因为只能删除星号前字典序最小的字符 c,而且还要让结果的字典序最小,所以只能删除星号前的所有 c中,位于最右边的字符。

class Solution {
    public String clearStars(String s) {
        int len = s.length();//原字符串长度
        boolean isDel[] = new boolean[len];//该数组决定原字符串每个下标对应的字符是否输出
        LinkedList<Integer>[] stacks = new LinkedList[26];//26个栈代表26个小写字母,每个栈储存原字符串对应下标
        for(int i=0;i<26;i++){
            stacks[i] = new LinkedList();//初始化
        }
        for(int i=0;i<len;i++){
            Character ch = s.charAt(i);
            if(ch!='*'){//如果不是*,将下标压进对应栈中
                stacks[ch-'a'].offerFirst(i);//ch-'a'为下标
                
            }else{
                isDel[i] = true;//如果是*,最后应该删除,不应该输出
                for(int j=0;j<26;j++){//从小到大遍历,保证删除字典序最小的字母
                    if(!stacks[j].isEmpty()){
                        int k = stacks[j].removeFirst();//获取离*号最近的下标
                        isDel[k] = true;//删除原字符串中对应的字符
                        break;//删除一个即可,跳出循环
                    }
                }

            }
        }
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<len;i++) {
            if(!isDel[i]){
                sb.append(s.charAt(i));
            }
            
        }
        return sb.toString();
    }
}

找到按位与最接近 K 的子数组

给你一个数组nums和一个整数k。你需要找到nums的一个
子数组
,满足子数组中所有元素按位与运算AND的值与k的绝对差尽可能小。换言之,你需要选择一个子数组nums[l…r]满足|k-(nums[l]ANDnums[l+1]…ANDnums[r])|最小。

请你返回最小的绝对差值。

子数组是数组中连续的非空元素序列。

示例1:

输入:nums=[1,2,4,5],k=3

输出:1

解释:

子数组nums[2…3]的按位AND运算值为4,得到最小差值|3-4|=1。

解题思路

用划动窗口找到到index i的从左到右,最后一个小于k的子序列,和第一个大于或者等于k的子序列。保留后者。前两者序列与值与k的最小差异值都可以作为候选答案。

class Solution {
    public int minimumDifference(int[] nums, int k) {
        int res = Integer.MAX_VALUE;
		int n = nums.length;
		int[] left = new int[n + 1];
		left[0] = Integer.MAX_VALUE;
		int rightAnd = Integer.MAX_VALUE;
		int leftSize = 0;
		int rightSize = 0;
		int t ;
		for (int i = 0; i < n; i++) {
			var x = nums[i]; 
			rightSize++;
			rightAnd &= x;
			
			while ((left[leftSize] & rightAnd) < k) {
				t = left[leftSize] & rightAnd;
				res = Math.min(Math.abs(k - t), res);
				if (leftSize-- > 1)
					continue;
				for (int j = 0; j < rightSize; j++)
					left[j + 1] = left[j] & nums[i - j];

				leftSize = rightSize;
				rightSize = 0;
				rightAnd = Integer.MAX_VALUE;
				if (leftSize == 0)
					break;
			}
			t = left[leftSize] & rightAnd;
			res = Math.min(Math.abs(k - t), res);
		}
		return res;
    }
}

来源

LeetCode周赛

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吴代庄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值