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。

?		匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。