欢迎大家加QQ群:623375442,可以方便群里面交流。

100307. Minimum Number of Chairs in a Waiting Room

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

  • 如果 s[i] == 'E',表示有一位顾客进入候诊室并占用一把椅子。
  • 如果 s[i] == 'L',表示有一位顾客离开候诊室,从而释放一把椅子。

返回保证每位进入候诊室的顾客都能有椅子坐的 最少 椅子数,假设候诊室最初是 空的 。

测试样例:

输入:s = "EEEEEEE"

输出:7

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

解答:遍历数组,记一下最大值。

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

100311. Count Days Without Meetings

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

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

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

测试样例:

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

输出:2

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

解答:计算一下前缀和。但是days的范围非常大,不能暴力计算。把meetings中所有出现的节点排序一下。meetings[i][0]代表某个位置+1,meeting[i][1]代表(meetings[i][1] + 1) -1。然后遍历排序完毕的meetings数组,计算一下前缀和。前缀和为0的区间代表没有会议。

class Solution {
    public int countDays(int days, int[][] meetings) {
        // 偷懒,用了红黑树排序。
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (int[] m : meetings) {
            map.put(m[0], map.getOrDefault(m[0], 0) + 1);
            map.put(m[1] + 1, map.getOrDefault(m[1] + 1, 0) - 1);
        }
        int res = 0;
        int lastTime = 1, meetingCount = 0;
        for (Map.Entry<Integer, Integer> kv : map.entrySet()) {
            // 计算前缀和
            int nextMeetingCount = meetingCount + kv.getValue();
            // 前缀和为0代表没有会议,更新没有会议的区间
            if (meetingCount == 0) {
                res += kv.getKey() - lastTime;
            }
            lastTime = kv.getKey();
            meetingCount = nextMeetingCount;
        }
        if (meetingCount == 0) {
            res += days + 1 - lastTime;
        }
        return res;
    }
}

100322. Lexicographically Minimum String After Removing Stars

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

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

  • 删除最左边的 '*' 字符,同时删除该星号字符左边一个字典序 最小 的字符。如果有多个字典序最小的字符,你可以删除它们中的任意一个。

请你返回删除所有 '*' 字符以后,剩余字符连接而成的 字典序最小 的字符串。

测试样例:

输入:s = "aaba*"

输出:"aab"

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

解答:将所有非'*'字符串用栈记录下来,每次碰到'*'之后,将最小字符的最大位置出栈(出栈代表删除该字符)。

class Solution {
    public String clearStars(String s) {
        int len = s.length();
        boolean[] isAdd = new boolean[len];
        Stack<Integer>[] stacks = new Stack[26];
        for (int i = 0; i < 26; ++i) {
            stacks[i] = new Stack<>();
        }
        for (int i = 0; i < len; ++i) {
            isAdd[i] = true;
            if (s.charAt(i) == '*') {
                isAdd[i] = false;
                // 最小字符出栈
                for (int j = 0; j < 26; ++j) {
                    if (!stacks[j].isEmpty()) {
                        isAdd[stacks[j].pop()] = false;
                        break;
                    }
                }
            } else {
                stacks[s.charAt(i) - 'a'].push(i);
            }
        }

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

100315. Find Subarray With Bitwise AND Closest to K

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

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

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

测试样例:

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

输出:1

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

解答:经典双指针。与运算符牵涉的数字越多,结果是单调递减的。利用双指针寻找第一个AND区间大于k的范围(可能寻找不到,注意不要指针越界)。

class Solution {
    public int minimumDifference(int[] nums, int k) {
        int[] arr = new int[30];
        int res = Integer.MAX_VALUE;
        int st = 0, ed = 0;
        while (ed < nums.length) {
            refresh(arr, nums[ed], 1);
            int add = countNum(arr, ed - st + 1);
            res = Math.min(res, Math.abs(k - add));
            while (st <= ed && add < k) {
                refresh(arr, nums[st++], -1);
                add = countNum(arr, ed - st + 1);
                res = Math.min(res, Math.abs(k - add));
            }
            ++ed;
        }
        return res;
    }

    private void refresh(int[] arr, int num, int diff) {
        for (int i = 0; i < 30; ++i) {
            if (isMark(num, i)) {
                arr[i] += diff;
            }
        }
    }

    private int countNum(int[] arr, int len) {
        int res = 0;
        for (int i = 0; i < 30; ++i) {
            if (arr[i] == len) {
                res += (1 << i);
            }
        }
        return res;
    }

    private boolean isMark(int num, int offset) {
        int tmp = (num >> offset) & 1;
        return tmp == 1;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *