问题
候诊室中的最少椅子数
给你一个字符串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;
}
}