… a man was given directions to go from one point to another. The directions were “NORTH”, “SOUTH”, “WEST”, “EAST”. Clearly “NORTH” and “SOUTH” are opposite, “WEST” and “EAST” too.
Going to one direction and coming back the opposite direction right away is a needless effort. Since this is the wild west, with dreadful weather and not much water, it’s important to save yourself some energy, otherwise you might die of thirst!
The directions given to the man are, for example, the following (depending on the language):
["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"].
or
{ "NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST" };
or
[North, South, South, East, West, North, West]
You can immediately see that going “NORTH” and immediately “SOUTH” is not reasonable, better stay to the same place! So the task is to give to the man a simplified version of the plan. A better plan in this case is simply:
["WEST"]
or
{ "WEST" }
or
[West]
In [“NORTH”, “SOUTH”, “EAST”, “WEST”], the direction “NORTH” + “SOUTH” is going north and coming back right away.
The path becomes [“EAST”, “WEST”], now “EAST” and “WEST” annihilate each other, therefore, the final result is [] (nil in Clojure).
In [“NORTH”, “EAST”, “WEST”, “SOUTH”, “WEST”, “WEST”], “NORTH” and “SOUTH” are not directly opposite but they become directly opposite after the reduction of “EAST” and “WEST” so the whole path is reducible to [“WEST”, “WEST”].
Write a function dirReduc which will take an array of strings and returns an array of strings with the needless directions removed (W<->E or S<->N side by side).
Not all paths can be made simpler. The path [“NORTH”, “WEST”, “SOUTH”, “EAST”] is not reducible. “NORTH” and “WEST”, “WEST” and “SOUTH”, “SOUTH” and “EAST” are not directly opposite of each other and can’t become such. Hence the result path is itself : [“NORTH”, “WEST”, “SOUTH”, “EAST”]. if you want to translate, please ask before translating.
# Directions-Reduction.jl
using Test
# 有对应关系时,经常可以用 Dict 化简代码
const opposite = Dict(
"NORTH" => "SOUTH",
"EAST" => "WEST",
"SOUTH" => "NORTH",
"WEST" => "EAST"
)
#> Dict{String, String} with 4 entries:
#> "NORTH" => "SOUTH"
#> "EAST" => "WEST"
#> "SOUTH" => "NORTH"
#> "WEST" => "EAST"
"""
简化无效路径
"""
#> "简化无效路径\n"
function dir_reduc(arr::Vector{String})::Vector{String}
= []
stack
for step ∈ arr
if isempty(stack)
push!(stack, step) # 只要栈空了,就填新元素
else
== stack[end] ? pop!(stack) : push!(stack, step)
opposite[step] end
end
stackend
#> dir_reduc (generic function with 1 method)
@test dir_reduc(["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]) == ["WEST"]
#> Test Passed
#> Expression: dir_reduc(["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]) == ["WEST"]
#> Evaluated: ["WEST"] == ["WEST"]
library(tidyverse)
library(magrittr)
<- function(arr) {
dirReduc # 用 named vector 起到其他语言中 Dict/Map 的作用
<- c("NORTH", "SOUTH", "EAST", "WEST") %>%
opposite_dir set_names(c("SOUTH", "NORTH", "WEST", "EAST"))
<- character(0)
stack
for (step in arr) {
<- length(stack)
n if (n > 0 && opposite_dir[step] == stack[n]) {
<- stack[-n]
stack else {
} + 1] <- step
stack[n
}
}
stack
}
library(testthat)
<- function(ls, expected) {
testing <- dirReduc(ls)
actual expect_equal(actual, expected)
}test_that("tests", {
<- c("NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST")
a testing(a, c("WEST"))
<- c("NORTH", "WEST", "SOUTH", "EAST")
a testing(a, c("NORTH", "WEST", "SOUTH", "EAST"))
<- c("NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "NORTH")
a testing(a, c("NORTH"))
})
#> Test passed 🎉
function dirReduc(arr) {
const opposite_dir = new Map([
"NORTH", "SOUTH"], ["SOUTH", "NORTH"],
["EAST", "WEST"], ["WEST", "EAST"]]);
[
const stack = [];
for (step of arr) {
let n = stack.length;
if (n !== 0 && opposite_dir.get(step) === stack[n - 1]) {
.pop();
stackelse {
} .push(step);
stack
}
}
return stack;
}
console.log(dirReduc(["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]));
#> [ 'WEST' ]