leetcode调试指南
leetcode 调试
方法2
代码拷贝到本地,用ide/gdb调试。
比如使用 vim + floaterm + cgdb,效果见后图
对于此法,提供一个 header-only 的头文件 📜《lc.h》,只需要引用此头文件,然后将Class Solution复制到本地,加上main函数即可运行
功能简介
- 常用头文件(类似<bits/stdc++.h>,但是win上没有)以及
using namespace std;
- leetcode的链表和二叉树的定义,以及快速构建函数
- 随机数库封装,可以直接获取随机vector、字符串等
- Logger,可以打印包括容器、嵌套容器、自定义类型在内的各种类型
- Assert, 一些断言。是的,这跟leetcode无关,可以在你编写自己的小算法的时候提供一些测试套件。效果如图:
- benchmark,简单的性能测试(测试运行n次用时、平均每次用时)
- 其他的,大杂烩。(比如对ppm位图的封装,你可以由此实现一个对可视化的排序算法...)
效果图
另外,推荐使用 vim + floaterm + cgdb 的方式,配合此头文件对leetcode代码进行调试,喜欢的点是比较轻量,随时随地能调一下子。效果如下
方法 1
在leetcode代码头上定义测试宏,使用print大法来调试。
这里我把代码用vscode的join line合并成一行了,不然有些喧宾夺主。记得提交的时候把DEBUG宏关闭就好。格式化后的代码见后文
#define DEBUG 1
#if DEBUG
#include <iostream>
#include <numeric>
#include <string>
#include <type_traits>
template <typename T> struct ListType { template <typename Ptr> static auto test(Ptr ptr) -> decltype(ptr->val, ptr->next, std::true_type{}); template <typename Ptr> static std::false_type test(...); static constexpr bool value = decltype(test<T>(nullptr))::value; }; template <typename T, typename = void> struct Container : std::false_type {}; template <typename T> struct Container<T, std::void_t<typename T::value_type>> : std::true_type {}; const std::string sep = ","; template <typename T> std::string skToString(T c) { if constexpr (ListType<T>::value) { std::string ret = "["; auto p = c; while (p != nullptr && p->next != nullptr) { ret = ret + skToString(p->val) + sep; p = p->next; } if (p != nullptr) { ret += skToString(p->val); } ret += "]"; return ret; } else if constexpr (Container<T>::value && !std::is_convertible_v<T, std::string>) { if (c.empty()) { return "[]"; } return "[" + std::accumulate(std::next(c.begin()), c.end(), skToString(*(c.begin())), [](std::string a, auto b) { return a + sep + skToString(b); }) + "]"; } else if constexpr (std::is_arithmetic_v<T>) { return std::to_string(c); } else if constexpr (std::is_convertible_v<T, std::string>) { return c; } else { return "{" + skToString(c.first) + sep + skToString(c.second) + "}"; } } template <typename... Args> std::string skFmt(std::string_view format, Args... args) { std::string fmtStr(format); return ((fmtStr.replace(fmtStr.find("{}"), 2, skToString(args))), ...); } template <typename... PairTypes> void dumpWithName(PairTypes... args) { ((std::cout << "【" << skToString(std::get<0>(args)) << "】:" << skToString(std::get<1>(args)) << " "), ...); }
#define TO_PAIR(x) std::make_pair(#x, x)
#define DUMP1(x) dumpWithName(TO_PAIR(x))
#define DUMP2(x, ...) dumpWithName(TO_PAIR(x)), DUMP1(__VA_ARGS__)
#define DUMP3(x, ...) dumpWithName(TO_PAIR(x)), DUMP2(__VA_ARGS__)
#define DUMP4(x, ...) dumpWithName(TO_PAIR(x)), DUMP3(__VA_ARGS__)
#define DUMP5(x, ...) dumpWithName(TO_PAIR(x)), DUMP4(__VA_ARGS__)
#define DUMP6(x, ...) dumpWithName(TO_PAIR(x)), DUMP5(__VA_ARGS__)
#define DUMP7(x, ...) dumpWithName(TO_PAIR(x)), DUMP6(__VA_ARGS__)
#define DUMP8(x, ...) dumpWithName(TO_PAIR(x)), DUMP7(__VA_ARGS__)
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
#define OUTV(...) std::cout << skFmt(__VA_ARGS__) << std::endl;
#define DUMP(...) do{GET_MACRO(__VA_ARGS__, DUMP8, DUMP7, DUMP6, DUMP5, DUMP4, DUMP3,DUMP2, DUMP1)(__VA_ARGS__);std::cout << "\n";}while(0)
#else
#define OUTV(...)
#define DUMP(...)
#endif
功能简介
- LOG(X) 输出 [#x] X \n 的效果
- LOGF(...) 即format,可以实现
LOGF("This's my var: list:{}, map:{}, vector:{}, string:{}, int:{} ...", l, mp, vc, str, i)
等类型的输出 - 对leetcode涉及到类型(无非就是容器,链表,和基本类型)进行toString()转换。(正因为有此假设,所以实现时重点在于简洁而不在鲁棒,不支持类型可能会segment fault)
效果图
进行了一波小更新,DUMP可以将传入的变量(最多8个)按照【name】: value的格式打印出来,省去了写format字串的麻烦,更方便一些。
附:
格式化后的代码,供诸君参考
#define DEBUG 1
#if DEBUG
#include <iostream>
#include <numeric>
#include <string>
#include <type_traits>
template <typename T>
struct ListType {
template <typename Ptr>
static auto test(Ptr ptr) -> decltype(ptr->val, ptr->next,
std::true_type{});
template <typename Ptr>
static std::false_type test(...);
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
template <typename T, typename = void>
struct Container : std::false_type {};
template <typename T>
struct Container<T, std::void_t<typename T::value_type>> : std::true_type {};
const std::string sep = ",";
template <typename T>
std::string skToString(T c) {
if constexpr (ListType<T>::value) {
std::string ret = "[";
auto p = c;
while (p != nullptr && p->next != nullptr) {
ret = ret + skToString(p->val) + sep;
p = p->next;
}
if (p != nullptr) {
ret += skToString(p->val);
}
ret += "]";
return ret;
} else if constexpr (Container<T>::value &&
!std::is_convertible_v<T, std::string>) {
if (c.empty()) {
return "[]";
}
return "[" +
std::accumulate(std::next(c.begin()), c.end(),
skToString(*(c.begin())),
[](std::string a, auto b) {
return a + sep + skToString(b);
}) +
"]";
} else if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(c);
} else if constexpr (std::is_convertible_v<T, std::string>) {
return c;
} else {
return "{" + skToString(c.first) + sep + skToString(c.second) + "}";
}
}
template <typename... Args>
std::string skFmt(std::string_view format, Args... args) {
std::string fmtStr(format);
return ((fmtStr.replace(fmtStr.find("{}"), 2, skToString(args))), ...);
}
template <typename... PairTypes>
void dumpWithName(PairTypes... args) {
((std::cout << "【" << skToString(std::get<0>(args))
<< "】:" << skToString(std::get<1>(args)) << " "),
...);
}
#define TO_PAIR(x) std::make_pair(#x, x)
#define DUMP1(x) dumpWithName(TO_PAIR(x))
#define DUMP2(x, ...) dumpWithName(TO_PAIR(x)), DUMP1(__VA_ARGS__)
#define DUMP3(x, ...) dumpWithName(TO_PAIR(x)), DUMP2(__VA_ARGS__)
#define DUMP4(x, ...) dumpWithName(TO_PAIR(x)), DUMP3(__VA_ARGS__)
#define DUMP5(x, ...) dumpWithName(TO_PAIR(x)), DUMP4(__VA_ARGS__)
#define DUMP6(x, ...) dumpWithName(TO_PAIR(x)), DUMP5(__VA_ARGS__)
#define DUMP7(x, ...) dumpWithName(TO_PAIR(x)), DUMP6(__VA_ARGS__)
#define DUMP8(x, ...) dumpWithName(TO_PAIR(x)), DUMP7(__VA_ARGS__)
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
#define OUTV(...) std::cout << skFmt(__VA_ARGS__) << std::endl;
#define DUMP(...) \
do { \
GET_MACRO(__VA_ARGS__, DUMP8, DUMP7, DUMP6, DUMP5, DUMP4, DUMP3, \
DUMP2, DUMP1) \
(__VA_ARGS__); \
std::cout << "\n"; \
} while (0)
#else
#define OUTV(...)
#define DUMP(...)
#endif