[Leetcode Weekly Contest]308

链接:LeetCode

[Leetcode]2389. 和有限的最长子序列

给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。
子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。

前缀和+二分。

class Solution {
    public int[] answerQueries(int[] nums, int[] queries) {
        Arrays.sort(nums);
        List<Integer> array = new ArrayList<>();
        int result = 0;
        for(var num:nums) {
            result += num;
            array.add(result);
        }
        int n = queries.length;
        int[] res = new int[n];
        for(int i=0;i<n;++i) {
            res[i] = answer(array, queries[i]);
        }
        return res;
    }

    public int answer(List<Integer> nums, int target) {
        // first larger index
        int lo = 0, hi = nums.size() - 1;
        while(lo <= hi) {
            int mid = lo + ((hi-lo) >> 1);
            if(nums.get(mid) <= target) lo = mid + 1;
            else hi = mid - 1 ;
        }
        return lo;
    }
}

[Leetcode]2390. 从字符串中移除星号

给你一个包含若干星号 * 的字符串 s 。
在一步操作中,你可以:

  • 选中 s 中的一个星号。
  • 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。

返回移除 所有 星号之后的字符串。
注意:

  • 生成的输入保证总是可以执行题面中描述的操作。
  • 可以证明结果字符串是唯一的。

栈模拟。

class Solution {
    public String removeStars(String s) {
        ArrayDeque<Character> queue = new ArrayDeque<Character>();
        for(Character ch: s.toCharArray()) {
            if(ch == '*') queue.removeLast();
            else queue.addLast(ch);
        }
        StringBuilder sb = new StringBuilder();
        for(var ch:queue) {
            sb.append(ch);
        }
        return sb.toString();
    }
}

[Leetcode]2391. 收集垃圾的最少总时间

给你一个下标从 0 开始的字符串数组 garbage ,其中 garbage[i] 表示第 i 个房子的垃圾集合。garbage[i] 只包含字符 'M' ,'P' 和 'G' ,但可能包含多个相同字符,每个字符分别表示一单位的金属、纸和玻璃。垃圾车收拾 一 单位的任何一种垃圾都需要花费 1 分钟。
同时给你一个下标从 0 开始的整数数组 travel ,其中 travel[i] 是垃圾车从房子 i 行驶到房子 i + 1 需要的分钟数。
城市里总共有三辆垃圾车,分别收拾三种垃圾。每辆垃圾车都从房子 0 出发,按顺序 到达每一栋房子。但它们 不是必须 到达所有的房子。
任何时刻只有 一辆 垃圾车处在使用状态。当一辆垃圾车在行驶或者收拾垃圾的时候,另外两辆车 不能 做任何事情。
请你返回收拾完所有垃圾需要花费的 最少 总分钟数。

贪心, 我们可以把每种垃圾分别处理,累加耗时。
注意到,答案其实可以分为两部分:

  • 所有垃圾的数目,即 \(\textit{garbage}\) 中所有字符串的长度之和。
  • 根据每一种字符在 \(\textit{garbage}\) 中最后一次出现的下标,即每辆垃圾车必须向右开到的房子的最小值,得到每辆车需要开的最短距离。

遍历 \(\textit{garbage}\) 可以求出。

class Solution {
    public int garbageCollection(String[] garbage, int[] travel) {
        int res = 0;
        int idx1 = 0, idx2 = 0, idx3 = 0;
        for(int i=0;i<garbage.length;++i) {
            String gar = garbage[i];
            res += gar.length();
            if(gar.contains("M")) idx1 = i;
            if(gar.contains("P")) idx2 = i;
            if(gar.contains("G")) idx3 = i;
        }
        int n = travel.length, curSum = 0;
        int[] prefixSum = new int[n+1];
        for(int i=0;i<n;++i) {
            curSum += travel[i];
            prefixSum[i+1] = curSum;
        }
        res += prefixSum[idx1] + prefixSum[idx2] + prefixSum[idx3];
        return res;
    }
}

[Leetcode] 2392. 给定条件下构造矩阵

给你一个 正 整数 k ,同时给你:

  • 一个大小为 n 的二维整数数组 rowConditions ,其中 rowConditions[i] = [abovei, belowi] 和
  • 一个大小为 m 的二维整数数组 colConditions ,其中 colConditions[i] = [lefti, righti] 。

两个数组里的整数都是 1 到 k 之间的数字。
你需要构造一个 k x k 的矩阵,1 到 k 每个数字需要 恰好出现一次 。剩余的数字都是 0 。
矩阵还需要满足以下条件:

  • 对于所有 0 到 n - 1 之间的下标 i ,数字 abovei 所在的 行 必须在数字 belowi 所在行的上面。
  • 对于所有 0 到 m - 1 之间的下标 i ,数字 lefti 所在的 列 必须在数字 righti 所在列的左边。

返回满足上述要求的 任意 矩阵。如果不存在答案,返回一个空的矩阵。

拓扑排序
数字之间的约束只发生在行与行、列于列,而行与列之间没有任何约束。因此我们可以分别处理行与列中数字的相对顺序

class Solution {
    public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) {
        int[] rowOrder = getOrder(rowConditions, k), colOrder = getOrder(colConditions, k);
        int[][] res = new int[k][k];
        if(rowOrder[k-1] == 0 || colOrder[k-1] == 0) return new int[][]{};
        HashMap<Integer, Integer> val2RowIdx = getIdx(rowOrder), val2ColIdx = getIdx(colOrder);
        for(int i=1;i<k+1;++i) {
            res[val2RowIdx.getOrDefault(i, 0)][val2ColIdx.getOrDefault(i, 0)] = i;
        }
        return res;
    }

    public int[] getOrder(int[][] conditions, int k) {
        int[] indegree = new int[k];
        // Note: 这里如果用HashSet去重,要注意判断conditions是否存在重复情况
        HashMap<Integer, ArrayList<Integer>> hash = new HashMap<>();
        for(var cond:conditions) {
            int above = cond[0], below = cond[1];
            hash.computeIfAbsent(above-1, key -> new ArrayList<Integer>()).add(below-1);
            indegree[below-1] += 1;
        }
        int[] res = new int[k];
        for(int i=0;i<k;++i) {
            boolean zeroFalg = false;
            int j = 0;
            while(j<k) {
                if(indegree[j] == 0) {
                    zeroFalg = true;
                    break;
                }
                ++j;
            }
            if(!zeroFalg) break;
            indegree[j] -= 1;
            res[i] = j+1;
            for(var nxt:hash.getOrDefault(j, new ArrayList<Integer>())) indegree[nxt] -= 1;
        }
        return res;
    }

    public HashMap<Integer, Integer> getIdx(int[] nums) {
        HashMap<Integer, Integer> hash = new HashMap<>();
        for(int i=0;i<nums.length;++i) {
            hash.put(nums[i], i);
        }
        return hash;
    }
}

参考:
LeetCode

posted @ 2022-08-29 22:31  Jamest  阅读(44)  评论(0编辑  收藏  举报