LeetCode C++ 本地调试
LeetCode中使用在线编辑器可以很方便的进行答题,但对我们这种菜鸟还是喜欢本地调试一遍复制粘贴。
本文Github地址:Pokerpoke/LeetCode
进行本地调试遇到以下问题:
- VS中只能存在一个
main()
函数 - 在
main()
函数中执行算法跟网页上缩进不同(强迫症) - 树、链表等数据结构构造比较麻烦
- 测试结果
- github
工具:
- Windows(需要WSL) 或者 Ubuntu
- VS code
- CMake
问题2
问题2比较简单,先解决问题2,构造Solution
类进行调试。
class Solution
{
int maxProfit(vector<int> &prices)
{
// 解答过程
return max;
}
};
int main()
{
Solution s;
vector<int> prices{7, 1, 5, 3, 6, 4}
ans = s.maxProfit();
cout << ans;
}
问题1
问题1的原因是因为VS中一个project只能有一个main()
函数,可以通过在解决方案下建立多个project的方式来解决,但这样不够方便,需要的只是新建文件,敲代码,测试。所以我采用了Windows(WSL) / Ubuntu + CMake的方式解决这个问题。
目录结构
├── CMakeLists.txt # 顶层CMake配置文件
├── README.md # 项目说明
├── build # 构建文件夹
├── doc # 解释说明,用以整理思路
├── include # 相关头文件
│ ├── CMakeLists.txt # CMake配置文件
│ ├── bstree.cc
│ ├── bstree.h # 二叉树头文件
│ ├── headers.h # 包含头文件
│ ├── listnode.cc
│ └── listnode.h # 链表头文件
├── leetcode # 编译脚本
└── src # 解答目录
├── 0.template.cc # 解答模板,每次复制改名即可
├── CMakeLists.txt # 解答CMake配置文件
├── climbStairs.cc
└── ...
顶层CMake配置
project(LeetCode)
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_subdirectory(include)
add_subdirectory(src)
include/
下CMake配置
aux_source_directory(. LEETCODE)
add_library(leetcode ${LEETCODE})
src/
目录下CMake配置,编译每个源文件,不需要每次新建以后添加项目
aux_source_directory(. EXECUTABLE)
foreach(T_FILE_NAME ${EXECUTABLE})
get_filename_component(EXECUTABLE_NAME ${T_FILE_NAME} NAME_WE)
# message(${EXECUTABLE_NAME})
add_executable(${EXECUTABLE_NAME} ${T_FILE_NAME})
target_link_libraries(
${EXECUTABLE_NAME}
leetcode
)
endforeach()
环境基本配置完成了,在src
目录下答题,然后调试即可。每次都编译全部解答会很慢,指定target又需要敲很长命令,将这些命令写成脚本即可。
leetcode
脚本
set -e
# 获取脚本所在目录
CMAKE_SOURCE_DIR=$(dirname $(readlink -f $0))
# 获取CMake源目录
CMAKE_SOURCE_DIR=$(pwd)
cd ${CMAKE_SOURCE_DIR}
if [ ! -d ./build ]
then
mkdir build
fi
# 指定解答
cd build && cmake .. && make $1 -j8 && cd src
# 运行
./$1
添加可执行权限
sudo chmod +x leetcode
用文件名区分leetcode题目,执行以下命令即可进行本地调试
./leetcode maxProfit
问题3
自行构建链表、二叉树的相关数据结构(待完善),这里没有采用写在同一个头文件的方式,如果将所有定义、实现写在同一个头文件需要在CMake中将library声明成接口的形式。
listnode.h
#ifndef _LISTNODE_H_
#define _LISTNODE_H_
#include <iostream>
#include <vector>
struct ListNode
{
int val;
ListNode *next;
ListNode(int x = 0, ListNode *p = nullptr) : val(x), next(nullptr){};
};
// 调试用,打印整个链表
void print_list(ListNode *head)
{
while (head != nullptr)
{
std::cout << head->val << " ";
head = head->next;
}
std::cout << std::endl;
}
class List
{
public:
ListNode *head, *tail;
int pos;
List()
{
head = nullptr;
tail = nullptr;
};
// 用vector进行初始化
List(const std::vector<int> &in)
{
head = nullptr;
tail = nullptr;
for (auto it : in)
this->insert(it);
};
~List(){};
// 插入节点
void insert(int x)
{
if (head == nullptr)
{
head = tail = new ListNode(x);
head->next = nullptr;
tail->next = nullptr;
}
else
{
ListNode *p = new ListNode(x);
tail->next = p;
tail = p;
tail->next = nullptr;
}
};
void print()
{
print_list(head);
}
};
#endif //!_LISTNODE_H_
bstree.h
#ifndef _BSTREE_H_
#define _BSTREE_H_
#include <vector>
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Tree
{
public:
Tree();
Tree(std::vector<int> &in);
~Tree();
TreeNode *root;
static void print_tree(TreeNode *root);
TreeNode *insert_ordered(const std::vector<int> &in, int l, int r);
void insert(const int &x);
void insert(const int &x, TreeNode *&parent);
bool is_empty();
void print();
void push(std::vector<int> &in);
};
#endif //!_BSTREE_H_
bstree.cc
#include "bstree.h"
#include <iostream>
#include <algorithm>
Tree::Tree()
{
root = nullptr;
}
Tree::Tree(std::vector<int> &in)
{
root = nullptr;
sort(in.begin(), in.end());
for (auto it : in)
std::cout << it << " ";
std::cout << std::endl;
root = insert_ordered(in, 0, in.size() - 1);
}
Tree::~Tree()
{
}
void Tree::print_tree(TreeNode *root)
{
if (root != nullptr)
{
print_tree(root->left);
std::cout << root->val << " ";
print_tree(root->right);
}
}
bool Tree::is_empty()
{
return (root == nullptr);
}
TreeNode *Tree::insert_ordered(const std::vector<int> &in, int l, int r)
{
if (l > r)
return nullptr;
int mid = (l + r + 1) / 2;
TreeNode *new_root = new TreeNode(in[mid]);
new_root->left = insert_ordered(in, l, mid - 1);
new_root->right = insert_ordered(in, mid + 1, r);
return new_root;
}
void Tree::insert(const int &x)
{
insert(x, root);
}
void Tree::insert(const int &x, TreeNode *&parent)
{
if (parent == nullptr)
{
parent = new TreeNode(x);
return;
}
else
{
if (x > parent->val)
return insert(x, parent->right);
else if (x < parent->val)
return insert(x, parent->left);
else
return;
}
}
void Tree::print()
{
print_tree(root);
std::cout << std::endl;
}
void Tree::push(std::vector<int> &in)
{
for (auto i : in)
{
this->insert(i);
}
}
headers.h,该文件主要用来include其他头文件以使解答可读性更高
#ifndef _HEADERS_H_
#define _HEADERS_H_
// c++ stl libraries
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <stack>
#include <queue>
// c libraries
#include <cctype>
#include <climits>
#include <cmath>
#include <cstring>
// listnode
#include "listnode.h"
#include "bstree.h"
using namespace std;
#endif // !_HEADERS_H_
问题4
使用googletest作为测试框架,gtest安装方式见项目主页
修改顶层CMakeLists.txt
...
enable_testing()
find_package(Threads REQUIRED)
find_package(GTest REQUIRED)
...
include_directories(${GTEST_INCLUDE_DIR})
...
修改headers.h
...
#include <gtest/gtest.h>
...
修改src/CMakeLists.txt
target_link_libraries(
${EXECUTABLE_NAME}
leetcode
gtest
${CMAKE_THREAD_LIBS_INIT}
)
测试例程
#include "headers.h"
class Solution
{
public:
int climbStairs(int n)
{
int ways[] = {1, 1};
for (int i = 1; i < n; i++)
{
int temp = ways[1];
ways[1] += ways[0];
ways[0] = temp;
}
return ways[1];
}
};
TEST(climbStairs, climbStairs)
{
Solution s;
EXPECT_EQ(s.climbStairs(2), 2);
EXPECT_EQ(s.climbStairs(3), 3);
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
执行./leetcode climbStairs
即可看到以下输出,表明结果正确
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from climbStairs
[ RUN ] climbStairs.climbStairs
[ OK ] climbStairs.climbStairs (1 ms)
[----------] 1 test from climbStairs (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[ PASSED ] 1 test.
问题5
使用git管理项目即可
.gitignore文件
.vscode # vscode配置目录
build # 构建目录
网友评论