关于刷题环境的看法与选择

ChlorineC Lv4

今天在准备机试,拿起很久没刷的算法题 (上次刷题还是大一刷洛谷) ,除了考虑刷哪一套题单,要考虑的就是使用什么语言、什么环境来刷。

2023年5月更新:

刷了一个多月题后我的感受发生了变化,其实用什么语言不重要,相反的,如果你想要快速上手一门语言的基本特性,你就用它来刷题就对了。

刷题环境的选择标准

由于线上环境与本地环境有较大区别,而面向机试的刷题练习应该尽量做到与线上环境保持一致 ,因此我提出了对本地环境的以下几点基本要求:

  • 尽量使用 文本编辑器+单文件(脚本) 的方式而 非IDE+项目 的模式,方便管理多道题目
  • 编译运行过程尽量简单,且支持单步调试
  • 语法简单易上手 (刷题就不要想borrow的事情了) ,有完善的轮子 (谁也不想用C手搓堆吧)
  • 语言运行速度不拖后腿,这点其实不太重要,因为大多只看复杂度而不看绝对时间
  • 环境本身不应提供过多辅助功能(如Copilot),有些在线环境甚至不提供代码提示

基于上述的基本标准,我们再进一步地细化一些标准,优先级从上到下递减

  1. 完善的轮子,如容器库、基础数据类操作方法等
  2. 单文件结构体系(或脚本语言),不依赖项目(刷题几乎不存在项目复用的需求,除非极少数题目共享数据结构需要多文件模块化)
  3. 函数为一等公民,而不必用类去包裹
  4. 简便的调试,清晰的异常处理信息
  5. 性能够用,贴近底层,有更多优化空间(不打榜的话其实没有需求)

刷题环境的推荐

根据我们上面提出的规则,根据满足的规则多少,我们将按优先级先后排列主流刷题环境,并依次叙述如何快速配置(均搭配Windows下的VS Code编辑器):

  1. C++ 11: 满足1、2、3、5(4部分符合)
  2. JS: 满足1、2、3、4(不包含TS,TS配置太麻烦了,不能开箱即用)
  3. Python:满足1、2、3、4(其实个人感觉Python比JS更好,但由于我讨厌Python的缩进所以放到后面)
  4. C# Script:满足1、2、3(部分4,且性能有些一言难尽)
  5. Java:满足1、4(如果不是后端需求大我真的都不想推荐)

VS Code 中的相关插件就不再推荐,自己搜索官方插件安装即可。

C++ 11

先抛开C++贴近底层的性能优势不谈(单纯刷题的话并无太大优势),由于C语言几乎是科班必修,C++完全可以当成C+STL来用,对初学者而言上手难度极低。

与此同时,在使用C++、看别人题解的同时也可以学习一些比较现代的C++语法(亲测洛谷、力扣和牛客都支持C++11),如auto迭代器、lambda表达式等。除此之外,C++的上限还很高,换句话说就是C++允许你去抠每个细节的性能,如果你觉得官方库的性能不尽人意你甚至可以自己写来超过官方库(如果你够牛的话,比如超过不开O2的STL)。

除此之外,C++还是CSP的官方赛事语言(不喜欢Java的同学们有福啦),虽然只允许你使用 Dev-CPP 作为环境。

环境配置(WSL2)

做C++开发的话,个人还是推荐在Linux环境下,WSL2 Ubuntu就是不错的选择。一方面可以避免Windows下C++安装配环境变量很麻烦或者被迫用 msbuild 的情况,一方面还可以练一练 Linux 小技巧,一石二鸟,何乐而不为呢?

首先安装WSL2 (这部分略),安装完成后安装C/C++套件:

1
2
3
4
5
sudo apt-get install build-essential gdb

# 安装完成后检查
g++ -v
gdb -v

如果成功打印了版本说明安装成功!

接着配置 VS Code 中的 WSL 开发环境,包括 launch.jsontasks.json 两部分,详见:使用vs code和wsl搭建C/C++开发环境_wsl c++ 。(偷懒了,以后会补充的)

环境配置(Windows)

如果你是一个坚定的 Windows 党,你也可以选择手动在 Windows 上配置 mingw-w64 套件来安装 g++(总之就是不推荐在VS以外使用MSBuild)

具体步骤如下:

  1. mingw-w64官网 找到一个Windows的预编译包(一般是x86-64),我个人用的是llvm-mingw (github.com) (如果你上不去或者下载不了,建议先把梯子搞定了,而不要去找网盘或者镜像源,学会使用国际互联网是在中国搞开发的第一步
  2. 下载,解压,放到你喜欢的目录下面,比如我的目录是 c:/mingw,注意看里面应该有一个 bin/ 目录,而里面就有 gcc.exe 和 g++.exe 等等
  3. 把解压的目录添加到环境变量
  4. 添加完了在终端里试试 g++ -v,如果显示了版本就说明安装成功。

后续配置VSCode的过程和上面几乎相同。

C++的弊端

  • C++的语法非常的不优雅,相对于C#和Java来说,一堆::和下划线实在不是很好看
  • C++的字符串处理不太行,很多功能如split等都需要手写
  • C++的报错信息很不友好,堆分配对象的Debug体验也很不好(指针就只给你显示它自己解引用的值)
  • VSCode配置相比JS和Python这样的脚本语言来说麻烦很多

但是没办法,你就是得会、得用C++。

JS

虽然我个人秉承着能用TS就不用JS的理念,但这也只是工程上。刷题的时候强调的就是一个开箱即用,而TS还要转译、配置无疑太过麻烦了,而且引入类型系统对刷题这个代码量其实没有太多的好处。

JS是动态类型的、解释型脚本语言,语法和Java很像,而且也可以直接编写顶层函数,也可以使用ES6后的现代语法和容器等等,而且它的配置相比C++来说简单太多,VS Code这种本就为前端而生的编辑器对JS和Node的支持可以说是开箱即用。

之前我还在担心JS的动态类型和奇怪特性会影响刷题,但现在看来完全是我多想了,用JS刷题对于前端er和Java开发者都是很爽的(特别是对C不熟悉的人)。

配置过程

  1. 安装 Node.JS (16或18都可以),过程比较简单,下一步即可
  2. 运行 node --version 检查安装情况
  3. 直接在 VS Code 里开写,调试配置会自动生成(Run Code也可以直接运行)

Python

Python 作为数据科学常用的语言,也是动态的、解释型的,其实个人感觉刷题体验和JS应该是不相上下的。与JS不同的是,cpython的底层让Python更多作为其他语言的“前端”存在(如C++写的众多机器学习、科学计算库),像胶水一样黏合不同的语言,降低使用门槛。

但是刷题过程中几乎不用到这些第三方库,Python的生态优势就消散了不少,不过即使Python本身性能较弱,但面对刷题这样的“轻量级需求”还是绰绰有余的。

个人而言,Python令我最膈应的地方还是缩进语法了,我真的很难想象一个正经语言会用空白符作为有用的语义分割。

最后,我的评价是:该用还得用,如果你本来就对Python很熟,用就对了!

配置过程

  1. 安装 Python(Python的版本管理是很麻烦的,但是刷题不管)
  2. 检查环境变量,终端运行 python
  3. 直接在 VS Code 里开写,调试配置会自动生成(Run Code也可以直接运行)

C# Script

这里不再推荐传统C#项目,而是C# Script,什么是C# Script可以看看我的这篇文章。毕竟 C# Script(下文简称CSX)就是利用了顶层语句和隐式引用语法糖+REPL解释环境的C#环境,也就是说里面完完全全就是C#的语法和环境,只是变成了脚本语言的形式。

它最大的优势就是C#完备的轮子(各种容器、数据处理和LinQ),还有C#大量的语法糖降低了编写复杂度(如var类型、隐式元组等),而这一切又以脚本的形式呈现出来(感觉就像 Python++),还支持单步调试。

它也有几点缺点,而且这些缺点还不小,所以排名才这么靠后:

  • 性能问题:REPL环境天生性能更差,在线平台C#的性能表现也不尽人意,但是过关肯定没问题
  • 大部分刷题环境不支持CSX,需要手动转换成类语法比较麻烦

具体配置的话还是参考我的另一篇文章:初探 C# Script - ChlorineC’s Blog

Java

个人感觉Java最大的槽点是擦除式泛型,但是这对刷题几乎没有影响。

Java 个人感觉最大的问题和 C# 这样的强OOP语言一样,是与项目深度绑定,但 C# Script 已经出了,所以现在只有 Java 一枝独秀了(谁让JS和Java不算是一门语言呢)。

如果你用着IDEA的话,那就直接用Java也没啥问题,否则个人感觉用VS Code去配Java还是有点麻烦的,具体配置过程这里就不再赘述。

至于老生常谈的GC和JVM调优这些问题,一方面对刷题根本没有影响,一方面新版本的JDK已经基本解决了这些问题(zGC和Native AOT)。

我本来以为Java和.NET性能应该是半斤八两的,毕竟个人体验下来在本地环境里.NET7其实会略快于Java11,但是刷题的实际成绩中Java大幅领先C# 10倍左右,时间复杂度直逼C++。

Benchmark

这里以搜索二维矩阵为例,以全部二分法LeetCode的评测结果作为Benchmark测试各平台性能。

在线平台:LeetCode 2023/04/12

解题代码如下(以C#为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Solution {
public bool SearchMatrix(int[][] matrix, int target) {
if (matrix.Length == 0 || matrix[0].Length == 0) return false;
int begin, mid, end;
begin = mid = 0;
int dim1 = matrix.Length, dim2 = matrix[0].Length;
end = dim1 * dim2 -1;
while (begin < end) {
mid = (begin + end) / 2;
if (matrix[mid/dim2][mid%dim2] < target) begin = mid + 1;
else end = mid;
}
return matrix[begin/dim2][begin%dim2] == target;
}
}

最终相同代码在不同语言下得到的成绩如下:

【图坏了】

可以看到:

  • C++发挥稳定,内存占用一如既往的独一档,但Java执行用时和其在一个水平上令人亮眼
  • C#和Java作为带Runtime和GC的语言,内存占用在一个量级上
  • C#不知道什么原因大幅落后于Java
  • Python表现令人意外(也可能是C#令人太意外了),处于中规中矩的水平

个人的其他困惑

关于在线平台个人最大的不满还是运行环境的不透明性,你不能直观地知道当前运行环境的SDK版本,也不知道相关配置(有没有开启特定优化)。

其次是在线编译器的代码提示不完整编译和Debug体验也不好,与本地环境脱节比较严重。

  • 标题: 关于刷题环境的看法与选择
  • 作者: ChlorineC
  • 创建于 : 2023-04-12 08:00:00
  • 更新于 : 2024-06-04 03:50:36
  • 链接: https://chlorinec.top/2023/04/12/Development/what-is-best-leetcode-lang/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论