682. 棒球比赛
题目链接
题目描述
你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。
比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops
,其中 ops[i]
是你需要记录的第 i
项操作,ops
遵循下述规则:
- 整数
x
- 表示本回合新获得分数x
"+"
- 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。"D"
- 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。"C"
- 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。
示例 1:
输入:ops = ["5","2","C","D","+"]
输出:30
解释:
"5" - 记录加 5 ,记录现在是 [5]
"2" - 记录加 2 ,记录现在是 [5, 2]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5].
"D" - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].
"+" - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].
所有得分的总和 5 + 10 + 15 = 30
示例 2:
输入:ops = ["5","-2","4","C","D","9","+","+"]
输出:27
解释:
"5" - 记录加 5 ,记录现在是 [5]
"-2" - 记录加 -2 ,记录现在是 [5, -2]
"4" - 记录加 4 ,记录现在是 [5, -2, 4]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5, -2]
"D" - 记录加 2 * -2 = -4 ,记录现在是 [5, -2, -4]
"9" - 记录加 9 ,记录现在是 [5, -2, -4, 9]
"+" - 记录加 -4 + 9 = 5 ,记录现在是 [5, -2, -4, 9, 5]
"+" - 记录加 9 + 5 = 14 ,记录现在是 [5, -2, -4, 9, 5, 14]
所有得分的总和 5 + -2 + -4 + 9 + 5 + 14 = 27
示例 3:
输入:ops = ["1"]
输出:1
提示:
1 <= ops.length <= 1000
ops[i]
为"C"
、"D"
、"+"
,或者一个表示整数的字符串。整数范围是[-3 * 104, 3 * 104]
- 对于
"+"
操作,题目数据保证记录此操作时前面总是存在两个有效的分数 - 对于
"C"
和"D"
操作,题目数据保证记录此操作时前面总是存在一个有效的分数
解答思路一【Java】
时间2 ms 击败 84.55%
内存39.7 MB 击败 34.74%
典型的模拟题,这道题没啥特别的,跟着题目给的思路走就可以了
- 首先创建一个栈(Stack)用于存储得分。
- 遍历操作数组中的每个操作。
- 对于每个操作,
- 如果是"+"操作,将栈顶元素弹出,与新的栈顶元素相加后再将原来的栈顶元素重新入栈。
- 如果是"D"操作,将栈顶元素乘以2后入栈。
- 如果是"C"操作,将栈顶元素弹出。
- 如果是数字操作,将该操作转换为整数后入栈。
- 遍历完操作数组后,将栈中剩余的元素弹出并累加得分。
- 返回得分结果。
import java.util.Stack;
class Solution {
public int calPoints(String[] operations) {
Stack<Integer> stack = new Stack<>();
for (String op : operations) {
if (op.equals("+")) {
int top = stack.pop();
int newTop = top + stack.peek();
stack.push(top);
stack.push(newTop);
} else if (op.equals("D")) {
stack.push(stack.peek() * 2);
} else if (op.equals("C")) {
stack.pop();
} else {
stack.push(Integer.parseInt(op));
}
}
int sum = 0;
while (!stack.isEmpty()) {
sum += stack.pop();
}
return sum;
}
}
这段代码涉及的知识点包括:
- 栈(Stack):用于存储得分的数据结构。
- 字符串操作:通过判断操作字符串的内容来执行相应的操作。
- 类型转换:将字符串转换为整数类型。
- 循环结构:通过循环遍历操作数组和栈的元素。
- 条件判断:通过条件判断语句来判断操作的类型,并执行相应的操作。
657. 机器人能否返回原点
题目链接
题目描述
在二维平面上,有一个机器人从原点 (0, 0)
开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0)
处结束。
移动顺序由字符串 moves
表示。字符 move[i]
表示其第 i
次移动。机器人的有效动作有 R
(右),L
(左),U
(上)和 D
(下)。
如果机器人在完成所有动作后返回原点,则返回 true
。否则,返回 false
。
注意:机器人“面朝”的方向无关紧要。 “R”
将始终使机器人向右移动一次,“L”
将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。
示例 1:
输入: moves = "UD"
输出: true
解释:机器人向上移动一次,然后向下移动一次。所有动作都具有相同的幅度,因此它最终回到它开始的原点。因此,我们返回 true。
示例 2:
输入: moves = "LL"
输出: false
解释:机器人向左移动两次。它最终位于原点的左侧,距原点有两次 “移动” 的距离。我们返回 false,因为它在移动结束时没有返回原点。
解答思路一【Java】
时间4 ms 击败 95.89%
内存42.4 MB 击败 43.39%
- 首先定义两个变量x和y,用于记录横向和纵向移动的次数。初始值都为0。
- 遍历移动操作字符串中的每个字符。
- 对于每个移动操作字符,
- 如果是'R',表示向右移动,则将x加1。
- 如果是'L',表示向左移动,则将x减1。
- 如果是'U',表示向上移动,则将y加1。
- 如果是'D',表示向下移动,则将y减1。
- 遍历完移动操作字符串后,判断x和y是否都为0。
- 如果都为0,表示移动操作会回到原点,返回true。
- 如果有任何一个不为0,表示移动操作不会回到原点,返回false。
class Solution {
public boolean judgeCircle(String moves) {
int x = 0; // 横向移动次数
int y = 0; // 纵向移动次数
for (char move : moves.toCharArray()) {
if (move == 'R') {
x++;
} else if (move == 'L') {
x--;
} else if (move == 'U') {
y++;
} else if (move == 'D') {
y--;
}
}
return x == 0 && y == 0;
}
}
这段代码涉及的知识点包括:
- 字符串操作:遍历移动操作字符串中的每个字符。
- 循环结构:通过循环遍历移动操作字符串的每个字符。
- 条件判断:通过条件判断语句判断移动操作的类型,并执行相应的操作。
- 变量的增减操作:根据移动操作的类型,对变量进行累加或累减操作。
- 返回结果:根据最后计算出的x和y的值,判断移动操作是否会回到原点,并返回相应的结果。
1275. 找出井字棋的获胜者
题目链接
题目描述
A 和 B 在一个 3 x 3 的网格上玩井字棋。
井字棋游戏的规则如下:
- 玩家轮流将棋子放在空方格 (" ") 上。
- 第一个玩家 A 总是用 "X" 作为棋子,而第二个玩家 B 总是用 "O" 作为棋子。
- "X" 和 "O" 只能放在空方格中,而不能放在已经被占用的方格上。
- 只要有 3 个相同的(非空)棋子排成一条直线(行、列、对角线)时,游戏结束。
- 如果所有方块都放满棋子(不为空),游戏也会结束。
- 游戏结束后,棋子无法再进行任何移动。
给你一个数组 moves
,其中每个元素是大小为 2
的另一个数组(元素分别对应网格的行和列),它按照 A 和 B 的行动顺序(先 A 后 B)记录了两人各自的棋子位置。
如果游戏存在获胜者(A 或 B),就返回该游戏的获胜者;如果游戏以平局结束,则返回 "Draw";如果仍会有行动(游戏未结束),则返回 "Pending"。
你可以假设 moves
都 有效(遵循井字棋规则),网格最初是空的,A 将先行动。
示例 1:
输入:moves = [[0,0],[2,0],[1,1],[2,1],[2,2]]
输出:"A"
解释:"A" 获胜,他总是先走。
"X " "X " "X " "X " "X "
" " -> " " -> " X " -> " X " -> " X "
" " "O " "O " "OO " "OOX"
示例 2:
输入:moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]]
输出:"B"
解释:"B" 获胜。
"X " "X " "XX " "XXO" "XXO" "XXO"
" " -> " O " -> " O " -> " O " -> "XO " -> "XO "
" " " " " " " " " " "O "
示例 3:
输入:moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]]
输出:"Draw"
输出:由于没有办法再行动,游戏以平局结束。
"XXO"
"OOX"
"XOX"
示例 4:
输入:moves = [[0,0],[1,1]]
输出:"Pending"
解释:游戏还没有结束。
"X "
" O "
" "
提示:
1 <= moves.length <= 9
moves[i].length == 2
0 <= moves[i][j] <= 2
moves
里没有重复的元素。moves
遵循井字棋的规则。
解答思路一【Java】
时间0 ms 击败 100%
内存39.3 MB 击败 12.26%
- 首先创建一个3x3的二维数组grid,用于表示井字棋的网格。
- 创建一个变量player,用于表示当前玩家的ID,初始值为1,表示玩家A。
- 遍历moves数组中的每个落子操作。
- 对于每个落子操作,提取出行号和列号,并将对应位置的二维数组中的元素更新为当前玩家的ID。然后切换到下一个玩家。
- 遍历检查行和列的胜利情况:
- 如果某一行或某一列的格子中的元素都相同且不为0,则表示有玩家获胜,根据该格子中的元素判断获胜的玩家是A还是B。
- 检查对角线的胜利情况:
- 如果两条对角线上的格子中的元素都相同且不为0,则表示有玩家获胜,根据该格子中的元素判断获胜的玩家是A还是B。
- 检查是否还有空方格:
- 如果所有格子都不为0,表示棋盘已经填满,但没有玩家获胜,返回"Draw"表示平局。
- 如果以上条件都不满足,则返回"Pending"表示棋局还未结束。
class Solution {
public String tictactoe(int[][] moves) {
int[][] grid = new int[3][3]; // 二维数组表示井字棋网格
int player = 1; // 玩家ID,1表示A, -1表示B
for (int[] move : moves) {
int row = move[0]; // 当前落子的行号
int col = move[1]; // 当前落子的列号
grid[row][col] = player; // 更新网格
player = -player; // 切换玩家
}
// 检查行和列
for (int i = 0; i < 3; i++) {
if (grid[i][0] != 0 && grid[i][0] == grid[i][1] && grid[i][0] == grid[i][2]) {
return grid[i][0] == 1 ? "A" : "B";
}
if (grid[0][i] != 0 && grid[0][i] == grid[1][i] && grid[0][i] == grid[2][i]) {
return grid[0][i] == 1 ? "A" : "B";
}
}
// 检查对角线
if (grid[0][0] != 0 && grid[0][0] == grid[1][1] && grid[0][0] == grid[2][2]) {
return grid[0][0] == 1 ? "A" : "B";
}
if (grid[0][2] != 0 && grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0]) {
return grid[0][2] == 1 ? "A" : "B";
}
// 检查是否有空方格
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (grid[i][j] == 0) {
return "Pending";
}
}
}
// 没有获胜者且无空方格,平局
return "Draw";
}
}
这段代码涉及的知识点包括:
- 二维数组:用于表示井字棋的网格。
- 循环结构:通过循环遍历落子操作数组和网格中的元素。
- 条件判断:通过条件判断语句判断胜利的情况和平局的情况。
- 数组的索引和赋值:通过索引获取到二维数组中的元素,并对元素进行赋值。
- 变量的切换和使用:通过player变量切换玩家,并根据当前玩家的ID进行操作。
- 返回结果:根据检查的结果,返回相应的胜负结果或平局结果。
1041. 困于环中的机器人
题目链接
题目描述
在无限的平面上,机器人最初位于 (0, 0)
处,面朝北方。注意:
- 北方向 是y轴的正方向。
- 南方向 是y轴的负方向。
- 东方向 是x轴的正方向。
- 西方向 是x轴的负方向。
机器人可以接受下列三条指令之一:
"G"
:直走 1 个单位"L"
:左转 90 度"R"
:右转 90 度
机器人按顺序执行指令 instructions
,并一直重复它们。
只有在平面中存在环使得机器人永远无法离开时,返回 true
。否则,返回 false
。
示例 1:
输入:instructions = "GGLLGG"
输出:true
解释:机器人最初在(0,0)处,面向北方。
“G”:移动一步。位置:(0,1)方向:北。
“G”:移动一步。位置:(0,2).方向:北。
“L”:逆时针旋转90度。位置:(0,2).方向:西。
“L”:逆时针旋转90度。位置:(0,2)方向:南。
“G”:移动一步。位置:(0,1)方向:南。
“G”:移动一步。位置:(0,0)方向:南。
重复指令,机器人进入循环:(0,0)——>(0,1)——>(0,2)——>(0,1)——>(0,0)。
在此基础上,我们返回true。
示例 2:
输入:instructions = "GG"
输出:false
解释:机器人最初在(0,0)处,面向北方。
“G”:移动一步。位置:(0,1)方向:北。
“G”:移动一步。位置:(0,2).方向:北。
重复这些指示,继续朝北前进,不会进入循环。
在此基础上,返回false。
示例 3:
输入:instructions = "GL"
输出:true
解释:机器人最初在(0,0)处,面向北方。
“G”:移动一步。位置:(0,1)方向:北。
“L”:逆时针旋转90度。位置:(0,1).方向:西。
“G”:移动一步。位置:(- 1,1)方向:西。
“L”:逆时针旋转90度。位置:(- 1,1)方向:南。
“G”:移动一步。位置:(- 1,0)方向:南。
“L”:逆时针旋转90度。位置:(- 1,0)方向:东方。
“G”:移动一步。位置:(0,0)方向:东方。
“L”:逆时针旋转90度。位置:(0,0)方向:北。
重复指令,机器人进入循环:(0,0)——>(0,1)——>(- 1,1)——>(- 1,0)——>(0,0)。
在此基础上,我们返回true。
提示:
1 <= instructions.length <= 100
instructions[i]
仅包含'G', 'L', 'R'
解答思路一【Java】
时间0 ms 击败 100%
内存39.2 MB 击败 95.21%
这道题只要判断机器人走完一圈会不会回到原地就行了
- 首先创建变量x和y,用于表示机器人的横纵坐标位置,初始值都为0。
- 创建变量direction,用于表示机器人的方向,初始值为0,表示朝北方向。
- 遍历指令字符串中的每个字符。
- 对于每个字符,
- 如果是'G',根据当前的方向向对应的坐标轴方向移动一步。
- 如果是'L',将方向逆时针旋转90度。
- 如果是'R',将方向顺时针旋转90度。
- 判断机器人的运动结果是否会返回出发位置。如果满足以下任意一个条件,返回true;否则返回false:
- 机器人停止后,横纵坐标都为0;
- 机器人停止后,方向不再是向北方向。
class Solution {
public boolean isRobotBounded(String instructions) {
int x = 0;
int y = 0;
int direction = 0; // 0表示北,1表示东,2表示南,3表示西
for (char c : instructions.toCharArray()) {
if (c == 'G') {
if (direction == 0) {
y++;
} else if (direction == 1) {
x++;
} else if (direction == 2) {
y--;
} else if (direction == 3) {
x--;
}
} else if (c == 'L') {
direction = (direction + 3) % 4; // 逆时针旋转90度,加3再取余
} else if (c == 'R') {
direction = (direction + 1) % 4; // 顺时针旋转90度,加1再取余
}
}
return (x == 0 && y == 0) || direction != 0;
}
}
这段代码涉及的知识点包括:
- 循环结构:通过循环遍历指令字符串中的每个字符。
- 条件判断:通过条件判断语句判断指令字符的类型,并执行相应的操作。
- 变量的增减操作:根据当前的方向,增减对应的坐标轴上的值。
- 变量的取余操作:通过取余运算实现循环递增或递减,实现方向的旋转。
- 逻辑运算:通过逻辑运算符判断机器人的运动结果是否返回出发位置。
1672. 最富有客户的资产总量
题目链接
题目描述
给你一个 m x n
的整数网格 accounts
,其中 accounts[i][j]
是第 i
位客户在第 j
家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。
客户的 资产总量 就是他们在各家银行托管的资产数量之和。最富有客户就是 资产总量 最大的客户。
示例 1:
输入:accounts = [[1,2,3],[3,2,1]]
输出:6
解释:
第 1 位客户的资产总量 = 1 + 2 + 3 = 6
第 2 位客户的资产总量 = 3 + 2 + 1 = 6
两位客户都是最富有的,资产总量都是 6 ,所以返回 6 。
示例 2:
输入:accounts = [[1,5],[7,3],[3,5]]
输出:10
解释:
第 1 位客户的资产总量 = 6 第 2 位客户的资产总量 = 10 第 3 位客户的资产总量 = 8 第 2 位客户是最富有的,资产总量是 10
示例 3:
输入:accounts = [[2,8,7],[7,1,3],[1,9,5]]
输出:17
提示:
m == accounts.length
n == accounts[i].length
1 <= m, n <= 50
1 <= accounts[i][j] <= 100
解答思路一【Java】
时间0 ms 击败 100%
内存40.5 MB 击败 88.62%
- 遍历二维数组accounts,对每个客户计算其资产总量,即对每个客户的资产数量求和
- 比较每个客户的资产总量,找到最大值。
- 返回最大值作为最富有客户的资产总量。
class Solution {
public int maximumWealth(int[][] accounts) {
int maxWealth = 0;
for (int[] customer : accounts) {
int wealth = 0;
for (int amount : customer) {
wealth += amount;
}
maxWealth = Math.max(maxWealth, wealth);
}
return maxWealth;
}
}
知识点:
1. 二维数组的遍历方式。
2. 数组的求和。
3. Math类的使用。
4. 变量赋值与比较。
1572. 矩阵对角线元素的和
题目链接
题目描述
给你一个正方形矩阵 mat
,请你返回矩阵对角线元素的和。
请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。
示例 1:
输入:mat = [[1,2,3],
[4,5,6],
[7,8,9]]
输出:25
解释:对角线的和为:1 + 5 + 9 + 3 + 7 = 25
请注意,元素 mat[1][1] = 5 只会被计算一次。
示例 2:
输入:mat = [[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]]
输出:8
示例 3:
输入:mat = [[5]]
输出:5
提示:
n == mat.length == mat[i].length
1 <= n <= 100
1 <= mat[i][j] <= 100
解答思路一【Java】
时间1 ms 击败 25.37%
内存42.9 MB 击败 13.79%
解题思路:
1. 遍历正方形矩阵mat的所有元素。
2. 判断当前元素是否在主对角线上(即行索引和列索引相等)或者副对角线上(即行索引和列索引之和为矩阵长度减一)。
3. 根据判断结果,将对应元素的值加到对角线和上。
4. 返回对角线和作为结果。
class Solution {
public int diagonalSum(int[][] mat) {
int sum = 0;
int n = mat.length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j || i + j == n - 1) {
sum += mat[i][j];
}
}
}
return sum;
}
}
知识点:
1. 二维数组的遍历方式。
2. 数组索引的使用。
3. 变量的赋值与比较。
工程日志
2023-07-05
- 简单的模拟题基本上只要跟着题目给的描述走就可以了,因为步骤简单,时空复杂度也难不到哪里去
- 编程基础 0 到 1的题目整体上偏简单,更考验答题者的基本功,因此基础好就显得尤其重要