HJ17.坐标移动
解法一:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <string.h>
const int W[2] {0, 1};
const int S[2] {0, -1};
const int A[2] {-1, 0};
const int D[2] {1, 0};
const std::unordered_map<char, const int*> DIR {
{'W', W}, {'S', S}, {'A', A}, {'D', D}
};
std::pair<char, int> parser(const std::string& s) {
auto cmd = std::pair<char, int>('0', 0);
if (DIR.find(s[0]) == DIR.end()) {
return cmd;
}
for (int i = 1; i < s.length(); ++i) {
if (s[i] < '0' || s[i] > '9') {
return cmd;
}
}
cmd.first = s[0];
std::stringstream ss;
ss << s.substr(1);
ss >> cmd.second;
ss.clear();
return cmd;
}
int* coor(std::string s) {
int* co = new int[2]{0, 0};
for (char* p = strtok((char*)s.data(), ";"); p; p = strtok(NULL, ";" )) {
auto cmd = parser(p);
auto itor = DIR.find(cmd.first);
if (itor != DIR.end()) {
co[0] += itor->second[0] * cmd.second;
co[1] += itor->second[1] * cmd.second;
}
}
return co;
}
int main() {
std::string in;
while (getline(std::cin, in)) {
int* co = coor(in);
std::cout << co[0] << ',' << co[1] << std::endl;
delete(co);
}
return 0;
}
解法二:
#include <string>
#include <sstream>
#include <iostream>
#include <unordered_map>
#include <regex>
#include <string.h>
bool valid(const std::string& s) {
// [ADWS]\d{1}\d?
std::regex res("[ADWS]\\d{1}\\d?");
return std::regex_match(s, res);
}
int* coor(std::string s) {
int* co = new int[2]{0, 0};
std::unordered_map<char, int> dir;
std::stringstream ss;
std::string token;
int cnt = 0;
for (char* p = strtok((char*)s.data(), ";"); p; p = strtok(NULL, ";" )) {
token = p;
if (valid(token)) {
ss << token.substr(1);
ss >> cnt;
ss.clear();
dir[token[0]] += cnt;
}
}
co[0] = co[0] - dir['A'] + dir['D'];
co[1] = co[1] - dir['S'] + dir['W'];
return co;
}
int main() {
std::string in;
while (getline(std::cin, in)) {
int* co = coor(in);
std::cout << co[0] << ',' << co[1] << std::endl;
delete(co);
}
return 0;
}
解题思路:
难点1:题目的思路不难,很容易可以想到,主要纠结于使用什么工具来实现;vecotr、int[]、pair,可选择的比较多,最后决定用int[];
难点2:好久没写c了,直接在函数里开了数组,忘了得new;
难点3:split的实现,网上转了一圈,最后决定用strtok,get到了新知识;
难点4:命令的解析,熟练正则更好,代码看起来干净很多,无奈之前都是用的时候查手册,没有记下来;
难点5:c++的string转int,找了一圈,还是stream实现起来最靠谱;
难点6:字典的使用,让代码更干净,可维护性更强。看了一圈答案,很多 if else 或者 switch 做的;
知识点:
知识点1:数组做map的value,直接取地址就完事;
const int W[2] {0, 1};
const int S[2] {0, -1};
const int A[2] {-1, 0};
const int D[2] {1, 0};
const std::unordered_map<char, const int*> DIR {
{'W', W}, {'S', S}, {'A', A}, {'D', D}
};
知识点2:string转int,stringstream用完之后一定要记得clear;
std::string s = "134627";
int num = 0;
std::stringstream ss;
ss << s;
ss >> num;
ss.clear();
知识点3:split的实现;参考Split a string;
/* This is C code */
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "one, two,, four , five,"; /* mutable! */
const char* p;
for (p = strtok( s, "," ); p; p = strtok( NULL, "," ))
{
printf( "\"%s\"\n", p );
}
return 0;
}
注意:strtok的第一个参数类型是char * 而不是const char *,参考C++ 的 string 为什么不提供 split 函数? - 知乎用户的回答 - 知乎。
char *token = strtok(str.data(), " "); // non-const data() needs c++17
知识点4:c++正则表达式的应用,最简单的判断能否进行匹配;
#include <regex>
#include <string>
bool valid(const std::string& s) {
// [ADWS]\d{1}\d?
std::regex res("[ADWS]\\d{1}\\d?");
return std::regex_match(s, res);
}
知识点5:正则表达式的语法规则,参考正则表达式;
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
\d 匹配一个数字字符。等价于 [0-9]。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。