leetcode

//to_string()//数字转字符串 //stoi()字符串转数字 //string(1,char)字符转数字//string构造函数

1LL会在运算时把后面的临时数据扩容成long long类型,再在赋值给左边时转回int类型。

array<int, 26>

array:这是 C++ 标准库中的一个模板类,位于 头文件中。它是一个固定大小的容器,类似于传统的 C++ 数组,但提供了更多功能和安全性。 int:表示数组中存储的元素类型是整数。 26:表示数组的大小,即数组中有 26 个元素

unordered_map

在C++中,std::unordered_map 是一个关联容器,用于存储键值对(key-value pairs)。如果你想检查 std::unordered_map 是否包含某个键(key),可以使用 find() 方法或 count() 方法。虽然 C++20 引入了 contains() 方法,但如果你使用的是 C++20 之前的版本,就需要用其他方式来实现。 使用 find() 方法 find() 方法会在容器中查找指定的键。如果找到了,返回一个指向该键值对的迭代器;如果没有找到,返回 end() 迭代器。

2.使用 count() 方法 count() 方法会返回键在容器中出现的次数(对于 unordered_map,只能是 0 或 1)

3.使用 C++20 的 contains() 方法 如果你使用的是 C++20 或更高版本,可以直接使用 contains() 方法。它会返回一个布尔值,表示容器是否包含指定的键。 // 注意不要直接 += cnt[sj-k],如果 sj-k 不存在,会插入 sj-k

static constexpr int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

这种定义通常用于二维平面的搜索问题,如迷宫搜索、棋盘游戏、网格路径搜索等。 通过遍历这个数组,可以方便地实现从当前位置向四个方向的移动。 constexpr 的作用: constexpr 表示这个数组是一个编译时常量,它的值在编译时就已经确定,不能在运行时修改。 这样可以提高代码的效率和安全性,同时避免在运行时动态分配内存。 constexpr 是 C++11 引入的一个非常强大的关键字,它的作用是声明一个“编译时常量表达式”,即在编译阶段就能确定其值的变量或函数。使用 constexpr 可以显著提高代码的效率和安全性,同时还能让代码更加清晰和易于维护。 具体用法略

lambada表达式

这段代码是一个使用C++17标准的lambda表达式,并且使用了递归和参数化捕获的特性 [&]表示捕获当前作用域中的所有变量 this auto&& dfs:这是C++17中引入的参数化捕获特性。this auto&&表示捕获当前lambda对象的引用,允许lambda在递归调用时引用自身。 -> void:表示这个lambda表达式没有返回值 auto dfs = [&](this auto&& dfs, int i) -> void { if (i == nums.size()) { ans++; return; } }; Lambda 表达式是一种强大的工具,它结合了简洁性、匿名性、闭包特性以及与 STL 算法的无缝集成。它在现代 C++ 编程中被广泛应用,尤其是在需要定义简单函数、捕获上下文或实现递归时。

  1. 简洁性
  2. 捕获上下文 Lambda 表达式可以捕获外部变量(通过 [&] 或 [=]),这使得它能够直接访问和修改外部作用域的变量,而无需通过参数传递。
  3. 匿名性
  4. 支持闭包 Lambda 表达式本质上是一种闭包,它可以捕获外部变量并将其封装起来。这使得 Lambda 表达式可以作为函数对象(functor)使用,而无需显式定义类。 5.支持递归 从 C++17 开始,Lambda 表达式可以通过 this auto&& 捕获自身,从而实现递归调用。这使得 Lambda 表达式可以用于复杂算法(如深度优先搜索、动态规划等) 6.与 STL 算法结合 Lambda 表达式与 C++ 标准库中的算法(如 std::sort、std::for_each、std::transform 等)结合得非常好,可以实现非常简洁的代码。
  5. 减少代码冗余 在某些场景下,使用 Lambda 表达式可以避免定义多个小函数,从而减少代码冗余。例如,在多线程编程中,Lambda 表达式可以直接捕获线程需要的上下文。

emplace_back

contains

在C++中,std::unordered_set 是一个关联容器,用于存储唯一的元素。从C++20开始,std::unordered_set 提供了一个成员函数 contains,用于检查容器中是否包含某个元素。这是一个非常方便的函数,可以替代之前的 find 或 count 方法。

std::unordered_set::contains 的用法

函数原型 cpp复制

bool contains(const key_type& key) const; 参数:key 是要检查的元素。 返回值:如果容器中包含该元素,则返回 true;否则返回 false。

lower_bound(nums.begin(),nums.end(),target);

lower_bound() 是 C++ 标准库中的一个函数,它在有序容器(如 std::vector、std::array、std::deque 等)中查找不小于给定值的第一个元素。这个函数使用二分查找算法,因此它的查找效率是 O(log n)。

memset

它定义在 (C++)或 <string.h>(C)头文件中 memset 用于在内存中填充指定的字节值. void* memset(void* dest, int value, size_t count); dest: 指向目标内存区域的指针。 该内存区域将被填充。 value: 要填充的字节值。 注意:value 是一个 int 类型,但它会被解释为一个 单字节值(即只使用其最低的 8 位)。因此,value 的有效范围是 0 到 255。 count: 要填充的字节数 指定从dest开始的内存区域中有多少字节需要被填充 返回值: 返回目标内存区域的指针,方便链式调用 是一个底层的内存操作函数

常见用途:

初始化内存区域 清空内存

sizeof

sizeof 是 C++ 中的一个运算符,用于获取变量、类型或表达式的大小(以字节为单位)。它是一个编译时运算符,因此它的结果在编译时就已经确定,不会在运行时计算。

函数的声明如下:

Vector

1.assign assign 用于重新分配容器的内容,会清空当前容器,并用新的内容填充。

2.resize resize 用于调整容器的大小,同时可以指定新元素的默认值。

3.reverse reverse 并不是 std::vector 的成员函数,而是 C++ 标准库中的一个算法,用于反转容器中的元素顺序。

4.reserve reserve 用于预留容器的内存空间,但不会改变容器的大小

max_element

在 C++ 中,max_element 是标准模板库(STL)中的一个算法函数,定义在头文件 中。它用于查找指定范围内的最大元素。 max_element 的第一个和第二个参数分别是迭代器,表示要查找的范围的开始和结束。 它返回一个迭代器,指向范围内的最大元素。

reduce

std::reduce 是C++17中引入的一个算法,它位于 头文件中。它类似于 std::accumulate,但提供了更好的并行化支持。 :将一个范围内的元素通过指定的二元操作符进行归并(reduce) //默认使用加法

在代码中,dfs 函数的参数 const string& s 使用了引用传参,这是出于性能优化语义清晰的考虑。以下是详细解释:

  1. 性能优化:避免不必要的拷贝 在C++中,传递大型对象(如字符串、向量等)时,直接传递会触发拷贝构造函数,导致对象被复制一份。对于字符串 s,如果直接传递,每次递归调用都会复制整个字符串,这会带来不必要的开销,尤其是在字符串较长时。

例如: void dfs(string s, int i); // 直接传递 每次调用 dfs 时,都会复制整个字符串 s,这会导致时间复杂度和空间复杂度显著增加。

而使用引用传参: void dfs(const string& s, int i); // 引用传参 这种方式不会复制字符串,而是直接传递原始字符串的引用。这样可以显著减少内存占用和拷贝时间,提高程序的运行效率。

  1. 语义清晰:明确字符串不会被修改 在 dfs 函数中,字符串 s 是输入参数,且在递归过程中不需要修改它。使用 const string& 表示: 只读访问:const 修饰符表明 s 在函数内部不会被修改,这有助于代码的可读性和安全性。 明确意图:引用传参表明 s 是一个共享的输入数据,而不是每次递归调用时的独立副本。

这种写法清晰地表达了函数的语义:dfs 函数只是对输入字符串 s 进行读取操作,而不会修改它。

  1. 对比:直接传递 vs 引用传递 假设字符串 s 的长度为 n,递归深度为 n: 直接传递:每次递归调用都会复制整个字符串,总的时间复杂度为 O(n^2),空间复杂度也为 O(n^2)。 引用传递:每次递归调用只是传递一个引用,时间复杂度为 O(n),空间复杂度为 O(n)(主要来自递归栈)。

因此,使用引用传参可以显著优化性能,尤其是在处理大字符串时。

  1. 总结 在 dfs 函数中,使用 const string& s 的原因如下: 性能优化:避免不必要的字符串拷贝,减少时间和空间开销。 语义清晰:明确字符串是只读的输入参数,不会被修改。 最佳实践:在C++中,对于大型对象(如字符串、向量等),通常推荐使用引用传参,以提高效率。

这种写法是C++编程中的常见优化技巧,尤其适用于递归函数和深度优先搜索场景。

perror函数

perror 是一个在 C 语言中常用的函数,用于打印错误信息。它属于标准库 <stdio.h>,主要用于将错误信息输出到标准错误输出(通常是屏幕)。 void perror(const char *s); perror 常用于处理系统调用或库函数失败时的错误。当这些函数失败时,它们通常会将错误码存储在 errno 中,而 perror 可以帮助开发者快速定位问题。

typdef函数

C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等

为基本数据类型定义新的类型名

为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称

typedef struct tagNode { char *pItem; pNode pNext; } *pNode; 其实问题并非在于 struct 定义的本身,大家应该都知道,C 语言是允许在结构中包含指向它自己的指针的,我们可以在建立链表等数据结构的实现上看到很多这类例子。那问题在哪里呢?其实,根本问题还是在于 typedef 的应用。

在上面的代码中,新结构建立的过程中遇到了 pNext 声明,其类型是 pNode。这里要特别注意的是,pNode 表示的是该结构体的新别名。于是问题出现了,在结构体类型本身还没有建立完成的时候,编译器根本就不认识 pNode,因为这个结构体类型的新别名还不存在,所以自然就会报错。因此,我们要做一些适当的调整,比如将结构体中的 pNext 声明修改成如下方式: 解决办法 1.在struct前加typdef 2.将struct与typdef分开定义

为数组定义简洁的类型名称

为指针定义简洁的名称

typedef 是用来定义一种类型的新别名的,它不同于宏,不是简单的字符串替换

assert函数

assert 是 C 语言中一个非常有用的调试工具,用于在程序运行时检查条件是否为真。如果条件为假(即表达式的结果为 0),程序会终止运行,并打印一条错误信息,指出断言失败的位置。

C语言和C++的最大数据结构和最小数据结构

头文件都问 <limits.h> C语言最大数据结构 INT_MAX C语言最小数据结构 INT_MIN C++语言最大数据结构 INT32_MAX C++语言最小数据结构 INT32_MIN

uint64_t

是一种数据类型,通常用于表示无符号的64位整数

定义

它是C语言和C++语言中定义的一种标准整数类型。 在C语言中,uint64_t 是通过头文件 <stdint.h> 定义的。 在C++语言中,uint64_t 是通过头文件 定义的。

特点

无符号:uint64_t 是无符号整数类型,这意味着它不能表示负数,只能表示非负整数。 64位:uint64_t 占用64位(8字节)的存储空间,因此它可以表示的数值范围是从0到 264−1,即从0到18446744073709551615。 平台无关性:uint64_t 是一种固定宽度的整数类型,它的大小在所有支持它的平台上都是固定的,不会因平台的不同而改变。

使用场景

大整数计算:当需要处理较大的整数时,uint64_t 是一个合适的选择。例如,在处理大文件的偏移量、大数组的索引或者大范围的计数器时,uint64_t 可以提供足够的存储空间。 跨平台开发:在跨平台的程序中,使用 uint64_t 可以确保整数的大小在不同的平台上保持一致,避免因平台差异导致的错误。 性能优化:在某些情况下,使用 uint64_t 可以提高程序的性能。例如,在进行位运算或整数运算时,64位整数的运算速度可能会比32位整数更快。