[Leetcode Weekly Contest]293

链接:LeetCode

[Leetcode]2273. 移除字母异位词后的结果数组

给你一个下标从 0 开始的字符串 words ,其中 words[i] 由小写英文字符组成。
在一步操作中,需要选出任一下标 i ,从 words 中 删除 words[i] 。其中下标 i 需要同时满足下述两个条件:

  1. 0 < i < words.length
  2. words[i - 1] 和 words[i] 是 字母异位词 。

只要可以选出满足条件的下标,就一直执行这个操作。
在执行所有操作后,返回 words 。可以证明,按任意顺序为每步操作选择下标都会得到相同的结果。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。例如,"dacb" 是 "abdc" 的一个字母异位词。

遍历即可。

class Solution {
    public List<String> removeAnagrams(String[] words) {
        String pre = "";
        List<String> res = new ArrayList<>();
        for(var word:words) {
            var charArray = word.toCharArray();
            Arrays.sort(charArray);
            String sortedWord = String.valueOf(charArray);
            if(sortedWord.equals(pre)) {
                continue;
            } else {
                res.add(word);
                pre = sortedWord;
            }
        }
        return res;
    }
}

[Leetcode]2274. 不含特殊楼层的最大连续楼层数

Alice 管理着一家公司,并租用大楼的部分楼层作为办公空间。Alice 决定将一些楼层作为 特殊楼层 ,仅用于放松。
给你两个整数 bottom 和 top ,表示 Alice 租用了从 bottom 到 top(含 bottom 和 top 在内)的所有楼层。另给你一个整数数组 special ,其中 special[i] 表示 Alice 指定用于放松的特殊楼层。
返回不含特殊楼层的 最大 连续楼层数。

遍历即可。注意遍历到最后一个特殊楼层时,需要考虑此楼层与上一个特殊楼层的差,以及top与该楼层的差。

class Solution {
    public int maxConsecutive(int bottom, int top, int[] special) {
        Arrays.sort(special);
        int res = 0;
        for(int i=0;i<special.length;++i) {
            if(i == 0) res = Math.max(res, special[i] - bottom);
            else res = Math.max(res, special[i] - special[i-1] - 1 );
            if(i == special.length-1) res = Math.max(res, top - special[i]);
        }
        return res;
    }
}

[Leetcode]2275. 按位与结果大于零的最长组合

对数组 nums 执行 按位与 相当于对数组 nums 中的所有整数执行 按位与 。

  • 例如,对 nums = [1, 5, 3] 来说,按位与等于 1 & 5 & 3 = 1 。
  • 同样,对 nums = [7] 而言,按位与等于 7 。

给你一个正整数数组 candidates 。计算 candidates 中的数字每种组合下 按位与 的结果。 candidates 中的每个数字在每种组合中只能使用 一次 。
返回按位与结果大于 0 的 最长 组合的长度。

位运算题目经典技巧:逐个考虑每一个比特位。
假设元素值只有 0 和 1,那么解法就很简单了:由于不能选 0(这会导致按位与为 0),我们选择所有的 1,答案即为 1 的个数。
将上述结论推广,考虑每一个比特位,统计这一位上的 1 的个数,取所有个数的最大值作为答案。

class Solution {
    public int largestCombination(int[] candidates) {
        int[] cnt = new int[32];
        int max = 0;
        for (int c : candidates) {
            for (int i = 0; i < 32; i++) {
                if (((1 << i) & c) > 0) cnt[i]++;
            }
        }
        for (int i = 0; i < 32; i++) {
            max = Math.max(max, cnt[i]);
        }
        return max;
    }
}

[Leetcode]2276. 统计区间中的整数数目

给你区间的 空 集,请你设计并实现满足要求的数据结构:

  • 新增:添加一个区间到这个区间集合中。
  • 统计:计算出现在 至少一个 区间中的整数个数。

实现 CountIntervals 类:

  • CountIntervals() 使用区间的空集初始化对象
  • void add(int left, int right) 添加区间 [left, right] 到区间集合之中。
  • int count() 返回出现在 至少一个 区间中的整数个数。

注意:区间 [left, right] 表示满足 left <= x <= right 的所有整数 x 。

对于本题来说,线段树的每个节点可以保存对应范围的左右端点 l 和 r,以及范围内 add 过的整数个数 \(\textit{cnt}\)

代码实现时,无需记录 lazy tag,这是因为被覆盖的范围无需再次覆盖,因此若 \(\textit{cnt}\) 等于范围的长度 \(r-l+1\),则可直接返回。

class CountIntervals {
    CountIntervals left, right;
    int l, r, res;

    public CountIntervals() {
        l = 1;
        r = (int) 1e9;
    }

    CountIntervals(int l, int r) {
        this.l = l;
        this.r = r;
    }

    public void add(int L, int R) { // 为方便区分变量名,将递归中始终不变的入参改为大写(视作常量)
        if (res == r - l + 1) return; // 当前节点已被完整覆盖,无需执行任何操作
        if (L <= l && r <= R) { // 当前节点已被区间 [L,R] 完整覆盖,不再继续递归
            res = r - l + 1;
            return;
        }
        int mid = (l + r) / 2;
        if (left == null) left = new CountIntervals(l, mid); // 动态开点
        if (right == null) right = new CountIntervals(mid + 1, r); // 动态开点
        if (L <= mid) left.add(L, R);
        if (mid < R) right.add(L, R);
        res = left.res + right.res;
    }

    public int count() {
        return res;
    }
}

参考:LeetCode

posted @ 2022-06-27 18:55  Jamest  阅读(21)  评论(0编辑  收藏  举报