我正在尝试解决这个编码挑战:
绘图机器人位于坐标平面的 (0,0) 点,字符串
描述了机器人将采取的路径。moves
字符串的每个字符都描述机器人所做的单个动作。此外,机器人还会做出动作 与它们在字符串中出现的顺序完全相同,从位置 (0,0) 开始。假设机器人已经 从字符串中进行了一些移动,并且当前位于点 (x,y),如果字符串的下一个字符是:
- “^”:机器人将移动到(x,y+1),
- “v”:机器人将移动到(x,y-1),
- ”<": the robot will move to (x-1,y),
- ">":机器人将移动到(x+1,y)。
机器人每次移动时,都会在当前位置和移动到的点之间画一条线。确保字符串
中提供的指令永远不会导致机器人多次访问同一点,但点 (0,0) 除外,机器人可能会访问该点两次: 机器人路径的起点和终点。任务是确定机器人完成字符串中提供的所有动作后,它绘制的所有线条是否形成一个矩形。moves
编写一个函数:
:给定字符串function solution(moves)
,如果机器人的路径将形成矩形,则返回 true,否则返回 false。moves
- 鉴于
,该函数应返回 true。moves="^^^<<<<vvv>>>>"
- 鉴于
,该函数应返回 true。moves="<vvv>>^^^<"
假设:
- 字符串
的长度在[1...100]范围内。moves
- 字符串
仅由以下字符组成:“^”、“v”、“<" and/or ">”。moves
- 机器人不会两次访问同一个点,除了点 (0,0),该点可能会在机器人路径的起点和终点被访问。
这是我写的代码,它仅用于检查形状是正方形还是矩形, 但它无法判断形状是否有更多匝数,同时高度和宽度仍然不同, 例如,
moves="^^^^^^<<<<vv>>v<<vvv>>>>";
不会形成一个矩形,但因为它有
两边高度相同,算作矩形。
const moves = "^^^<<<<vvv>>>>";
console.log(solution(moves));
function solution(moves) {
let xPos = 0,
yPos = 0;
let xMin = 0,
xMax = 0,
yMin = 0,
yMax = 0;
let visited = new Set();
visited.add("0,0");
for (let i = 0; i < moves.length; i++) {
let movement = moves[i];
if (movement === "<") {
xPos--;
xMin = Math.min(xMin, xPos);
} else if (movement === ">") {
xPos++;
xMax = Math.max(xMax, xPos);
} else if (movement === "^") {
yPos++;
yMax = Math.max(yMax, yPos);
} else if (movement === "v") {
yPos--;
yMin = Math.min(yMin, yPos);
}
let currPos = `${xPos},${yPos}`;
visited.add(currPos);
}
if (xPos !== 0 || yPos !== 0) return false;
const width = xMax - xMin + 1;
const height = yMax - yMin + 1;
console.log(visited);
if (width > height || height > width) return true;
else return false;
}
我想知道我需要什么操作才能确保只有在形成矩形时才返回true。
检查这个:
function solution(moves) {
let xPos = 0,
yPos = 0;
let xMin = 0,
xMax = 0,
yMin = 0,
yMax = 0;
let visited = new Set();
visited.add("0,0");
let leftTurns = 0;
let rightTurns = 0;
for (let i = 0; i < moves.length; i++) {
let movement = moves[i];
if (movement === "<") {
xPos--;
xMin = Math.min(xMin, xPos);
leftTurns++;
} else if (movement === ">") {
xPos++;
xMax = Math.max(xMax, xPos);
rightTurns++;
} else if (movement === "^") {
yPos++;
yMax = Math.max(yMax, yPos);
} else if (movement === "v") {
yPos--;
yMin = Math.min(yMin, yPos);
}
let currPos = `${xPos},${yPos}`;
visited.add(currPos);
}
if (xPos !== 0 || yPos !== 0) return false;
const width = xMax - xMin + 1;
const height = yMax - yMin + 1;
if (width > height || height > width) return false;
if (visited.size !== (width + 1) * (height + 1)) return false;
if (leftTurns !== rightTurns) return false;
return true;
}
我在这里看到了一些东西。
我认为你的代码可能处理#1,也许你的验证处理#2。 对于#3,试试这个:
// 假设上面#1已经被确认了
const moves='^^^^^^<<<<vv>>v<<vvv>>>>';//"^^^<<<<vvv>>>>";
function testit() {
alert(solution(moves));
alert(checkTransitionCount(moves));
}
//function solution(moves){...this is your code...}
function checkTransitionCount(moves) {
let transitionCount = 0;
let nextChar = moves[0];
for (let idx = 1; idx < moves.length; idx++) {
if (nextChar != moves[idx]) {
transitionCount++;
nextChar = moves[idx];
}
}
if (transitionCount == 3)
return true;
if (transitionCount == 4)
if (moves[0] == moves[moves.length - 1])
return true;
return false;
}
空字符串对应于可以被视为零面积矩形的点。除此之外,输入定义一个矩形当且仅当:
为了避免担心回绕,请移动输入字符串,以便移动字符串的第一个 elt 是输入的第二个不同的 elt。
我将使用 e1、e2、e3 和 e4 来引用您在移位字符串中遇到的第一个、第二个、第三个和第四个不同元素。
然后用你移动的字符串:
为了有效,这一系列动作应该具有:
这是带有一些测试用例的实现:
const opposites = { "^": "v", ">": "<", "v": "^", "<": ">" };
function solution(moves) {
if (!moves) return true; // Or false. Whatever is expected for empty input string
let corners = 4;
const counters = { "^": 0, ">": 0, "v": 0, "<": 0 };
let prev = moves.at(-1);
for (let i = 0; i < moves.length; i++) {
let current = moves[i];
counters[current]++;
if (current !== prev) {
corners--;
if (corners < 0 || opposites[prev] === current) return false;
}
prev = current;
}
return corners === 0 && counters["^"] === counters["v"] && counters[">"] === counters["<"];
}
const tests = [
["^^^<<<<vvv>>>>", true],
["^^<<<<vvv>>>>^", true],
["^^^>>>>vvv<<<<", true],
["^^>>>>vvv<<<<^", true],
["^^^<<<<vv>>v>>", false], // Too many corners
["^^<<<<vvv>^>>>", false], // Too many corners
["^^>>vv<<^^>>vv<<", false], // Too many corners
["^^vvv>>>><<<<^", false], // Backtracking
["^^^>>>><<<<vvv", false], // Backtracking
["^^>>>>vvv<<^", false], // Not arriving at (0, 0)
["^^>>>>vvvv<<<<^", false], // Not arriving at (0, 0)
];
for (const [moves, expected] of tests) {
console.log(moves, "got", solution(moves), "expected", expected);
}
另一种使用正则表达式的解决方案:更优雅,但效率稍低:
function solution(moves) {
if (!moves) return true; // Or false. Whatever is expected for empty input string
if (/\^v|v^|<>|></.test(moves)) return false; // Backtracking moves detected
const sides = moves.match(/(.)\1*/g).map(({length}) => length);
if (sides.length === 5 && moves.at(-1) === moves[0]) sides[0] += sides.pop();
return sides.length === 4 && sides[0] === sides[2] && sides[1] === sides[3];
}
const tests = [
["^^^<<<<vvv>>>>", true],
["^^<<<<vvv>>>>^", true],
["^^^>>>>vvv<<<<", true],
["^^>>>>vvv<<<<^", true],
["^^^<<<<vv>>v>>", false], // Too many corners
["^^<<<<vvv>^>>>", false], // Too many corners
["^^>>vv<<^^>>vv<<", false], // Too many corners
["^^vvv>>>><<<<^", false], // Backtracking
["^^^>>>><<<<vvv", false], // Backtracking
["^^>>>>vvv<<^", false], // Not arriving at (0, 0)
["^^>>>>vvvv<<<<^", false], // Not arriving at (0, 0)
];
for (const [moves, expected] of tests) {
console.log("got", solution(moves), "expected", expected);
}