[Leetcode Weekly Contest]260
链接:LeetCode
[Leetcode]2016. 增量元素之间的最大差值
给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < n 且 nums[i] < nums[j] 。
返回 最大差值 。如果不存在满足要求的 i 和 j ,返回 -1 。
遍历即可。
class Solution {
public int maximumDifference(int[] nums) {
int res = -1;
int n = nums.length;
for(int i =0;i<n;++i) {
for(int j=i+1;j<n;++j) {
if(nums[j] > nums[i]) {
res = Math.max(res,nums[j]-nums[i]);
}
}
}
return res;
}
}
[Leetcode]2017. 网格游戏
给你一个下标从 0 开始的二维数组 grid ,数组大小为 2 x n ,其中 grid[r][c] 表示矩阵中 (r, c) 位置上的点数。现在有两个机器人正在矩阵上参与一场游戏。
两个机器人初始位置都是 (0, 0) ,目标位置是 (1, n-1) 。每个机器人只会 向右 ((r, c) 到 (r, c + 1)) 或 向下 ((r, c) 到 (r + 1, c)) 。
游戏开始,第一个 机器人从 (0, 0) 移动到 (1, n-1) ,并收集路径上单元格的全部点数。对于路径上所有单元格 (r, c) ,途经后 grid[r][c] 会重置为 0 。然后,第二个 机器人从 (0, 0) 移动到 (1, n-1) ,同样收集路径上单元的全部点数。注意,它们的路径可能会存在相交的部分。
第一个 机器人想要打击竞争对手,使 第二个 机器人收集到的点数 最小化 。与此相对,第二个 机器人想要 最大化 自己收集到的点数。两个机器人都发挥出自己的 最佳水平 的前提下,返回 第二个 机器人收集到的 点数 。
由于机器人只会向下和向右行走,可以遍历每一种情况,计算最优解。另外,在比较第二个机器人不同路线的点数时,可以利用前缀和来优化算法复杂度。
class Solution {
public long gridGame(int[][] grid) {
long sum1 = 0, sum2 = Arrays.stream(grid[0]).asLongStream().sum(); // 大数溢出
int n = grid[0].length;
long res = Long.MAX_VALUE;
for(int i=0; i<n; ++i) {
sum2 -= grid[0][i];
if(i!=0) sum1 += grid[1][i-1];
long cur = Math.max(sum1, sum2);
res = Math.min(res, cur);
}
return res;
}
}
[Leetcode]2018. 判断单词是否能放入填字游戏内
给你一个 m x n 的矩阵 board ,它代表一个填字游戏 当前 的状态。填字游戏格子中包含小写英文字母(已填入的单词),表示 空 格的 ' ' 和表示 障碍 格子的 '#' 。
如果满足以下条件,那么我们可以 水平 (从左到右 或者 从右到左)或 竖直 (从上到下 或者 从下到上)填入一个单词:
- 该单词不占据任何 '#' 对应的格子。
- 每个字母对应的格子要么是 ' ' (空格)要么与 board 中已有字母 匹配 。
- 如果单词是 水平 放置的,那么该单词左边和右边 相邻 格子不能为 ' ' 或小写英文字母。
- 如果单词是 竖直 放置的,那么该单词上边和下边 相邻 格子不能为 ' ' 或小写英文字母。
给你一个字符串 word ,如果 word 可以被放入 board 中,请你返回 true ,否则请返回 false 。
深度优先遍历。对每一个方格向上,下,左,右遍历判断即可。
class Solution {
enum Direction
{
TOP,DOWN,LEFT,RIGHT;
}
public boolean placeWordInCrossword(char[][] board, String word) {
int n = board.length, m=board[0].length;
int lenWord = word.length();
for(int i=0;i<n;++i) {
for (int j=0; j<m; ++j) {
if(board[i][j]=='#') continue;
if((i==0 || board[i-1][j]=='#') && i<=n-lenWord && dfs(board,word,i,j,Direction.DOWN)) return true;
if((i==n-1 || board[i+1][j]=='#') && i>=lenWord-1 && dfs(board,word,i,j,Direction.TOP)) return true;
if((j==0 || board[i][j-1]=='#') && j<=m-lenWord && dfs(board,word,i,j,Direction.RIGHT)) return true;
if((j==m-1 || board[i][j+1]=='#') && j>=lenWord-1 && dfs(board,word,i,j,Direction.LEFT)) return true;
}
}
return false;
}
public boolean dfs(char[][] board, String word, int i, int j, Direction dir) {
int n = board.length, m=board[0].length;
int lenWord = word.length();
for(int ind=0;ind<lenWord;ind++) {
if (board[i][j] != ' ' && board[i][j]!=word.charAt(ind)) return false;
if(dir == Direction.DOWN) i ++;
if(dir == Direction.TOP) i --;
if(dir == Direction.RIGHT) j ++;
if(dir == Direction.LEFT) j --;
}
if(i>=0 && i<=n-1 && j>=0 && j<=m-1 && board[i][j]!='#') return false;
return true;
}
}
[Leetcode]2019. 解出数学表达式的学生分数
给你一个字符串 s ,它 只 包含数字 0-9 ,加法运算符 '+' 和乘法运算符 '' ,这个字符串表示一个 合法 的只含有 个位数数字 的数学表达式(比方说 3+52)。有 n 位小学生将计算这个数学表达式,并遵循如下 运算顺序 :
- 按照 从左到右 的顺序计算 乘法 ,然后
- 按照 从左到右 的顺序计算 加法 。
给你一个长度为 n 的整数数组 answers ,表示每位学生提交的答案。你的任务是给 answer 数组按照如下 规则 打分:
- 如果一位学生的答案 等于 表达式的正确结果,这位学生将得到 5 分。
- 否则,如果答案由 一处或多处错误的运算顺序 计算得到,那么这位学生能得到 2 分。
- 否则,这位学生将得到 0 分。
请你返回所有学生的分数和。
逆波兰表达式+区间DP。计算表达式的正确结果可以使用逆波兰表达式。而计算由 一处或多处错误的运算顺序得到的 错误答案,则可以采取分治的方法,即每一步选择第几个运算符为当前运算,将字符串分为左右两边,再对左右两边的字符串递归求解,由于分解过程中存在分解相同的情况,可以用map作为记忆化存储。
class Solution {
HashMap<String, Set<Integer>> hash = new HashMap<>();//用于记忆化搜索
//计算表达式的正确值
public int result(String s){
Deque<Integer> q = new LinkedList();
Deque<Character> cq = new LinkedList();
int idx = 0;
for(int i = 0;i < s.length();i ++){
if(s.charAt(i) >= '0' && s.charAt(i) <= '9'){
q.offerFirst(s.charAt(i) - '0');
if(!cq.isEmpty() && cq.peekFirst() == '*'){
int n1 = q.pollFirst();
int n2 = q.pollFirst();
q.offerFirst(n1 * n2);
cq.pollFirst();
}
}else{
cq.offerFirst(s.charAt(i));
}
}
while(!cq.isEmpty()){
int n1 = q.pollFirst();
int n2 = q.pollFirst();
q.offerFirst(n1 + n2);
cq.pollFirst();
}
return q.peekFirst();
}
public int scoreOfStudents(String s, int[] answers) {
var nums = new ArrayList<Integer>();
var ops = new ArrayList<Character>();
int trueAnswer = result(s);
for(int ind=0; ind<s.length();++ind){
if((ind&1)!=0) ops.add(s.charAt(ind));
else nums.add((int)(s.charAt(ind)-'0'));
}
var twoAnswer = dfs(nums,ops,0,nums.size()-1);
int res = 0;
for (var answer:
answers) {
if(answer == trueAnswer) res += 5;
else if(twoAnswer.contains(answer)) res += 2;
}
return res;
}
public HashSet<Integer> dfs(List<Integer> nums,List<Character> ops, int i, int j) {
String key = i+"-"+j;
if(hash.containsKey(key)) {
return (HashSet<Integer>)hash.get(key);
}
var hashSet = new HashSet<Integer>();
if(i == j) {
hashSet.add(nums.get(i));
hash.put(key,hashSet);
return hashSet;
//hash.put(key,new HashSet<Integer>(){{add(nums.get(i));}});
//return (HashSet<Integer>)hash.get(key);
}
for(int ind=i;ind<j;ind++)
{
var nums1 = dfs(nums,ops,i,ind);
var nums2 = dfs(nums,ops,ind+1,j);
var op = ops.get(ind);
for (int num1:nums1) {
for (int num2:nums2) {
if(op=='+' && num1+num2<=1000) hashSet.add(num1+num2);
else if(op=='*' && num1*num2<=1000) hashSet.add(num1*num2);
}
}
hash.put(key,hashSet);
}
return hashSet;
}
}