跳到主要内容

HJ17. 坐标移动

题目描述

无限大二维网格上有小人,初始位置为原点 (0, 0)。接收一系列指令进行移动。

指令格式

  • 首字符为 A/S/D/W(左/下/右/上)
  • 末字符固定为 ;
  • 中间为 1-99 的数字(可含前导零)

非法指令(格式不正确、数字超出范围、方向字符非法等)应被忽略。

输入格式

一行字符串,长度 ≤ 10000,由大写字母、数字和分号组成。保证至少一个 ; 且末尾为 ;

输出格式

一行两个整数,横纵坐标用逗号间隔。

示例

示例 1

输入:

A10;S20;W10;D30;X;A1A;B10A11;;A10;

输出:

10,-10

说明:

  • A10:左移 10 → (-10, 0)
  • S20:下移 20 → (-10, -20)
  • W10:上移 10 → (-10, -10)
  • D30:右移 30 → (20, -10)
  • X:非法,忽略
  • A1A:非法,忽略
  • B10A11:非法,忽略
  • 空指令:忽略
  • A10:左移 10 → (10, -10)

示例 2

输入:

ABC;AKL;DA1;D001;W023;A100;S00;

输出:

0,0

说明:

  • A100:数字 100 超出 1-99 范围,非法
  • S00:数字 00 = 0,不在 1-99 范围内,非法

示例 3

输入:

A00;S01;W2;

输出:

0,1

说明:

  • A00:数字 0 非法
  • S01:数字 1 合法(含前导零),下移 1 → (0, -1)
  • W2:数字 2 合法,上移 2 → (0, 1)

解题思路

第一步:理解问题本质

本题是一个字符串解析 + 模拟题。需要将输入字符串按 ; 分割成多条指令,逐一验证合法性,合法指令则更新坐标。

第二步:分析指令合法性

一条合法指令必须同时满足:

  1. 非空
  2. 首字符是 A/S/D/W 之一
  3. 后续部分是 1-2 位数字
  4. 数字值在 1-99 范围内(含前导零时按实际值计算)

第三步:确定解析方案

使用正则表达式验证指令格式最为简洁:

import re
match = re.fullmatch(r'([ASDW])(\d{1,2})', cmd)
  • ([ASDW]):匹配方向字符
  • (\d{1,2}):匹配 1-2 位数字
  • fullmatch:要求整个字符串完全匹配

再用 int() 转换后验证范围 1 <= distance <= 99


完整代码实现

import sys
import re


def solve():
line = sys.stdin.readline().strip()

# 方向映射:A=左(x-), D=右(x+), W=上(y+), S=下(y-)
delta = {
'A': (-1, 0),
'D': (1, 0),
'W': (0, 1),
'S': (0, -1),
}

x, y = 0, 0
commands = line.split(';')

for cmd in commands:
if not cmd:
continue

match = re.fullmatch(r'([ASDW])(\d{1,2})', cmd)
if not match:
continue

direction = match.group(1)
distance = int(match.group(2))

if distance < 1 or distance > 99:
continue

dx, dy = delta[direction]
x += dx * distance
y += dy * distance

print(f"{x},{y}")


if __name__ == "__main__":
solve()

示例推演

以输入 A10;S20;W10;D30;X;A1A;B10A11;;A10; 为例:

指令方向数字合法性坐标变化当前坐标
A10A(左)10x -= 10(-10, 0)
S20S(下)20y -= 20(-10, -20)
W10W(上)10y += 10(-10, -10)
D30D(右)30x += 30(20, -10)
X--忽略(20, -10)
A1A--忽略(20, -10)
B10A11--忽略(20, -10)
--忽略(20, -10)
A10A(左)10x -= 10(10, -10)

结果10,-10


复杂度分析

指标复杂度说明
时间O(n)遍历所有字符一次,正则匹配为常数时间
空间O(n)split 产生的指令列表

n 为输入字符串长度


易错点总结

1. 范围判断遗漏

# 错误!只判断了格式,没判断数值范围
match = re.fullmatch(r'([ASDW])(\d{1,2})', cmd)
if match: # 但 \d{1,2} 可以匹配 "00" 和 "99",需要进一步验证

解决:提取数字后验证 1 <= distance <= 99

2. 方向映射错误

# 易混淆的方向映射
delta = {
'A': (-1, 0), # 左:x 减小
'D': (1, 0), # 右:x 增大
'W': (0, 1), # 上:y 增大(注意不是减小!)
'S': (0, -1), # 下:y 减小
}

记忆技巧W = Up( North,y+),S = Down(South,y-)。

3. 空指令处理

split(';') 会在末尾分号后产生空字符串,必须跳过:

if not cmd:
continue

4. 不用正则的手动解析

如果不想用正则,也可以手动解析,但代码会更长:

def is_valid(cmd):
if len(cmd) < 2:
return False
if cmd[0] not in 'ASDW':
return False
if not cmd[1:].isdigit():
return False
dist = int(cmd[1:])
return 1 <= dist <= 99

扩展思考

  • 如果支持负数距离?A-10,需要调整正则为 [ASDW]-?\d{1,2}
  • 如果允许多行输入? 外层加 for line in sys.stdin 循环。
  • 如果指令含小数?A1.5,需要浮点数处理和更复杂的正则。

相关题目

加载评论中...