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位图的封装,你可以由此实现一个对可视化的排序算法…)
    更新日志:
  • (20240817) 新增跳表、图以及并查集;修复print的错误

效果图

image

另外,推荐使用 vim + floaterm + cgdb 的方式,配合此头文件对leetcode代码进行调试,喜欢的点是比较轻量,随时随地能调一下子。效果如下
image

方法 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 {}; template <typename T, typename = void> struct QueueLike : std::false_type {}; template <typename T> struct QueueLike<T, decltype((void)std::declval<T>().pop(), (void)std::declval<T>().front())> : std::true_type {}; template <typename T, typename = void> struct StackLike : std::false_type {}; template <typename T> struct StackLike<T, decltype((void)std::declval<T>().pop(), (void)std::declval<T>().top())> : 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 (StackLike<T>::value) { T tmp = c; std::string ret; while (!tmp.empty()) { ret += skToString(tmp.top()); ret += sep; tmp.pop(); } return ret.substr(0, ret.length() - sep.length()); } else if constexpr (QueueLike<T>::value) { T tmp = c; std::string ret; while (!tmp.empty()) { ret += skToString(tmp.front()); ret += sep; tmp.pop(); } return ret.substr(0, ret.length() - sep.length()); } 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 if constexpr (std::is_pointer_v<T>) { return "➶"; } 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

功能简介

  • DUMP(…) 将传入的变量按照 [变量名]: 变量值 的格式依次打印出来。可以接受0-8个参数(应该够用了吧,不够仿照例子扩充)
  • OUTV(…) 类似log4j那种打日志的方式,可以实现 OUTV("This's my var: list:{}, map:{}, vector:{}, string:{}, int:{} ...", l, mp, vc, str, i)等类型的输出
  • 对leetcode涉及到类型(无非就是容器,链表,和基本类型)进行toString()转换。(正因为有此假设,所以实现时重点在于简洁而不在鲁棒,不支持类型可能会segment fault)

效果图

DUMP可以将传入的变量(最多8个)按照【name】: value的格式打印出来,省去了写format字串的麻烦,更方便一些。
image
在这里插入图片描述
(LOGF就是现在的宏OUTV,下面的图是更新前的老名字。这里只是为了展示可以支持哪些类型)
在这里插入图片描述

附:

格式化后的代码,供诸君参考

#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 {};
template <typename T, typename = void>
struct QueueLike : std::false_type {};
template <typename T>
struct QueueLike<T, decltype((void)std::declval<T>().pop(),
                             (void)std::declval<T>().front())>
    : std::true_type {};
template <typename T, typename = void>
struct StackLike : std::false_type {};
template <typename T>
struct StackLike<T, decltype((void)std::declval<T>().pop(),
                             (void)std::declval<T>().top())> : 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 (StackLike<T>::value) {
        T tmp = c;
        std::string ret;
        while (!tmp.empty()) {
            ret += skToString(tmp.top());
            ret += sep;
            tmp.pop();
        }
        return ret.substr(0, ret.length() - sep.length());
    } else if constexpr (QueueLike<T>::value) {
        T tmp = c;
        std::string ret;
        while (!tmp.empty()) {
            ret += skToString(tmp.front());
            ret += sep;
            tmp.pop();
        }
        return ret.substr(0, ret.length() - sep.length());
    } 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 if constexpr (std::is_pointer_v<T>) {
        return "➶";
    } 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值