LeetCode周赛357

LeetCode周赛357

链接:https://leetcode.cn/contest/weekly-contest-357/

A题

题意:字符串当前为i即反转前面子串。

public String finalString(String s) {  
    StringBuilder sb = new StringBuilder();  
    for (int i = 0; i < s.length(); i++) {  
        if (s.charAt(i) == 'i') {  
            sb.reverse();  
        } else {  
            sb.append(s.charAt(i));  
        }  
    }  
    return sb.toString();  
}

B题

给你一个长度为 n 的数组 nums 和一个整数 m 。请你判断能否执行一系列操作,将数组拆分成 n非空 数组。
在每一步操作中,你可以选择一个 长度至少为 2 的现有数组(之前步骤的结果) 并将其拆分成 2 个子数组,而得到的 每个 子数组,至少 需要满足以下条件之一:

  • 子数组的长度为 1 ,或者
  • 子数组元素之和 大于或等于 m
    如果你可以将给定数组拆分成 n 个满足要求的数组,返回 true ;否则,返回 false
    **注意:**子数组是数组中的一个连续非空元素序列。

思路:本质上,只要有两个连续的元素和大于等于m,则可以完成操作,所以暴力遍历一遍即可。

public boolean canSplitArray(List<Integer> nums, int m) {  
    if (nums.size() <= 2) {  
        return true;  
    }  
    for (int i = 0; i < nums.size() - 1; i++) {  
        if (nums.get(i) + nums.get(i + 1) >= m) {  
            return true;  
        }  
    }  
    return false;  
}
C题

给你一个下标从 0 开始、大小为 n x n 的二维矩阵 grid ,其中 (r, c) 表示:

  • 如果 grid[r][c] = 1 ,则表示一个存在小偷的单元格
  • 如果 grid[r][c] = 0 ,则表示一个空单元格
    你最开始位于单元格 (0, 0) 。在一步移动中,你可以移动到矩阵中的任一相邻单元格,包括存在小偷的单元格。
    矩阵中路径的 安全系数 定义为:从路径中任一单元格到矩阵中任一小偷所在单元格的 最小 曼哈顿距离。
    返回所有通向单元格 (n - 1, n - 1) 的路径中的 最大安全系数
    单元格 (r, c) 的某个 相邻 单元格,是指在矩阵中存在的 (r, c + 1)(r, c - 1)(r + 1, c)(r - 1, c) 之一。
    两个单元格 (a, b)(x, y) 之间的 曼哈顿距离 等于 | a - x | + | b - y | ,其中 |val| 表示 val 的绝对值。

思路:此题需要我们求满足val的最大值,可以用二分来求val。判断的时候要求得到每个点到小偷的最小曼哈顿距离大于等于val,这些点连通起来要保证起始点和终点连通,所以需要用到并查集。而求每个点到小偷的曼哈顿距离可以使用同源BFS,即遍历每个小偷每一步所覆盖的点的范围,然后更新。直至矩阵中所有的点都覆盖。

同源BFS代码:

var dis = new int[grid.size()][grid.get(0).size()];  
var vis = new boolean[grid.size()][grid.get(0).size()];  
var dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};  
for (int i = 0; i < grid.size(); i++) {  
    for (int j = 0; j < grid.get(i).size(); j++) {  
        if (grid.get(i).get(j) == 1) {  
            queue.add(new int[]{i, j});  
            dis[i][j] = 0;  
            vis[i][j] = true;  
        }  
    }  
}  
int cnt = 0;  
while(!queue.isEmpty()) {  
    int size = queue.size();  
    cnt++;  
    for (int i = 0; i < size; i++) {  
        int[] ints = queue.poll();  
        for (var dir : dirs) {  
            int x = ints[0] + dir[0];  
            int y = ints[1] + dir[1];  
            if (x >= 0 && x < grid.size() && y >= 0 && y < grid.get(0).size() && !vis[x][y]) {  
                vis[x][y] = true;  
                dis[x][y] = cnt;  
                queue.add(new int[]{x, y});  
            }  
        }  
    }  
}

离散化 + 并查集+二分代码:

private int[] fa;  
private int find(int x) {  
    if (fa[x] != x) fa[x] = find(fa[x]);  
    return fa[x];  
}  
private void merge(int x, int y) {  
    if (find(x) != find(y)) {  
        fa[find(x)] = find(y);  
    }  
}
int n = grid.get(0).size();  
fa = new int[n * n];  
int l = 1, r = 400;  
int len = 0;  
while(l <= r) {  
    for (int i = 0; i < n * n; i++) {  
        fa[i] = i;  
    }  
    vis = new boolean[grid.size()][grid.get(0).size()];  
    int mid = (l + r) >> 1;  
    for (int i = 0; i < grid.size(); i++) {  
        for (int j = 0; j < grid.get(i).size(); j++) {  
            if (dis[i][j] < mid) {  
                continue;  
            }  
            if (j != 0 && vis[i][j - 1]) {  
                merge(i * n + j, i * n + j - 1);  
            }  
            if (i != 0 && vis[i - 1][j]) {  
                merge(i * n + j, (i - 1) * n + j);  
            }  
            vis[i][j] = true;  
        }  
    }  
    if (vis[grid.size() - 1][grid.get(0).size() - 1] && find(0) == find((grid.size() - 1) * n + grid.get(0).size() - 1)) {  
        l = mid + 1;  
        len = mid;  
    } else {  
        r = mid - 1;  
    }  
}  
return len;

完整代码如下:

private int[] fa;  
private int find(int x) {  
    if (fa[x] != x) fa[x] = find(fa[x]);  
    return fa[x];  
}  
private void merge(int x, int y) {  
    if (find(x) != find(y)) {  
        fa[find(x)] = find(y);  
    }  
}  
public int maximumSafenessFactor(List<List<Integer>> grid) {  
    Deque<int[]> queue = new LinkedList<>();  
    var dis = new int[grid.size()][grid.get(0).size()];  
    var vis = new boolean[grid.size()][grid.get(0).size()];  
    var dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};  
    for (int i = 0; i < grid.size(); i++) {  
        for (int j = 0; j < grid.get(i).size(); j++) {  
            if (grid.get(i).get(j) == 1) {  
                queue.add(new int[]{i, j});  
                dis[i][j] = 0;  
                vis[i][j] = true;  
            }  
        }  
    }  
    int cnt = 0;  
    while(!queue.isEmpty()) {  
        int size = queue.size();  
        cnt++;  
        for (int i = 0; i < size; i++) {  
            int[] ints = queue.poll();  
            for (var dir : dirs) {  
                int x = ints[0] + dir[0];  
                int y = ints[1] + dir[1];  
                if (x >= 0 && x < grid.size() && y >= 0 && y < grid.get(0).size() && !vis[x][y]) {  
                    vis[x][y] = true;  
                    dis[x][y] = cnt;  
                    queue.add(new int[]{x, y});  
                }  
            }  
        }  
    }  
    int n = grid.get(0).size();  
    fa = new int[n * n];  
    int l = 1, r = 400;  
    int len = 0;  
    while(l <= r) {  
        for (int i = 0; i < n * n; i++) {  
            fa[i] = i;  
        }  
        vis = new boolean[grid.size()][grid.get(0).size()];  
        int mid = (l + r) >> 1;  
        for (int i = 0; i < grid.size(); i++) {  
            for (int j = 0; j < grid.get(i).size(); j++) {  
                if (dis[i][j] < mid) {  
                    continue;  
                }  
                if (j != 0 && vis[i][j - 1]) {  
                    merge(i * n + j, i * n + j - 1);  
                }  
                if (i != 0 && vis[i - 1][j]) {  
                    merge(i * n + j, (i - 1) * n + j);  
                }  
                vis[i][j] = true;  
            }  
        }  
        if (vis[grid.size() - 1][grid.get(0).size() - 1] && find(0) == find((grid.size() - 1) * n + grid.get(0).size() - 1)) {  
            l = mid + 1;  
            len = mid;  
        } else {  
            r = mid - 1;  
        }  
    }  
    return len;  
}

此题也可以通过遍历哈曼顿距离所对应的点来求值,当前曼哈顿距离下,对应的点做一遍并查集,然后判断是否满足起始点和重点在同一个集合内,如果满足直接输出当前值即可。

D题

题意:给你一个长度为 n 的二维整数数组 items 和一个整数 k
items[i] = [profiti, categoryi],其中 profiticategoryi 分别表示第 i 个项目的利润和类别。
现定义 items子序列优雅度 可以用 total_profit + distinct_categories2 计算,其中 total_profit 是子序列中所有项目的利润总和,distinct_categories 是所选子序列所含的所有类别中不同类别的数量。
你的任务是从 items 所有长度为 k 的子序列中,找出 最大优雅度
用整数形式表示并返回 items 中所有长度恰好为 k 的子序列的最大优雅度。
注意: 数组的子序列是经由原数组删除一些元素(可能不删除)而产生的新数组,且删除不改变其余元素相对顺序。

思路:也就是数组中任选k个元素,满足元素的val + 元素种类的平方和最大。
对元素的val从大到小排序,并选前k个。在保证元素的val和为最大的情况下,然后进行反悔贪心操作。对于下一个可取的元素而言,若它是一个新的种类,并且之前所取的元素中,有种类重复的元素,那么我们添加它,并且删除之前种类重复元素中,val最小的一个。重复操作,选择所有结果的最大值即是最优解。
代码如下:

public long findMaximumElegance(int[][] items, int k) {  
    Arrays.sort(items, (a, b) -> b[0] - a[0]);  
    long mx = 0;  
    long preSum = 0;  
    Set<Integer> set = new HashSet<>();  
    Deque<Integer> stack = new LinkedList<>();  
    for (int i = 0; i < items.length; i++) {  
        if (i < k) {  
            preSum += items[i][0];  
            if (!set.add(items[i][1])) {  
                stack.push(items[i][0]);  
            }  
        } else if (!stack.isEmpty() && set.add(items[i][1])) {  
            preSum += items[i][0] - stack.pop();  
        }  
        mx = Math.max(mx, preSum + (long) set.size() * set.size());  
    }  
    return mx;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值