Re: [闲聊] 每日LeetCode

楼主: fxfxxxfxx (爱丽丝)   2022-10-21 10:46:22
※ 引述《Rushia (みけねこ的鼻屎)》之铭言:
: 12. Integer to Roman
: 给予一个1到3999之间的整数,将这个整数转成罗马符号表示法
今天(昨天?)的题目感觉比较像是在考你怎么写得优雅
可惜我就专门写面条code
我一开始的作法是建四个阵列:
string _1000[] = {"", "M", "MM", "MMM"};
string _100[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
string _10[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
string _1[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
直接把各个位数对应到的字串行举出来,所以例如输入是 3412,就会是
_1000[3] + _100[4] + _10[1] + _1[2]
这个方法仔细想想好像也没有不好,只怕会不小心打错字而已
就程式的逻辑上来讲还蛮清晰的
不过就这样结束好像蛮无聊的
然后我想到,既然他输入只在 [1, 3999] 之间
不知到能不能在编译时期就建出一个大小是 4000 的阵列直接存答案
这样应该执行速度就会超快的
第一种作法当然就是在本地算出 4000 个答案之后直接在程式码中写下像是
const char *ans[4000] = {
"", "I", "II", /* .... */
"MMMCMXCIX"
};
类似这种的。不过这样程式码会非常长,而且有点丑。
后来我想到可以用 constexpr 函式在编译时期建出我们要的阵列
但因为我对 C++ 不是很熟,所以花了不少时间
查了一下发现好像都是要把阵列包起来,不管是在自定义的 struct
或是 std::array 之类的东西。接着再用 constexpr 的 constructor / lambda
来初始化好我们的阵列,像是:
static constexpr auto A = [] {
std::array<int, 10> ret = {};
for (int i = 0; i < 10; i++)
ret[i] = i * i;
return ret;
}();
像这样就可以建出一个 [0, 1, 4, ..., 81] 的 std::array
不过要确定是 c++17 以后,才能在 constexpr 里用 lambda
但有一个问题就是题目要回传 string ,但在 constexpr 里不能用 string
(c++20 好像可以了,但 LeetCode 还在17),所以我改用 std::array<char, 21>
然后就照之前的方法建出一个
constexpr std::array<std::array<char, 21>, 4000> ans = /* ... */
之后要拿到答案就只要
string intToRoman(int num) {
return string(ans[num].data());
}
直接去 ans 里拿就好了。
丢去 godbolt.org 确认一下 -O2 下生出来长怎样
可以看到生出了超大一块的 Solution::ans
之后的确就直接去 ans 里拿一个 char 指标
虽然不知道转成 string 快不快,不过我想不到更快的做法了
程式码:
https://leetcode.com/submissions/detail/826324831/
时间: 0 ms (beats 100%)
空间: 5.8MB (beats 99.31%)
其实空间能赢 99% 蛮奇怪的吧
我多造了一个至少 4000 * 21 ~= 80KB 的阵列
不知道他是怎么算的,很难想像其他人会用的比这个多
作者: Jaka (Jaka)   2022-10-21 10:51:00
大师
作者: JerryChungYC (JerryChung)   2022-10-21 10:52:00
大师
作者: pandix (面包屌)   2022-10-21 10:56:00
大师
作者: amos0716 (肥包)   2022-10-21 11:58:00
大师
作者: uglybaby (lalala123)   2022-10-21 12:10:00
大师

Links booklink

Contact Us: admin [ a t ] ucptt.com