数据结构与算法

[(459条消息) 【C语言】程序运行过程:预处理/编译/汇编/链接_预处理编译汇编链接_慕雪华年的博客-CSDN博客](https://blog.csdn.net/muxuen/article/details/123227200?ops_request_misc={"request_id"%3A"168596052316800182799736"%2C"scm"%3A"20140713.130102334.."}&request_id=168596052316800182799736&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-123227200-null-null.142^v88^control_2,239^v2^insert_chatgpt&utm_term=预处理 编译 汇编 链接&spm=1018.2226.3001.4187)

(443条消息) 保研机试——1基础算法(排序、哈希、模拟(日期、图形、查找、进制、字符串)、递归与分治、贪心)_Yuezero_的博客-CSDN博客

[(425条消息) 数据结构保研面试题整理(自用)_保研数据结构常温问题_乌鸡摸鱼的博客-CSDN博客](https://blog.csdn.net/m0_52571748/article/details/120505195?ops_request_misc=&request_id=&biz_id=102&utm_term=数据结构 保研&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-120505195.142^v73^pc_search_v2,201^v4^add_ask,239^v2^insert_chatgpt&spm=1018.2226.3001.4187)

(463条消息) 插入排序–折半插入排序(来一来,看一看,走过路过,不要错过)_老 胡的博客-CSDN博客

P问题、NP问题、NPC问题、NP-hard问题详解 - 知乎 (zhihu.com)

[保研机试整理 - 知乎 (zhihu.com)

什么时候才考虑用二分答案的技巧?
正向求出答案不好入手,求解答案远远没有验证答案简单。

已知前序后序算中序有多少种:

[(441条消息) 二叉树遍历(已知前序和后序遍历,求中序遍历的可能的序列数)_已知二叉树的前序遍历和后序遍历_我要出家当道士的博客-CSDN博客

(462条消息) 堆排序的时间复杂度分析_一只牛_007的博客-CSDN博客

建立索引树:[(462条消息) 2020北航计算机夏令营机试题目个人理解_北航夏令营 机试_四处碰壁嘤嘤怪的博客-CSDN博客](https://blog.csdn.net/Bernie_double/article/details/118190022?ops_request_misc={"request_id"%3A"168715279416800185829257"%2C"scm"%3A"20140713.130102334.."}&request_id=168715279416800185829257&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-118190022-null-null.142^v88^control_2,239^v2^insert_chatgpt&utm_term=北航夏令营 机试&spm=1018.2226.3001.4187)

注意

scanf后,用getchar()吃掉回车

表示最大 INT_MAX(climits)

1
2
3
4
5
6
7
8
//malloc
int *nums;
nums=(*int)malloc(10*sizeof(int));
//long long int 别用cin cout
long long a;
scanf("%lld",&a);
printf("%lld",a);

scanf还会返回成功输入的变量的个数,因此可判定EOF

Floyd判圈法很吊

1.lower_bound(v.begin(), v.end(), key)-v.begin()返回有序序列中大于等于key的第一个值的位置
2.upper_bound(v.begin(), v.end(), key)-v.begin()返回有序序列中大于key的第一个值的位置
3.lower_bound(v.begin(), v.end(), key, greater())-v.begin()返回有序序列中小于等于key的第一个值的位置
4.upper_bound(v.begin(), v.end(), key, greater())-v.begin()返回有序序列中小于key的第一个值的位置
5.上述四个函数,若无满足条件的值,则返回v.size()

文件操作

1
2
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);

lint&formatter

vscode记得装一个clang-format, ctrl+s能够自动保存

strcut初始化的例子:

1
2
3
4
5
6
7
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };

一些常用的库

  1. algorithm
  2. vector
  3. map
  4. queue
  5. iostream
  6. string
  7. bits/stdc++.h(带上就对了,不过mac的clang不支持,GCC支持)
  8. cmath(sqrt之类的)
  9. climits(INT_MAX INT_MIN)

STL内置find()复杂度
algorithm的find 复杂度是O(n),对vector,string等 顺序查询。
map::findset::find 复杂度是O(logn),因为map和set底层都是红黑树。


vector:

下面是一些常用的vector方法:

  1. push_back:在vector的末尾添加一个元素。

  2. pop_back:删除vector末尾的一个元素。

  3. size:返回vector中元素的个数。

  4. clear:删除vector中所有的元素。

  5. empty:判断vector是否为空。

  6. at:返回vector中指定位置的元素。

  7. front:返回第一个元素。

  8. back:返回最后一个元素。

  9. erase:删除vector中指定位置的元素。

  10. insert:在vector中指定位置插入一个元素或多个元素。

    1. std::vector<int> vec = {1, 2, 3};
          
      // 在开头插入3个值为0的元素
      vec.insert(vec.begin(), 3, 0);
      
      1
      2
      3
      4
      5
      6
      7
      8
      9



      11. `resize`:改变vector的大小。

      12. `reserve`:为vector预留一定的空间。

      ```c++
      reverse(a.begin(),a.end());
  11. swap:交换两个vector中的元素。

  12. begin:返回指向vector第一个元素的迭代器。

  13. end:返回指向vector最后一个元素之后的迭代器。 这些方法能够满足大部分情况下的需求,可以根据具体的使用场景选择合适的方法进行操作。

要取迭代器的值,直接*指针取值

对于向量(vector),它是一种支持随机访问的容器,因此可以直接通过下标访问向量中的元素

1
2
3
4
5
vector<int> v = {1, 2, 3, 4, 5};
// 使用auto关键字定义迭代器
for (auto it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}

vector不能直接使用sort函数进行排序,需要传入一个迭代器指定排序的范围。修改代码如下:

sort(v.begin(),v.end(),com);


map

以下是C++中map类的常用方法:

  1. insert(make_pair<key, value>):向map中插入一个键值对。

  2. erase(key):删除map中指定键的元素。

  3. clear():清空map中所有元素。

  4. size():返回map中元素的个数。

  5. empty():返回map是否为空。

  6. find(key):查找map中是否存在指定键的元素,如果存在则返回指向该元素的迭代器,否则返回end()迭代器。

    常常和end联合起来用判断找到没。(这个适合动态查找,底层红黑树实现)

    e.g. if (m.find(key)!=m.end())

  7. count(key):返回指定键在map中出现的次数,如果不存在则返回0或1。

  8. begin():返回指向map第一个元素的迭代器。

  9. end():返回指向map最后一个元素后面的位置的迭代器。

  10. operator[]:通过键访问map中的元素,如果键不存在,则自动插入一个新的键值对并返回对应的值。

  11. lower_bound(key):返回第一个大于或等于指定键的元素的迭代器。

  12. upper_bound(key):返回第一个大于指定键的元素的迭代器。

  13. equal_range(key):返回一个pair对象,其中包含lower_bound和upper_bound返回的迭代器。

  14. swap(map2):交换当前map和map2的元素。 C++中的map类是一种关联式容器,用于存储键值对,其中每个键都唯一,并且按照一定的顺序排列。map的底层实现通常是红黑树,因此查找、插入和删除操作的时间复杂度为O(log n),其中n是map中元素的个数。map类提供了丰富的方法,可以方便地进行键值对的操作,例如插入、删除、查找、排序等。同时,由于map使用键值对来存储数据,因此可以将map看作是一种特殊的数组,其下标为键,对应的值为数组元素。因此,可以通过下标来访问和修改map中的元素。

1
2
3
4
5
map<string, int> m = {{"apple", 1}, {"banana", 2}, {"orange", 3}};
// 使用auto关键字定义迭代器
for (auto it = m.begin(); it != m.end(); it++) {
cout << it->first << ": " << it->second << endl;
}

pair

这里注意pair的用法

1
2
3
4
5
6
7
8
const pair<int,int>mapping[]={
{1:2},
{2:3},
}

const auto &[k,v] : mapping{

}

stack

C++ 中的 stack 库提供了以下常用的方法:

  • push(elem):将元素 elem 压入栈顶。
  • pop():弹出栈顶元素。
  • top():返回栈顶元素,但不弹出。
  • empty():判断栈是否为空。
  • size():返回栈中元素的个数。 除此之外,stack 还支持以下操作:
  • emplace(args…):构造一个新元素并将其压入栈顶。
  • swap(stack):交换两个 stack 的元素。
  • operator==、operator!=、operator<、operator<=、operator>、operator>=:比较两个 stack 是否相等、不相等、小于、小于等于、大于、大于等于。 具体用法可以参考下面的示例代码

stack元素可以是任何类型。


queue

C++中的queue是一种容器适配器,用于实现“先进先出”(FIFO)的数据结构。queue基于deque或list进行实现,提供了一些方法来操作队列,包括入队、出队、获取队首元素、获取队列大小等。以下是queue的常用方法:

  1. push(element):将一个元素加入队列的尾部。
  2. pop():将队列头部的元素弹出,但没有返回值。
  3. front():返回队列头部的元素。
  4. back():返回队列尾部的元素。
  5. empty():判断队列是否为空。
  6. size():返回队列中元素的个数。 使用queue需要包含头文件,可以通过以下方式创建一个queue对象:

对于队列(queue),由于它是一种先进先出(FIFO)的数据结构,因此只能通过front()和back()函数来访问队列的头部和尾部元素,而不能直接通过下标访问。如果要使用下标访问队列元素,需要先将队列转换为数组或向量。


priority_queue

1
2
3
4
5
6
7
8
#include <queue>
//对于基础类型 默认是大顶堆
priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;


priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆
priority_queue<string> b;

对于优先队列,复杂结构类型要重载运算符(436条消息) C++ 运算符重载_c 重载运算符_高祥xiang的博客-CSDN博客

1
2
3
4
5
6
7
8
struct complex{
int real;
int imag;
......
bool operator<(Complex c)const{
return real*real+imag*imag<c.real*c.real+c.imag*c.imag;
}
}

注意上面这个const是必须要有的

注意这里的重载运算符跟后面的想要大顶堆还是小顶堆有关系。如果要小顶堆,greater这里,其实要重写的就只有operator>,如果是大顶堆,要重写operator<


string

C++中的string类是一个封装了字符串操作的类,提供了一系列方法来处理和操作字符串。以下是常用的string类方法:

  1. length():返回字符串的长度。

  2. size():返回字符串的长度。

  3. clear():清空字符串。

  4. empty():判断字符串是否为空。

  5. assign(str):将字符串的值设置为str。

  6. assign(str, pos, len):将字符串的值设置为str中从pos位置开始的长度为len的子串。

  7. append(str):在字符串的末尾添加str。

  8. append(str, pos, len):在字符串的末尾添加str中从pos位置开始的长度为len的子串。

  9. push_back(ch):在字符串的末尾添加一个字符。

  10. insert(pos, str):在字符串的pos位置插入str。

  11. erase(pos, len):删除从pos位置开始长度为len的子串。

    erase(n):删除indexn后面的字符

  12. replace(pos, len, str):替换从pos位置开始长度为len的子串为str。

  13. substr(pos, len):返回从pos位置开始长度为len的子串。

  14. find(str):查找str在字符串中第一次出现的位置,返回该位置的索引值。(找不到就是-1)

  15. rfind(str):查找str在字符串中最后一次出现的位置,返回该位置的索引值。

  16. to_string:将数字转化成字符串

  17. stoi(将字符串转化成整数数字) stod(将字符串转化成浮点数)

  18. compare(str):比较字符串和str的大小,返回0(相等)、1(大于)或-1(小于)。 除了以上列举的方法,string类还支持重载运算符,例如+(字符串拼接)、+=(字符串拼接赋值)、==(字符串相等判断)、[](访问字符串中指定位置的字符)等。string类的使用非常方便,可以像使用普通变量一样对字符串进行赋值、拼接、查找、替换等操作。例如:

注意string s,其s[i]类型为char,char强制类型转换可以这样转换

string(1,s[i]),1表示char长度

s[i]可以直接比较

输入str1,如果str1为空则退出

scanf不会读回车,如果下一行是gets会直接读取缓冲区中的回车,所有会用一个getchar()在中间把缓冲区中的回车抵消掉

stoi(str) 将其转换为整数,注意,如果是"04",直接变成4

string::npos用于判断结尾(其实找不到直接-1也行):

1
2
3
4
5
6
7
8
9
10
11
12
13
//find函数返回 jk 在 s 中的下标位置
position = s.find("jk");
// 如果没找到,返回一个特别的标志
// c++中用npos表示,我这里npos取值是4294967295
if(position != s.npos)
{
cout << "position: " << position << endl;
}
else
{
cout << "Not found the flag" << endl;
}

如果输入的字符串有空格,那么用如下代码

1
getline(cin,str)

可以直接通过下标修改字符

删除字符串内重复字符:

1
2
3
4
5
string str="aadfgggh";
//去重复
sort(str.begin(),str.end());
str.erase(unique(str.begin(),str.end()),str.end());

删除字符串内某个指定字符:

1
2
string str="aadfgggh";
str.erase(remove(str.begin(),str.end(),'a'),str.end()); //在容器中, 删除[begin,end)之间的所有值等于'a'的值.
1
2
#include<string>
string::erase(begin,end):删除[begin,end)之间的所有值c

在Find the Smallest Number中,我发现string的超出index一位的位置依然可以访问,但是没有数


algorithm

C++标准库中的algorithm库提供了许多常用的算法,这些算法可以用于处理容器中的数据,例如排序、查找、遍历等。以下是algorithm库中常用的方法:

  1. sort(first, last, func):对[first, last)区间内的元素进行升/降序排序(取决于func返回)。
  2. vector<int>nums;
    sort(nums.begin(),nums.end());
    sort(nums.begin(),nums.end(),std::greater<int>());
    sort(nums.begin(),nums.end(),[](vector<int>a, vector<int>b){
    	return a[1]<v[1];
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49

    3. reverse(first, last):对[first, last)区间内的元素进行翻转。
    4. find(first, last, val):在[first, last)区间内查找值为val的元素,返回该元素的迭代器。如果没有找到,返回last。
    5. find_if(first, last, pred):在[first, last)区间内查找满足条件pred的第一个元素,返回该元素的迭代器。如果没有找到,返回last。
    6. count(first, last, val):统计[first, last)区间内值为val的元素个数。
    7. count_if(first, last, pred):统计[first, last)区间内满足条件pred的元素个数。
    8. accumulate(first, last, init):对[first, last)区间内的元素进行累加,初始值为init。
    9. max_element(first, last):返回[first, last)区间内的最大元素的迭代器。
    10. min_element(first, last):返回[first, last)区间内的最小元素的迭代器。
    11. unique(first, last):对[first, last)区间内的元素去重,返回去重后的末尾迭代器。
    12. remove(first, last, val):删除[first, last)区间内值为val的元素,返回删除后的末尾迭代器。
    13. remove_if(first, last, pred):删除[first, last)区间内满足条件pred的元素,返回删除后的末尾迭代器。
    14. for_each(first, last, func):对[first, last)区间内的元素执行操作func。
    15. transform(first1, last1, first2, result, op):将[first1, last1)区间内的元素和[first2, ...)区间内的元素进行op操作,并将结果存储到[result, ...)区间内。

    ### climits

    <climits>中定义的常量主要有以下几种:

    1. 整数类型的最大值和最小值:INT_MAX、INT_MIN、LONG_MAX、LONG_MIN、SHRT_MAX、SHRT_MIN等等。
    2. 字符类型的最大值和最小值:CHAR_MAX、CHAR_MIN、SCHAR_MAX、SCHAR_MIN、UCHAR_MAX等等。
    3. 位数相关的常量:CHAR_BIT、INT_BIT、LONG_BIT等等。
    4. 其他常量:MB_LEN_MAX表示一个多字节字符的最大长度,FLT_MAX、FLT_MIN、DBL_MAX、DBL_MIN等等表示浮点类型的最大值和最小值。

    ### set

    unordered_set

    ** **

    `set` 是C++ STL中的关联容器,具有以下特点:
    - **自动排序**:元素按升序排列(默认)
    - **唯一性**:不允许重复元素
    - **高效查找**:基于红黑树实现,查找、插入、删除时间复杂度为 O(log n)

    **头文件和声明**

    ```cpp
    #include <set>
    #include <iostream>

    // 基本声明
    std::set<int> mySet;

    // 自定义比较函数
    std::set<int, std::greater<int>> descendingSet;

    // 自定义类型
    std::set<std::string> stringSet;

基本操作

1. 插入元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <set>
#include <iostream>

int main() {
std::set<int> mySet;

// insert方法
mySet.insert(10);
mySet.insert(20);
mySet.insert(5);
mySet.insert(10); // 重复元素不会插入

// 插入多个元素
mySet.insert({1, 3, 7, 9});

// 输出结果:1 3 5 7 9 10 20(自动排序且去重)
for(const auto& elem : mySet) {
std::cout << elem << " ";
}

return 0;
}

2. 查找元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <set>
#include <iostream>

int main() {
std::set<int> mySet = {1, 3, 5, 7, 9};

// find方法 - 返回迭代器
auto it = mySet.find(5);
if(it != mySet.end()) {
std::cout << "找到元素: " << *it << std::endl;
} else {
std::cout << "未找到元素" << std::endl;
}

// count方法 - 返回0或1
if(mySet.count(7)) {
std::cout << "元素7存在" << std::endl;
}

// contains方法 (C++20)
// if(mySet.contains(7)) {
// std::cout << "元素7存在" << std::endl;
// }

return 0;
}

3. 删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <set>
#include <iostream>

int main() {
std::set<int> mySet = {1, 2, 3, 4, 5};

// 删除指定值
mySet.erase(3);

// 删除迭代器指向的元素
auto it = mySet.find(4);
if(it != mySet.end()) {
mySet.erase(it);
}

// 删除范围
auto first = mySet.find(1);
auto last = mySet.find(5);
if(first != mySet.end() && last != mySet.end()) {
mySet.erase(first, last); // 删除[1,5)范围
}

return 0;
}

utility:

在 C++ 中,pair 是标准模板库(STL)中的一种模板类,定义在头文件 <utility> 中,用于将两个值(可以是不同类型)组合成一个单元


🧩 一、基本定义

1
2
3
4
#include <utility>  // 必须包含的头文件
using namespace std;

pair<T1, T2> p;
  • T1:第一个元素的类型
  • T2:第二个元素的类型
  • p.first:访问第一个元素
  • p.second:访问第二个元素

✅ 二、创建 pair 的几种方式

  1. 直接初始化
1
pair<int, string> p1(10, "hello");
  1. 使用 make_pair(自动推导类型)
1
auto p2 = make_pair(20, "world");  // 类型自动推导为 pair<int, const char*>

✅ 推荐使用 make_pair,简洁且避免手动写类型。

  1. 使用花括号初始化(C++11 起)
1
pair<int, double> p3{30, 3.14};
  1. 赋值构造
1
2
pair<string, int> p4;
p4 = make_pair("age", 25);

🔍 三、访问元素

1
2
cout << p1.first << endl;   // 输出: 10
cout << p1.second << endl; // 输出: hello

🔄 四、比较操作

pair 支持 ==, !=, <, <=, >, >=,比较规则是:

  1. 先比较 first
  2. 如果 first 相等,再比较 second
1
2
3
4
5
6
pair<int, string> a(1, "apple");
pair<int, string> b(1, "banana");
pair<int, string> c(2, "apple");

cout << (a < b) << endl; // true —— first 相同,"apple" < "banana"
cout << (a < c) << endl; // true —— 1 < 2

✅ 这使得 pair 非常适合用作 map 的键、或在 setpriority_queue 中排序。


📦 五、常用场景

  1. 作为函数返回多个值
1
2
3
4
5
6
7
8
pair<int, int> getMinMax(vector<int>& nums) {
int minVal = *min_element(nums.begin(), nums.end());
int maxVal = *max_element(nums.begin(), nums.end());
return make_pair(minVal, maxVal);
}

auto result = getMinMax({3, 1, 4, 1, 5});
cout << "Min: " << result.first << ", Max: " << result.second << endl;
  1. 在 map 中遍历键值对
1
2
3
4
5
6
7
8
map<string, int> ages = {{"Alice", 30}, {"Bob", 25}};

for (const auto& p : ages) {
cout << p.first << " is " << p.second << " years old." << endl;
}
// 输出:
// Alice is 30 years old.
// Bob is 25 years old.

💡 map::value_type 就是 pair<const Key, T>

  1. 优先队列中自定义优先级
1
2
3
4
5
6
7
8
9
10
11
12
13
priority_queue<pair<int, string>> pq; // 默认按 first 降序
pq.push(make_pair(10, "low"));
pq.push(make_pair(30, "high"));
pq.push(make_pair(20, "medium"));

while (!pq.empty()) {
cout << pq.top().first << ": " << pq.top().second << endl;
pq.pop();
}
// 输出:
// 30: high
// 20: medium
// 10: low

🆚 六、pair vs tuple

特性 pair<T1, T2> tuple<T1, T2, T3, ...>
元素个数 固定 2 个 任意多个
访问方式 .first, .second get<0>(t), get<1>(t)
使用场景 简单二元组(键值对、坐标等) 多返回值、复杂组合

✅ 如果只需要两个值,优先用 pair —— 语义清晰、访问方便。


🧠 七、小技巧

结构化绑定(C++17 起)

1
2
3
4
auto p = make_pair(100, "OK");
auto [value, message] = p; // 解构赋值

cout << value << ", " << message << endl; // 输出: 100, OK

✅ 非常适合用于循环或函数返回值解包:

1
2
3
for (const auto& [key, val] : myMap) {
cout << key << " => " << val << endl;
}

📚 八、完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
// 创建 pair
pair<int, string> p1 = make_pair(1, "apple");
pair<int, string> p2{2, "banana"};

// 访问
cout << p1.first << ": " << p1.second << endl;

// 比较
if (p1 < p2) {
cout << "p1 < p2" << endl;
}

// 用在 vector 中
vector<pair<int, string>> vec;
vec.push_back(p1);
vec.push_back(p2);

// 排序(默认按 first 升序)
sort(vec.begin(), vec.end());

for (const auto& p : vec) {
cout << p.first << " - " << p.second << endl;
}

// C++17 结构化绑定
for (const auto& [id, name] : vec) {
cout << "ID: " << id << ", Name: " << name << endl;
}

return 0;
}

✅ 总结

pair 是 C++ 中轻量级的“二元组”容器,用于捆绑两个相关值,广泛用于返回多值、map 遍历、排序、优先队列等场景。

📌 记住:

  • 包含头文件:#include <utility>
  • 创建:make_pair(a, b){a, b}
  • 访问:.first, .second
  • 支持比较、可作 map 键
  • C++17 支持结构化绑定:auto [x, y] = p;

掌握 pair,是用好 STL 和现代 C++ 的基础技能之一!

迭代器操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <set>
#include <iostream>

int main() {
std::set<int> mySet = {10, 20, 30, 40, 50};

// 正向遍历
std::cout << "正向遍历: ";
for(auto it = mySet.begin(); it != mySet.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// 反向遍历
std::cout << "反向遍历: ";
for(auto it = mySet.rbegin(); it != mySet.rend(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// 范围for循环
std::cout << "范围循环: ";
for(const auto& elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;

return 0;
}

容量和属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <set>
#include <iostream>

int main() {
std::set<int> mySet = {1, 2, 3};

// 大小
std::cout << "大小: " << mySet.size() << std::endl;

// 是否为空
std::cout << "是否为空: " << (mySet.empty() ? "是" : "否") << std::endl;

// 最大大小
std::cout << "最大大小: " << mySet.max_size() << std::endl;

return 0;
}

自定义比较函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <set>
#include <iostream>
#include <string>

// 方法1:函数对象
struct Compare {
bool operator()(const std::string& a, const std::string& b) const {
return a.length() < b.length(); // 按长度排序
}
};

// 方法2:函数指针
bool compareLength(const std::string& a, const std::string& b) {
return a.length() < b.length();
}

int main() {
// 按字符串长度排序
std::set<std::string, Compare> lengthSet;
lengthSet.insert("apple");
lengthSet.insert("hi");
lengthSet.insert("banana");
lengthSet.insert("cat");

// 输出: hi cat apple banana (按长度排序)
for(const auto& str : lengthSet) {
std::cout << str << " ";
}
std::cout << std::endl;

return 0;
}

实际应用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <set>
#include <iostream>
#include <vector>
#include <algorithm>

// 去除vector中的重复元素
std::vector<int> removeDuplicates(const std::vector<int>& vec) {
std::set<int> uniqueSet(vec.begin(), vec.end());
return std::vector<int>(uniqueSet.begin(), uniqueSet.end());
}

// 查找两个集合的交集
std::set<int> intersection(const std::set<int>& set1, const std::set<int>& set2) {
std::set<int> result;
std::set_intersection(set1.begin(), set1.end(),
set2.begin(), set2.end(),
std::inserter(result, result.begin()));
return result;
}

int main() {
// 去重示例
std::vector<int> numbers = {1, 2, 2, 3, 3, 4, 5, 5};
std::vector<int> uniqueNumbers = removeDuplicates(numbers);

std::cout << "去重后: ";
for(int num : uniqueNumbers) {
std::cout << num << " ";
}
std::cout << std::endl;

// 交集示例
std::set<int> set1 = {1, 2, 3, 4, 5};
std::set<int> set2 = {3, 4, 5, 6, 7};
std::set<int> intersect = intersection(set1, set2);

std::cout << "交集: ";
for(int num : intersect) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

multiset 简介

如果需要允许重复元素,可以使用 multiset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <set>
#include <iostream>

int main() {
std::multiset<int> multiSet;

multiSet.insert(10);
multiSet.insert(20);
multiSet.insert(10); // 允许重复

std::cout << "multiset大小: " << multiSet.size() << std::endl; // 输出: 3

// 统计特定元素出现次数
std::cout << "10出现次数: " << multiSet.count(10) << std::endl; // 输出: 2

return 0;
}

性能特点

  • 插入: O(log n)
  • 删除: O(log n)
  • 查找: O(log n)
  • 空间复杂度: O(n)

set 是处理需要排序且唯一性要求的场景的理想选择!

设置输出精度

设置输出精度为1位小数

cout << fixed << setprecision(1) << ans << endl

设置输出位数

printf(“%02d”,&)

前面补零,两位,不够两位就补零

KMP

KMP 算法详解 - 知乎 (zhihu.com)

(427条消息) 从头到尾彻底理解KMP(2014年8月22日版)_kmp算法难吗是什么级别_v_JULY_v的博客-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//next
void GetNext(char* p,int next[])
{
int pLen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < pLen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//kmp
int KmpSearch(char* s, char* p)
{
int i = 0;
int j = 0;
int sLen = strlen(s);
int pLen = strlen(p);
while (i < sLen && j < pLen)
{
//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if (j == -1 || s[i] == p[j])
{
i++;
j++;
}
else
{
//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = next[j];
}
}
if (j == pLen)
return i - j;
else
return -1;
}

动态规划

最大连续子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;

int dp[1000001];
int nums[1000001];
int main(){
int N;
while(cin>>N){
if (N==EOF)break;
int maxnum=INT_MIN;
for (int i=1;i<=N;i++){
cin>>nums[i];
}
dp[1]=nums[1];
if (N==1){
cout<<dp[1]<<endl;
break;
}
for (int i=2;i<=N;i++){
dp[i]=max(nums[i],dp[i-1]+nums[i]);
maxnum=max(dp[i],maxnum);
}
cout<<maxnum<<endl;

}
return 0;
}


最大子矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <algorithm>
using namespace std;

int dp[101];
int matrix[101][101];
int support[101][101];
int arr[101];

int hangmax(int n){
int maxnum;
for (int i=1;i<=n;i++){
dp[i]=max(arr[i],dp[i-1]+arr[i]);
maxnum=max(maxnum,dp[i]);
}
return maxnum;
}

int allmax(int n){
int maxnum;
for (int i=1;i<=n;i++){
for (int j=i;j<=n;j++){
for (int k=1;k<=n;k++){
if (i==1){
arr[k]=support[j][k];
}else{
arr[k]=support[j][k]-support[i-1][k];
}
}
maxnum=max(hangmax(n),maxnum);

}
}
return maxnum;
}

int main(){
int n;
cin>>n;
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
cin>>matrix[i][j];

}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i==1)support[i][j]=matrix[i][j];
else{
support[i][j]=matrix[i][j]+support[i-1][j];
}
}
}
int maxnum;
maxnum=allmax(n);
cout<<maxnum<<endl;
return 0;


}

最长递增/减序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <algorithm>
using namespace std;

int dp[26];
int daodan[26];

int countmax(int n){
int maxnum=0;
for (int i=1;i<=n;i++){
dp[i]=1;
}
for (int i=2;i<=n;i++){
for (int j=1;j<i;j++){
if (daodan[i]<=daodan[j])
dp[i]=max(1,dp[j]+1);
maxnum=max(maxnum,dp[i]);
}
}
return maxnum;
}

int main(){
int n;
cin>>n;
for (int i=1;i<=n;i++){
cin>>daodan[i];
}
int maxnum;
maxnum=countmax(n);
cout<<maxnum<<endl;
return 0;
}

最大上升子序列和(O(N^2))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <algorithm>
using namespace std;

int dp[1001];
int nums[1001];

int countmax(int n){
int maxsum;
for (int i=1;i<=n;i++){
dp[i]=nums[i];
}
for (int i=2;i<=n;i++){
for (int j=1;j<i;j++){
if (nums[i]>nums[j])
dp[i]=max(nums[i],dp[j]+nums[i]);
maxsum=max(maxsum,dp[i]);
}
}
return maxsum;
}

int main(){
int n;
cin>>n;
for (int i=1;i<=n;i++){
cin>>nums[i];
}
int maxsum;
if (n==1){
cout<<nums[1];
return 0;
}
maxsum=countmax(n);
cout<<maxsum<<endl;
return 0;
}

最长公共子序列(LCS)

1
7
3
5
9
4
8
3

(461条消息) 最长公共子序列 (LCS) 详解+例题模板(全)_lxt_Lucia的博客-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

string s1;
string s2;

int countmax(string s1,string s2){
int length1=s1.size();
int length2=s2.size();
int dp[length1][length2];
for (int i=0;i<length1;i++){
for (int j=0;j<length2;j++){
dp[i][j]=0;
}
}
int maxnum=0;
for (int i=0;i<length1;i++){
for (int j=0;j<length2;j++){
if (s1[i]==s2[j]){
if (i==0||j==0){
dp[i][j]=1;
}else{
dp[i][j]=dp[i-1][j-1]+1;
}
}else{
if (i==0||j==0){
dp[i][j]=0;
}else{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}

}
maxnum=max(maxnum,dp[i][j]);
}
}
return maxnum;
}
int main(){
while(cin>>s1>>s2){
int maxnum=countmax(s1,s2);
cout<<maxnum<<endl;

}
return 0;
}

LIS(Nlogn)

(465条消息) 最长上升子序列 (LIS) 详解+例题模板 (全)_lxt_Lucia的博客-CSDN博客

01背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;

struct d{
int price;
int score;
};

int main(){
int C,N;
while (cin>>C>>N){
if (C==0&&N==0)break;
int dp[C+1];
d deal[N];
for (int i=0;i<=C;i++){
dp[i]=0;
}
for (int i=0;i<N;i++){
int price;
int score;
cin>>price>>score;
deal[i].price=price;
deal[i].score=score;
}
for (int i=0;i<N;i++){
for (int j=C;j>=1;j--){
if (j>=deal[i].price){
dp[j]=max(dp[j-deal[i].price]+deal[i].score,dp[j]);
}
}
}
cout<<dp[C]<<endl;

}
return 0;
}

有个背包的变种

(465条消息) 复旦大学2021年计算机学院机试题解_复旦oj_PyKt的博客-CSDN博客

这里是直接顺序的

DFS BFS

排序

归并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
void merge(int* a, int low, int mid, int hight) //合并函数
{
int* b = new int[hight - low + 1]; //用 new 申请一个辅助函数
int i = low, j = mid + 1, k = 0; // k为 b 数组的小标
while (i <= mid && j <= hight)
{
if (a[i] <= a[j])
{
b[k++] = a[i++]; //按从小到大存放在 b 数组里面
}
else
{
b[k++] = a[j++];
}
}
while (i <= mid) // j 序列结束,将剩余的 i 序列补充在 b 数组中
{
b[k++] = a[i++];
}
while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中
{
b[k++] = a[j++];
}
k = 0; //从小标为 0 开始传送
for (int i = low; i <= hight; i++) //将 b 数组的值传递给数组 a
{
a[i] = b[k++];
}
delete[]b; // 辅助数组用完后,将其的空间进行释放(销毁)
}
void mergesort(int* a, int low, int hight) //归并排序
{
if (low < hight)
{
int mid = (low + hight) / 2;
mergesort(a, low, mid); //对 a[low,mid]进行排序
mergesort(a, mid + 1, hight); //对 a[mid+1,hight]进行排序
merge(a, low, mid, hight); //进行合并操作
}
}
int main()
{
int n, a[100];
cout << "请输入数列中的元素个数 n 为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
mergesort(a, 0, n-1);
cout << "归并排序结果" << endl;
for (int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}

快速排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void QuickSort(int arr[], int begin, int end)
{
//只有一个数或者区间不存在时
if (begin >= end) return;
int left = begin;
int right = end;
//选取左边第一个为key
int key = begin;
while (begin<end)
{
//右边选小
while (arr[end] >= arr[key] && begin < end)
{
end--;
}
//左边选大
while (arr[begin] <= arr[key] && begin < end)
{
begin++;
}
swap(arr[begin], arr[end]);
}
//此时left和right指针已经相遇
swap(arr[key], arr[end]);
//递归左右区间
key = end;
QuickSort(arr, left, key - 1);
QuickSort(arr, key + 1, right);
}

快速幂

1
2
3
4
5
6
7
8
9
10
11
12
const long long m=1e9+7;
long long quickpow(long long a,long long b){
long long sum=1;
while(b){
if(b&1)//与运算,可判断奇偶,详细见注释
sum=sum*a%m;//取模运算
a=a*a%m;
b>>=1;//位运算,右移,相当于除以2
}
return sum;
}

模拟问题

就是找规律,还行

日期问题

要预处理

最大公因数/最小公倍数

最小公倍数=a*b/c

c为最大公因数

1
2
3
4
5
6
7
8
9
//最大公因数
int biggest(int a,int b){
return b!=0?biggest(b,a%b):a;
}
//最小公倍数
int smallest(int a, int b){
int big=biggest(a,b);
return a*b/big;
}

素数筛法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<iostream>
using namespace std;
int n;

int main(){
while (cin>>n){

if (n==0)break;
if (n==2){
cout<<-1<<endl;
continue;
}
bool sushu[n+1];
for (int i=2;i<=n;i++){
sushu[i]=true;
}
for (int i=2;i<=n;i++){
if (sushu[i]==false)continue;
for (int j=i;j*i<=n;j++){ //j直接从i开始,提高效率
if (j*i<n){
sushu[j*i]=false;
}
}
}
for (int i=2;i<n;i++){
if (sushu[i]){
if (i%10==1){
cout<<i<<" ";
}
}

}
cout<<endl;

}
return 0;
}

对于一个数n,其质因数最多只有一个大于其平方根!

矩阵乘法(构造函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;

struct Matrix{
int matrix[10][10];
int row;
int col;
Matrix(int a,int b):row(a),col(b){}//注意构造函数的写法
};
Matrix Multiply(Matrix a,Matrix b){
Matrix ans=Matrix(a.row,b.col);
for (int i=0;i<a.row;i++){
for (int j=0;j<b.col;j++){
int temp=0;
for (int k=0;k<a.col;k++){
temp+=a.matrix[i][k]*b.matrix[k][j];
}
ans.matrix[i][j]=temp;
}
}
return ans;
}

void printMatrix(Matrix m){
int row=m.row;
int col=m.col;
for (int i=0;i<row;i++){
for (int j=0;j<col;j++){
if (j!=0){
cout<<" ";
}
cout<<m.matrix[i][j];
}
cout<<endl;
}
}


int main(){
Matrix a=Matrix(2,3);
Matrix b=Matrix(3,2);
for (int i=0;i<2;i++){
for (int j=0;j<3;j++){
cin>>a.matrix[i][j];
}
}
for (int i=0;i<3;i++){
for (int j=0;j<2;j++){
cin>>b.matrix[i][j];
}
}
Matrix c=Multiply(a,b);
printMatrix(c);
return 0;

}

高精度

最小生成树

prim算法求最小生成树- CSDN搜索

kruscal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <queue>
using namespace std;

struct edge{
int a;
int b;
int weight;
bool operator>(edge c)const{
return weight>c.weight;
}
edge(int q,int w,int e):a(q),b(w),weight(e){}
};

priority_queue<edge,vector<edge>,greater<edge>>edges;
int graph[100];


int find(int x){
if (graph[x]==-1)return x;
else{
int temp;
temp=find(graph[x]);
graph[x]=temp;
return temp;
}

}

int main(){
int n;
while (cin>>n){
if (n==0)break;
int a,b,weight;
int num=n*(n-1)/2;
memset(graph,-1,sizeof(graph));
for (int i=1;i<=n;i++){
graph[i]=-1;
}
while (num--){
cin>>a>>b>>weight;
edge edge1=edge(a,b,weight);
edges.push(edge1);
}
int sum=0;
int count=0;
while (!edges.empty()&&count<n-1){
edge temp=edges.top();
edges.pop();
int a=find(temp.a);
int b=find(temp.b);
int weight=temp.weight;
if (a!=b){
graph[a]=b;
count++;
sum+=weight;
}
}
cout<<sum<<endl;
}
return 0;
}

弗洛伊德

1
2
3
4
5
6
7
8
9
for (int k = 1;k <= n;k ++) { 
for (int i = 1;i <= n;i ++) {
for (int j = 1;j <= n;j ++) {
if (ans[i][k] == 无穷 || ans[k][j] == 无穷) continue;
if (ans[i][j] == 无穷 || ans[i][k] + ans[k][j] < ans[i][j])
ans[i][j] = ans[i][k] + ans[k][j];
}
}
}

迪杰斯特拉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
for (int i = 1;i <= n;i ++) { //初始化
Dis[i] = -1; //所有距离为-1,即不可达
mark[i] = false; //所有结点不属于集合K
}
Dis[1] = 0; //得到最近的点为结点1,长度为0
mark[1] = true; //将结点1加入集合K
int newP = 1; //集合K中新加入的点为结点1
for (int i = 1;i < n;i ++) { //循环n-1次,按照最短路径递增的顺序确定其他n-1个点的最短路径长度
for (int j = 0;j < edge[newP].size();j ++) { //遍历与该新加入集合
K中的结点直接相邻的边
int t = edge[newP][j].next; //该边的另一个结点
int c = edge[newP][j].c; //该边的长度
if (mark[t] == true) continue; //若另一个结点也属于集合K,则跳过
if (Dis[t] == - 1 || Dis[t] > Dis[newP] + c) //若该结点尚不可
达,或者该结点从新加入的结点经过一条边到达时比以往距离更短
Dis[t] = Dis[newP] + c; //更新其距离信息
}
int min = 123123123; //最小值初始化为一个大整数,为找最小值做准备
for (int j = 1;j <= n;j ++) { //遍历所有结点
if (mark[j] == true) continue; //若其属于集合K则跳过
if (Dis[j] == -1) continue; //若该结点仍不可达则跳过
if (Dis[j] < min) { //若该结点经由结点1至集合K中的某点在经过一条
边到达时距离小于当前最小值
min = Dis[j]; //更新其为最小值
newP = j; //新加入的点暂定为该点
}

欧拉回路(hierholzer)

(462条消息) 欧拉回路(hierholzer算法)_逐步插入回路法_run around的博客-CSDN博客

关键路径(AOE网)

最早开始时间=最晚开始时间

用拓扑图

最早开始时间(所有先序活动的最晚完成时间)

最晚开始时间(所有后续活动的最早开始时间减去该活动花费的时间)

注意源点的最早开始时间不一定为0,要初始化

汇点的最晚开始时间初始化为totalTime-该汇点任务的时间

非汇点的最晚开始时间为无穷

如果只是要求关键路径的长度,其实在earliest[i]初始化的时候就设置为任务的时间就行,但如果要算其他的,就还是设置为0

7 5
11 20 17 10 11 17 17
5 4
6 1
7 3
2 4
2 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <iostream>
#include <queue>
#include <vector>
#include <climits>
#define yushu 1e9+7
using namespace std;

queue<int>zero;
vector<int>re;
struct edge{
int to;
int weight;
};
int in[100001];
vector<edge>edges[100001];
int task[100001];
int earliest[100001];
int latest[100001];

int max(int a,int b){
return a>b?a:b;
}
int min(int a,int b){
return a<b?a:b;
}

int main(){
int n,m;
cin>>n>>m;
for (int i=1;i<=n;i++){
in[i]=0;
cin>>task[i];
}
int num=m;
int allTime=0;
cout<<"input edge"<<endl;
while (num--){
int a,b;
cin>>a>>b;
in[b]++;
edge temp;
temp.to=b;
temp.weight=task[b];
edges[a].push_back(temp);
}
cout<<"input finished."<<endl;
for (int i=1;i<=n;i++){
cout<<"earliest["<<i<<"]:"<<earliest[i]<<endl;
if (in[i]==0){
zero.push(i);


}
}
while (!zero.empty()){
int node=zero.front();
cout<<"zero:"<<node<<endl;
zero.pop();
re.push_back(node);
for (int i=0;i<edges[node].size();i++){
int to=edges[node][i].to;
int weight=edges[node][i].weight;
cout<<"edge:"<<node<<"-"<<to<<":"<<weight<<endl;
earliest[to]=max(earliest[to],earliest[node]+task[node]);
cout<<"earliest["<<to<<"]:"<<earliest[to]<<endl;
in[to]--;
if (in[to]==0){
zero.push(to);
}
}
}
for (int i=1;i<=n;i++){
allTime=max(allTime,earliest[i]+task[i]);
}
cout<<"reverse:"<<endl;
for (int i=re.size()-1;i>=0;i--){
int u=re[i];
if (edges[u].size()==0){
latest[u]=allTime-task[u];
cout<<"latest:["<<u<<"]:"<<latest[u]<<endl;
}else{
latest[u]=99999999;

}
for (int j=0;j<edges[u].size();j++){
int to=edges[u][j].to;
int weight=edges[u][j].weight;
latest[u]=min(latest[u],latest[to]-task[u]);
cout<<"latest:["<<u<<"]:"<<latest[u]<<endl;
}

}

cout<<endl;
for (int i=1;i<=n;i++){
cout<<"earliest["<<i<<"]:"<<earliest[i]<<endl;
cout<<"latest["<<i<<"]:"<<latest[i]<<endl;
}


int sum=1;

for (int i=1;i<=n;i++){
sum*=(latest[i]-earliest[i]+1);
}
cout<<allTime<<endl;
cout<<sum<<endl;
return 0;


}

(466条消息) AOE问题总结_DrCrypto的博客-CSDN博客

(466条消息) AOE网关键路径求解例题_关键路径例题图解_HardyDragon_CC的博客-CSDN博客

数位dp

(443条消息) 2019年南京大学计算机考研复试机试真题_南大计算机专业考研机试_yc_cy1999的博客-CSDN博客

一个整数可以变为多少个整数相加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N];//存所有状态
int main()
{
cin >> n;
f[0] = 1;
for (int i = 1; i <= n; i ++)
for(int j = i; j <= n; j ++)//j是容量
f[j] = (f[j] + f[j - i]) % mod;
cout << f[n] << endl;
return 0;
}

状压DP

(462条消息) 291. 蒙德里安的梦想(状压dp)_seez的博客-CSDN博客

[(462条消息) 状压dp] 蒙德里安的梦想(模板题+状压dp)_状压dp模板题_Ypuyu的博客-CSDN博客

(462条消息) C++笔试题模版汇总(五)动态规划/贪心_c++笔试题 考动态规划么_ai_XZP_master的博客-CSDN博客

状态压缩DP学习总结+经典例题精解_状压dp-CSDN博客

汉诺塔问题

结论:把i个盘子移到另一个柱面上,需要2^i-1步

关于汉诺塔问题 - 知乎 (zhihu.com)

放置街灯(Placing Lampposts, UVa 10859):star:

image-20230515221130204

经典贪心

(450条消息) UVA-10382经典贪心问题,区间覆盖_uva 10382_KXL5180的博客-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//酸奶工程
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//定义long long,防止爆int
ll n,s;
ll c[10010],y[10010];//存储费用和交互数量
ll f[10010];
ll sum=0;
int main(){
scanf("%lld%lld",&n,&s);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&c[i],&y[i]);
}
for(int i=1;i<=n;i++){
if(i==1){
f[i]=c[i];
}
else{
f[i]=min(c[i],f[i-1]+s);
}
sum=sum+f[i]*y[i];
}
printf("%lld",sum);
}

跳跃问题

(462条消息) Leetcode——跳跃问题II_跳跃问题2_Purple.''的博客-CSDN博客

分发糖果

(462条消息) 「leetcode」135.分发糖果【贪心算法】详细图解_代码随想录的博客-CSDN博客

线段树

(462条消息) 线段树 从入门到进阶(超清晰,简单易懂)_线段树进阶_繁凡さん的博客-CSDN博客

匈牙利算法

(462条消息) 匈牙利算法详解_Amelie_xiao的博客-CSDN博客

一个二分图中的最大匹配数等于这个图中的最小点覆盖数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int M, N;            //M, N分别表示左、右侧集合的元素数量
int Map[MAXM][MAXN]; //邻接矩阵存图
int p[MAXN]; //记录当前右侧元素所对应的左侧元素
bool vis[MAXN]; //记录右侧元素是否已被访问过
bool match(int i)
{
for (int j = 1; j <= N; ++j)
if (Map[i][j] && !vis[j]) //有边且未访问
{
vis[j] = true; //记录状态为访问过
if (p[j] == 0 || match(p[j])) //如果暂无匹配,或者原来匹配的左侧元素可以找到新的匹配
{
p[j] = i; //当前左侧元素成为当前右侧元素的新匹配
return true; //返回匹配成功
}
}
return false; //循环结束,仍未找到匹配,返回匹配失败
}
int Hungarian()
{
int cnt = 0;
for (int i = 1; i <= M; ++i)
{
memset(vis, 0, sizeof(vis)); //重置vis数组
if (match(i))
cnt++;
}
return cnt;
}

回溯

[(462条消息) 2018南京大学计算机夏令营机试第二题(回溯)_只会写臭虫的博客-CSDN博客](https://blog.csdn.net/weixin_43175029/article/details/94670710?ops_request_misc=&request_id=&biz_id=102&utm_term=Missing number Given a positi&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-94670710.142^v88^control_2,239^v2^insert_chatgpt&spm=1018.2226.3001.4187)

回溯就是dfs,并且在每次dfs时记得恢复原状态;如果只需要输出一种状态,设置flag标志位

N皇后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
using namespace std;
const int N = 20;

// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径

int n;
char g[N][N];
bool col[N], dg[N], udg[N];

void dfs(int u) {
// u == n 表示已经搜了n行,故输出这条路径
if (u == n) {
for (int i = 0; i < n; i ++ ) puts(g[i]); // 等价于cout << g[i] << endl;
puts(""); // 换行
return;
}

// 枚举u这一行,搜索合法的列
int x = u;
for (int y = 0; y < n; y ++ )
// 剪枝(对于不满足要求的点,不再继续往下搜索)
// 这里y-x+n是左上角到右下角,y+x是左下角到右上角
if (col[y] == false && dg[y - x + n] == false && udg[y + x] == false) {
col[y] = dg[y - x + n] = udg[y + x] = true;
g[x][y] = 'Q';
dfs(x + 1);
g[x][y] = '.'; // 恢复现场
col[y] = dg[y - x + n] = udg[y + x] = false;
}
}

int main() {
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = '.';

dfs(0);

return 0;
}

建立索引树

[(462条消息) 2020北航计算机夏令营机试题目个人理解_北航夏令营 机试_四处碰壁嘤嘤怪的博客-CSDN博客](https://blog.csdn.net/Bernie_double/article/details/118190022?ops_request_misc={"request_id"%3A"168715279416800185829257"%2C"scm"%3A"20140713.130102334.."}&request_id=168715279416800185829257&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-118190022-null-null.142^v88^control_2,239^v2^insert_chatgpt&utm_term=北航夏令营 机试&spm=1018.2226.3001.4187)

注意 建树不一定要指针,数组也可

4 5
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

hot 100+面试经典150

12.13-12.14

88. 合并两个有序数组 :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int tail1=m-1;
int tail2=n-1;
int tail=m+n-1;
while(tail1>=0||tail2>=0){
if (tail1==-1){
nums1[tail]=nums2[tail2];
tail2--;
}else if (tail2==-1){
nums1[tail]=nums1[tail1];
tail1--;
}else if (nums1[tail1]>=nums2[tail2]){
nums1[tail]=nums1[tail1];
tail1--;
}else if(nums1[tail1]<nums2[tail2]){
nums1[tail]=nums2[tail2];
tail2--;
}
tail--;
}
return ;
}
};

27. 移除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int k = 0; // 记录不等于 val 的元素数量

for (int i = 0; i < nums.size(); i++) {
if (nums[i] != val) {
nums[k] = nums[i]; // 将不等于 val 的元素移到前面
k++; // 增加计数
}
// 如果等于 val,就跳过,不处理
}

return k; // 返回不等于 val 的元素数量
}
};

80. 删除有序数组中的重复项 II :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int size = nums.size();
if (size<=2){
return size;
}
int slow=2;
int fast=2;
while(fast<size){
if (nums[slow-2]!=nums[fast]){
nums[slow]=nums[fast];
slow++;
}
fast++;
}
return slow;
}
};

169. 多数元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int majorityElement(vector<int>& nums) {
int size=nums.size();
map<int,int>mapping;
for (int num : nums){
mapping[num]+=1;
if (mapping[num]>size/2){
return num;
}
}
return 0;
}
};

189. 轮转数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k = k%nums.size();
if (k==0){
return;
}
vector<int>temp;
for (int i=nums.size()-k;i<nums.size();i++){
temp.push_back(nums[i]);
}
int start = nums.size()-k-1;
int i = nums.size()-1;
while(start>=0){
nums[i]=nums[start];
start--;
i--;
}
for (int i=0;i<k;i++){
nums[i]=temp[i];
}
return ;
}
};

121. 买卖股票的最佳时机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size()==1){
return 0;
}
const int size = prices.size();
int max_num=0;
int ans=0;
for (int i=prices.size()-1;i>=0;i--){
if (prices[i]>max_num){
max_num=prices[i];
}
if (i>=1){
if (max_num-prices[i-1]>ans){
ans = max_num-prices[i-1];
}
}

}
return ans;
}
};

122. 买卖股票的最佳时机 II :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int maxProfit(vector<int>& prices) {
int size = prices.size();
if (size==1){
return 0;
}
int dp[size][2];
dp[0][1]=-prices[0];
dp[0][0]=0;
for (int i=1;i<size;i++){
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
}
return dp[size-1][0];
}
};

55. 跳跃游戏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
bool canJump(vector<int>& nums) {
int size = nums.size();
vector<bool> reach(size,false);
reach[0]=true;
for (int i=0;i<size;i++){
if (reach[i]){
int maxJump = min(i + nums[i], size - 1);
for (int j=i;j<=maxJump;j++){
reach[j]=true;
}
}
}
return reach[size-1];
}
};

45. 跳跃游戏 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int jump(vector<int>& nums) {
int size =nums.size();
vector<bool>reach(size,false);
reach[0]=true;
vector<int>dp(size,size);
dp[0]=0;
for (int i=0;i<size;i++){
if (reach[i]){
int max_jump = min(size-1,i+nums[i]);
for (int j=i;j<=max_jump;j++){
reach[j]=true;
dp[j]=min(dp[j],dp[i]+1);
}
}
}
return dp[size-1];
}
};

274. H 指数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int hIndex(vector<int>& citations) {
int count[1000+1]={0};
for (int num: citations){
count[num]++;
}
int suffix_sum[1001]={0};

for (int i=1000;i>=0;i--){
if (i==1000){
suffix_sum[i]=count[i];
}else{
suffix_sum[i]=count[i]+suffix_sum[i+1];
}

if (suffix_sum[i]>=i){
return i;
}
}
return 0;
}
};

380. O(1) 时间插入、删除和获取随机元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class RandomizedSet {
public:
RandomizedSet() {
// 可选:添加随机种子初始化
// srand(time(NULL));
}

bool insert(int val) {
if (indexs.count(val) == 1){
return false;
}
nums.push_back(val);
indexs[val] = nums.size() - 1;
return true;
}

bool remove(int val) {
if (!indexs.count(val)){
return false;
}
int index = indexs[val];
int last = nums.back();

// 移动最后一个元素到要删除的位置
nums[index] = last;
nums.pop_back();

// 更新被移动元素的索引
indexs[last] = index;

// 删除要移除元素的索引
indexs.erase(val);

return true;
}

int getRandom() {
int index = rand() % nums.size();
return nums[index];
}

private:
vector<int> nums;
unordered_map<int, int> indexs;
};

238. 除自身以外数组的乘积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int size=nums.size();
vector<int>left(size+1,0);
vector<int>right(size+1,0);
left[0]=1;
right[size]=1;
for (int i=0;i<size;i++){
left[i+1]=left[i]*nums[i];
}
for (int i=size-1;i>=0;i--){
right[i]=right[i+1]*nums[i];
}
vector<int>ans(size,0);
for (int i=0;i<size;i++){
ans[i]=left[i]*right[i+1];
}
return ans;
}
};

134. 加油站 :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int n = gas.size();
int i = 0;
while (i < n) {
int sumOfGas = 0, sumOfCost = 0;
int cnt = 0;
while (cnt < n) {
int j = (i + cnt) % n;
sumOfGas += gas[j];
sumOfCost += cost[j];
if (sumOfCost > sumOfGas) {
break;
}
cnt++;
}
if (cnt == n) {
return i;
} else {
i = i + cnt + 1;
}
}
return -1;
}
};

135. 分发糖果 :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size();
int pre = 1;
int ans = 1;
int inc =1;
int dec = 0;
for (int i=1;i<n;i++){
if (ratings[i]>ratings[i-1]){
pre = pre+1;
ans +=pre;
inc = pre;
dec =0;
}else if(ratings[i]==ratings[i-1]){
pre =1;
ans+=pre;
inc=pre;
dec =0;
}else{
dec++;
if (dec==inc){
dec++;
}
ans +=dec;
pre = 1;
}
}
return ans;

}
};

42. 接雨水

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int trap(vector<int>& height) {
int size = height.size();
vector<int>left_max(size,0);
vector<int>right_max(size,0);
for (int i=1;i<size;i++){
left_max[i]=max(left_max[i-1],height[i-1]);
}
for (int i=size-2;i>=0;i--){
right_max[i]=max(right_max[i+1],height[i+1]);
}
int ans=0;
for (int i=0;i<size;i++){
ans+=max(0,(min(left_max[i],right_max[i])-height[i]));
}
return ans;
}
};

13. 罗马数字转整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
private:
map<char,int>mapping={
{'I',1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans =0;
int size = s.size();
for (int i=0;i<size;i++){
int v = mapping[s[i]];
if (i<size-1&&v<mapping[s[i+1]]){
ans-=v;
}else{
ans+=v;
}
}
return ans;
}
};

12. 整数转罗马数字 :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const pair<int,string>mapping[]={
{1000, "M"},
{900, "CM"},
{500, "D"},
{400, "CD"},
{100, "C"},
{90, "XC"},
{50, "L"},
{40, "XL"},
{10, "X"},
{9, "IX"},
{5, "V"},
{4, "IV"},
{1, "I"},
};
class Solution {

public:
string intToRoman(int num) {
string ans;
for (const auto & [k,v]: mapping){
while(num>=k){
num-=k;
ans+=v;
}
if (num==0){
break;
}
}
return ans;
}
};

14. 最长公共前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (strs.size()==0){
return "";
}
int length =1;
string ans="";
while(1){
// 检查第一个字符串长度
if (length > strs[0].size()) {
return ans;
}

string prefix = strs[0].substr(0, length);
bool match = true;

// 检查其他字符串
for (int i = 1; i < strs.size(); i++) {
// 检查长度是否足够
if (length > strs[i].size() ||
strs[i].substr(0, length) != prefix) {
match = false;
break;
}
}

if (match) {
ans = prefix; // 更新答案
length++;
} else {
break; // 不匹配时退出
}


}
return ans;

}
};

58. 最后一个单词的长度

这里c++很不好做,Python两行搞定

1
2
3
4
5
class Solution:
def lengthOfLastWord(self, s: str) -> int:
ss = s.split()
return len(ss[len(ss)-1])

这里的s.split是默认去掉所有空格

151. 反转字符串中的单词

依旧python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def reverseWords(self, s: str) -> str:
ss = s.split()
ss.reverse()
ans=""
for i,s in enumerate(ss):
if i==len(ss)-1:
ans=ans+s
else:
ans=ans+s+" "
return ans

# 或者下面这样
class Solution:
def reverseWords(self, s: str) -> str:
ss = s.split()
ss.reverse()
return " ".join(ss)

6. Z 字形变换 :star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
string convert(string s, int numRows) {
if (numRows==1){
return s;
}
vector<string>ss(numRows);
int i=0;
int flag=-1;
for (char c : s){
ss[i].push_back(c);
if (i==0 || i==numRows-1){
flag=-flag;
}
i=i+flag;
}
string ans="";
for (string temp: ss){
ans+=temp;
}
return ans;

}};

std::string 是字符容器

  • std::string 本质上是一个存储 char 类型的容器
  • 它提供了类似于 std::vector<char> 的接口
1
2
3
4
// 以下是等价的:
ss[i].push_back(c); // 方法1:使用 push_back
ss[i] += c; // 方法2:使用 += 操作符
ss[i].append(1, c); // 方法3:使用 append

但字符不能直接跟字符拼接

28. 找出字符串中第一个匹配项的下标

1
2
3
4
5
6
class Solution {
public:
int strStr(string haystack, string needle) {
return haystack.find(needle);
}
};

68. 文本左右对齐 :star:

原来string初始化能直接string(length,char)的吗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Solution {
// blank 返回长度为 n 的由空格组成的字符串
string blank(int n) {
return string(n, ' ');
}

// join 返回用 sep 拼接 [left, right) 范围内的 words 组成的字符串
string join(vector<string> &words, int left, int right, string sep) {
string s = words[left];
for (int i = left + 1; i < right; ++i) {
s += sep + words[i];
}
return s;
}

public:
vector<string> fullJustify(vector<string> &words, int maxWidth) {
vector<string> ans;
int right = 0, n = words.size();
while (true) {
int left = right; // 当前行的第一个单词在 words 的位置
int sumLen = 0; // 统计这一行单词长度之和
// 循环确定当前行可以放多少单词,注意单词之间应至少有一个空格
while (right < n && sumLen + words[right].length() + right - left <= maxWidth) {
sumLen += words[right++].length();
}

// 当前行是最后一行:单词左对齐,且单词之间应只有一个空格,在行末填充剩余空格
if (right == n) {
string s = join(words, left, n, " ");
ans.emplace_back(s + blank(maxWidth - s.length()));
return ans;
}

int numWords = right - left;
int numSpaces = maxWidth - sumLen;

// 当前行只有一个单词:该单词左对齐,在行末填充剩余空格
if (numWords == 1) {
ans.emplace_back(words[left] + blank(numSpaces));
continue;
}

// 当前行不只一个单词
int avgSpaces = numSpaces / (numWords - 1);
int extraSpaces = numSpaces % (numWords - 1);
string s1 = join(words, left, left + extraSpaces + 1, blank(avgSpaces + 1)); // 拼接额外加一个空格的单词
string s2 = join(words, left + extraSpaces + 1, right, blank(avgSpaces)); // 拼接其余单词
ans.emplace_back(s1 + blank(avgSpaces) + s2);
}
}
};

这种模拟题就纯恶心来着

125. 验证回文串

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
bool isPalindrome(string s) {
string sgood;
for (char ch: s) {
if (isalnum(ch)) { // 检查是字母/数字
sgood += tolower(ch);
}
}
string sgood_rev(sgood.rbegin(), sgood.rend());
return sgood == sgood_rev;
}
};

392. 判断子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool isSubsequence(string s, string t) {
int m = s.size();
int n = t.size();
int j=0;
for (int i=0;i<n;i++){
if (s[j]==t[i]){
j++;
}
}
return j==m;
}
};

167. 两数之和 II - 输入有序数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
map<int,int>mapping;
vector<int>ans;
for (int i=0;i<numbers.size();i++){
if (mapping.count(target-numbers[i])!=0){
if (mapping[target-numbers[i]]!=i){
ans.push_back(mapping[target-numbers[i]]+1);
ans.push_back(i+1);
return ans;
}
}
mapping[numbers[i]]=i;
}
return ans;
}
};

11. 盛最多水的容器:star:

这里注意数据范围,暴力必定超时,直接双指针就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int maxArea(vector<int>& height) {
int size = height.size();
int left = 0;
int right = size-1;
int ans=0;
while(left<right){
ans = max(ans,(right-left)*min(height[left],height[right]));
if (height[left]<height[right]){
left++;
}else{
right--;
}
}
return ans;
}
};

15. 三数之和

这里注意先排序,且在遍历的时候要筛重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
sort(nums.begin(),nums.end());
vector<vector<int>>ans;
for (int first=0;first<size;first++){
if (first>0&&nums[first]==nums[first-1]){
continue;
}
int third=size-1;
int target = -nums[first];
for (int second=first+1;second<size;second++){
if (second>first+1 && nums[second]==nums[second-1]){
continue;
}
while(second<third&&nums[second]+nums[third]>target){
third--;
}
if (second==third){
break;
}
if (nums[second]+nums[third]==target){
ans.push_back({nums[first],nums[second],nums[third]});
}
}
}
return ans;

}
};

209. 长度最小的子数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int size = nums.size();
vector<int> prefix_sum(size+1,0);
for (int i=1;i<=size;i++){
prefix_sum[i]+=prefix_sum[i-1]+nums[i-1];
}

int slow=0,fast=1;
int ans = size+1;
while(fast<=size){
if (prefix_sum[fast]-prefix_sum[slow]>=target){
ans = min(ans,fast-slow);
slow++;
}else{
fast++;
}
}
if (ans==size+1){
return 0;
}
return ans;
}
};

3. 无重复字符的最长子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int lengthOfLongestSubstring(string s) {
map<char,int>mapping;
int slow =0;
int fast=0;
int size =s.size();
int ans = 0;
while(fast<size){
if (mapping.count(s[fast])==0){
mapping[s[fast]]=1;
fast++;
ans = max(ans,fast-slow);
}else{
while(s[slow]!=s[fast]){
mapping.erase(s[slow]);
slow++;
}
mapping.erase(s[slow]);
slow++;
}
}
return ans;
}
};

12.15

30. 串联所有单词的子串 :star:

滑动窗口挺有意思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
int size = words.size();
int length = s.size();
int word_size = words[0].size();
vector<int>ans;
for (int i=0;i<word_size&&i+size*word_size<=length;i++){
map<string,int>mapping;
for (int j=0;j<size;j++){
mapping[s.substr(i+j*word_size,word_size)]++;
}
for (string word : words){
mapping[word]--;
if (mapping[word]==0){
mapping.erase(word);
}
}
for (int start=i;start<length-size*word_size+1;start+=word_size){
if (start!=i){
string temp=s.substr(start-word_size,word_size);
if (--mapping[temp]==0){
mapping.erase(temp);
}
temp = s.substr(start+word_size*(size-1),word_size);
if (++mapping[temp]==0){
mapping.erase(temp);
}
}
if (mapping.empty()){
ans.push_back(start);
}
}
}
return ans;
}
};

76. 最小覆盖子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int>mapping_t;
unordered_map<char,int>current;
for (char c : t){
mapping_t[c]+=1;
}
int length = s.size()+1;
int l=0;
int r=0;
int ans_l=-1;
while(r<s.size()){
if (mapping_t.find(s[r])!=mapping_t.end()){
current[s[r]]++;
}
while(check_ok(mapping_t,current)&&l<=r){
if (r-l+1<length){
length=r-l+1;
ans_l=l;
}
if (mapping_t.find(s[l])!=mapping_t.end()){
current[s[l]]--;
}
l++;
}
r++;
}
if (length==s.size()+1){
return "";
}
return s.substr(ans_l,length);
}
bool check_ok(unordered_map<char,int> t,unordered_map<char,int> current){
for (auto [k,v]:t){
if (current[k]<v){
return false;
}
}
return true;
}
};

12.16

36. 有效的数独

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector<vector<int>>rows(9,vector<int>(9,0));
vector<vector<int>>cols(9,vector<int>(9,0));
vector<vector<vector<int>>>kuang(3,vector<vector<int>>(3,vector<int>(9,0)));
for (int i=0;i<9;i++){
for(int j=0;j<9;j++){
if (board[i][j]!='.'){
int index = board[i][j]-'0'-1;
rows[i][index]+=1;
cols[j][index]+=1;
kuang[i/3][j/3][index]+=1;
if (rows[i][index]>1||cols[j][index]>1||kuang[i/3][j/3][index]>1){
return false;
}
}
}
}
return true;

}
};

这里另一种方式是

1
2
3
4
5
6
7
int rows[9][9];
int columns[9][9];
int subboxes[3][3][9];

memset(rows,0,sizeof(rows));
memset(columns,0,sizeof(columns));
memset(subboxes,0,sizeof(subboxes));

54. 螺旋矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<vector<bool>>visited(m,vector<bool>(n,false));
vector<int>ans;
int step=0;
int total=m*n;
int direction=0;

map<int, vector<int>> mapping = {
{0, {0, 1}},
{1, {1, 0}},
{2, {0, -1}},
{3, {-1, 0}}
};

int current_x=0;
int current_y=0;
while(step<total){
ans.push_back(matrix[current_x][current_y]);
visited[current_x][current_y]=true;
step++;
if (direction==0&&(current_y==n-1||visited[current_x][current_y+1])){
direction=1;
}else if (direction==1&&(current_x==m-1||visited[current_x+1][current_y])){
direction=2;
}else if(direction==2&&(current_y==0||visited[current_x][current_y-1])){
direction=3;
}else if (direction==3&&(current_x==0||visited[current_x-1][current_y])){
direction=0;
}
current_x+=mapping[direction][0];
current_y+=mapping[direction][1];
}
return ans;
}
};

这里注意mapping中的vector初始化是{}

在 C++ 中,初始化 vectormaparray 等容器,请始终使用 {},而不是 []
[] 只用于访问元素(如 vec[0]),不能用于初始化

48. 旋转图像:star:

倒不是说有多难,就是找准位置关系,水平翻转+对角线翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// 水平翻转
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
swap(matrix[i][j], matrix[n - i - 1][j]);
}
}
// 主对角线翻转
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};

12.17

73. 矩阵置零

有点过于简单了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m=matrix.size();
int n=matrix[0].size();
vector<pair<int,int>>zeros;
for (int i = 0;i<m;i++){
for (int j=0;j<n;j++){
if (matrix[i][j]==0){
zeros.push_back(pair<int,int>(i,j));
}
}
}
for (auto [i,j]:zeros){
setZero(i,j,matrix);
}
return;
}
void setZero(int i,int j,vector<vector<int>>& matrix){
int m=matrix.size();
int n=matrix[0].size();
for (int q=0;q<m;q++){
matrix[q][j]=0;
}
for (int p=0;p<n;p++){
matrix[i][p]=0;
}
return;
}
};

289. 生命游戏

ez

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int m=board.size();
int n= board[0].size();
vector<vector<int>>state(m,vector<int>(n,0));
for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
int live_count=count_live(i,j,board);
if (board[i][j]){
if (live_count<2||live_count>3){
state[i][j]=0;
}else{
state[i][j]=1;
}
}else{
if (live_count==3){
state[i][j]=1;
}
}
}
}
for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
board[i][j]=state[i][j];
}
}

}
int count_live(int i,int j,vector<vector<int>>& board){
int ans=0;
int m=board.size();
int n= board[0].size();
if (i>0)
ans+=board[i-1][j];
if (i>0&&j>0)
ans+=board[i-1][j-1];
if (i>0&&j<n-1)
ans+=board[i-1][j+1];
if (i<m-1&&j>0)
ans+=board[i+1][j-1];
if (i<m-1&&j<n-1)
ans+=board[i+1][j+1];
if (i<m-1)
ans+=board[i+1][j];
if (j>0)
ans+=board[i][j-1];
if (j<n-1)
ans+=board[i][j+1];
return ans;
}

};

12.19

383. 赎金信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
map<char,int>m1;
map<char,int>m2;
for (char c : ransomNote){
m1[c]++;
}
for (char c: magazine){
m2[c]++;
}
for (auto [k,v]: m1){
if (m2[k]<v){
return false;
}
}
return true;
}
};

205. 同构字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
bool isIsomorphic(string s, string t) {
map<char,char>mapping1;
map<char,char>mapping2;
for (int i=0;i<s.size();i++){
if (mapping1.count(s[i])==0&&mapping2.count(t[i])==0){
mapping1[s[i]]=t[i];
mapping2[t[i]]=s[i];
}else if(mapping1[s[i]]!=t[i]||mapping2[t[i]]!=s[i]){
return false;
}
}
return true;
}
};

290. 单词规律

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
s_list = s.split()

# 长度不匹配直接返回False
if len(pattern) != len(s_list):
return False

mapping1 = {} # pattern -> word
mapping2 = {} # word -> pattern

for i in range(len(pattern)):
p = pattern[i]
w = s_list[i]

# 检查双向映射是否一致
if p in mapping1:
if mapping1[p] != w:
return False
else:
mapping1[p] = w

if w in mapping2:
if mapping2[w] != p:
return False
else:
mapping2[w] = p

return True

242. 有效的字母异位词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
bool isAnagram(string s, string t) {
int len1 = s.size();
int len2 = t.size();
if (len1 != len2){
return false;
}
map<char,int>mapping1;
map<char,int>mapping2;
for (char c: s){
mapping1[c]++;
}
for (char c:t){
mapping2[c]++;
}
for (auto [k,v]: mapping1){
if (mapping2[k]!=v){
return false;
}
}
return true;
}
};,

49. 字母异位词分组:star:

这波属于是要sort(str.begin(),str.end());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdlib.h>

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std;

vector<vector<string>> groupAnagrams(vector<string>& strs) {
map<string, vector<string>> mapSet;
vector<vector<string>> ans;
// 添加
for (string s : strs) {
string temp = s;
sort(temp.begin(), temp.end());
if (mapSet.find(temp) != mapSet.end()) {
mapSet[temp].push_back(s);
} else {
mapSet[temp] = vector<string>{s};
}
}
// 遍历map,以key作为一个list
for (auto item = mapSet.begin(); item != mapSet.end(); item++) {
ans.push_back(item->second);
}
return ans;
}

// 添加函数来打印结果
void printResult(const vector<vector<string>>& result) {
cout << "[";
for (size_t i = 0; i < result.size(); ++i) {
if (i > 0) cout << ",";
cout << "[";
for (size_t j = 0; j < result[i].size(); ++j) {
if (j > 0) cout << ",";
cout << "\"" << result[i][j] << "\"";
}
cout << "]";
}
cout << "]" << endl;
}

int main() {
vector<string> list = {"eat", "tea", "tan", "ate", "nat", "bat"};
vector<vector<string>> ans = groupAnagrams(list);
printResult(ans); // 使用自定义函数打印
return 0;
}

1. 两数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>ans;
map<int,int>map_index;
int length = nums.size();
for (int i=0;i<length;i++){
if (map_index.count(target-nums[i])!=0){
ans.push_back(i);
ans.push_back(map_index[target-nums[i]]);
return ans;
}else{
map_index[nums[i]]=i;
}
}
return ans;
}
};

202. 快乐数:star:

这真的简单吗?我嘞个快慢指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
bool isHappy(int n) {
int slow=n;
int fast =n;
bool flag=false;
while(slow!=1&&fast!=1){
if (flag){
if (slow==fast){
return false;
}
}
flag=true;
slow=compute_n(slow);
fast=compute_n(fast);
fast=compute_n(fast);
}
return true;
}
int compute_n(int n){
int res=0;
while(n>0){
int temp = n%10;
res+=temp*temp;
n/=10;
}
return res;
}
};

219. 存在重复元素 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
map<int,int>mapping;
int length = nums.size();
for (int i=0;i<length;i++){
if (mapping.count(nums[i])!=0){
if (abs(mapping[nums[i]]-i)<=k){
return true;
}
}
mapping[nums[i]]=i;
}
return false;
}

int abs(int a){
if (a<0){
return -a;
}
return a;
}

};

128. 最长连续序列

注意set的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int ans=0;
unordered_set<int>us;
for (auto num:nums){
us.insert(num);
}

for (auto num: us){
if (us.count(num-1)==0){
int cn=num;
int len=1;
while(us.count(cn+1)){
cn++;
len++;
}
ans = max(ans,len);
}
}
return ans;
}
int max(int a,int b){
if (a>b){
return a;
}
return b;
}
};

12.20

228. 汇总区间

注意to_string,数字转字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string>ans;
int slow=0;
int fast=0;
int length = nums.size();
while(fast<length&&fast>=slow){
if (fast+1<length){
if (nums[fast]+1==nums[fast+1]){
fast++;
continue;
}else{
if (fast==slow){
string temp = to_string(nums[fast]);
ans.push_back(temp);
fast++;
slow++;
}else{
string s1 = to_string(nums[slow]);
string s2 = to_string(nums[fast]);
string temp = s1+"->"+s2;
ans.push_back(temp);
fast++;
slow=fast;
}
}
}else{
if (fast==slow){
string temp = to_string(nums[fast]);
ans.push_back(temp);
}else{
string s1 = to_string(nums[slow]);
string s2 = to_string(nums[fast]);
string temp = s1+"->"+s2;
ans.push_back(temp);
}
break;
}

}

return ans;
}
};

56. 合并区间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int max_num = -INT_MAX;
int size = intervals.size();
if (size ==1){
return intervals;
}
// 这里直接按照字典序进行排序
sort(intervals.begin(),intervals.end());
vector<vector<int>>ans;
int slow=0;
int fast=0;
max_num=intervals[0][1];
while(fast<size&&fast>=slow){
if (intervals[fast][0]<=max_num){
max_num = max(max_num,intervals[fast][1]);
fast++;
continue;
}else{
int num1 = intervals[slow][0];
vector<int>temp={num1,max_num};
ans.push_back(temp);
slow=fast;
max_num=intervals[fast][1];
}
}
vector<int>temp = {intervals[slow][0],max_num};
ans.push_back(temp);
return ans;
}
};

452. 用最少数量的箭引爆气球

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
// 按照右边界排序
sort(points.begin(),points.end(),[](vector<int>a,vector<int>b){
return a[1]<b[1];
});
int length = points.size();
if (length==1){
return 1;
}
int ans =0;
int slow =0,fast= 0;
while(fast<length&&fast>=slow){
if (points[fast][0]<=points[slow][1]){
fast++;
}else{
ans++;
slow=fast;
}
}
ans++;
return ans;

}
};

57. 插入区间

没啥好说的,约等于合并区间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>>ans;
intervals.push_back(newInterval);
sort(intervals.begin(),intervals.end());
int slow=0;
int fast =0;
int size=intervals.size();
if (size==1){
return intervals;
}
int max_right = intervals[0][1];
while(fast>=slow&&fast<size){
if (max_right>=intervals[fast][0]){
max_right=max(max_right,intervals[fast][1]);
fast++;
}else{
vector<int>temp = {intervals[slow][0],max_right};
ans.push_back(temp);
max_right = intervals[fast][1];
slow=fast;
}
}
vector<int>temp = {intervals[slow][0],max_right};
ans.push_back(temp);
return ans;
}
};

20. 有效的括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
bool isValid(string s) {
stack<char>c_stack;
for (char c:s){
if (c=='('||c=='{'||c=='['){
c_stack.push(c);
}else{
if (c==')'){
if (c_stack.empty()||c_stack.top()!='('){
return false;
}else{
c_stack.pop();
}
}else if (c=='}'){
if (c_stack.empty()||c_stack.top()!='{'){
return false;
}else{
c_stack.pop();
}
}else if (c==']'){
if (c_stack.empty()||c_stack.top()!='['){
return false;
}else{
c_stack.pop();
}
}
}
}
return c_stack.size()==0;
}
};

71. 简化路径:star:

自己写的逻辑还是太复杂了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
string simplifyPath(string path) {
string ans;
int index = 0;
string dir = "";
vector<string> st;
path += '/';
while(index < path.size()){
char& ch = path[index];
if(ch != '/'){
dir += ch;
index++;
continue;
}
else if(dir == ".." && !st.empty()){
st.pop_back();
}
else if(dir != ".." && dir != "." && dir != ""){
st.push_back(dir);
}
dir = "";
index++;
}

for(auto& dir : st){
ans += '/';
ans += dir;
}

return ans == "" ? "/" : ans;

}
};

155. 最小栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MinStack {
stack<int>s;
stack<int>min_s;
public:
MinStack() {
min_s.push(INT_MAX);
}

void push(int val) {
s.push(val);
min_s.push(min(min_s.top(),val));
}

void pop() {
s.pop();
min_s.pop();
}

int top() {
return s.top();
}

int getMin() {
return min_s.top();
}
};

/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/

150. 逆波兰表达式求值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int>num_s;
for (string token: tokens){
if (token != "+" && token != "-" && token != "*" && token != "/" ){
int num = stoi(token);
num_s.push(num);
}else{
int num1 = num_s.top();
num_s.pop();
int num2 = num_s.top();
num_s.pop();
if (token=="/"){
int temp = num2/num1;
num_s.push(temp);
}else if(token=="+"){
int temp = num2+num1;
num_s.push(temp);
}else if(token=="-"){
int temp = num2-num1;
num_s.push(temp);
}else{
int temp = num2*num1;
num_s.push(temp);
}
}
}
return num_s.top();
}
};

224. 基本计算器 :star:

妈的这里只有+和-,用信号转化的方式还是没太容易想到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
int calculate(string s) {
int sig = 1;
int ans=0;
stack<int>ops;
ops.push(1);
int size = s.size();
for (int i =0;i<size;i++){
char c = s[i];
if (c==' '){
continue;
}
if (c=='+'){
sig=ops.top();
}else if (c=='-'){
sig = -ops.top();
}else if (c=='('){
ops.push(sig);
}else if (c==')'){
ops.pop();
}else{
long num = 0;
while (i<size&&s[i]-'0'<=9&&s[i]-'0'>=0){
num = num*10+(s[i]-'0');
i++;
}
i--;
ans+=sig*num;
}
}
return ans;
}
};

141. 环形链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if (head == NULL || head->next == NULL){
return false;
}
ListNode *fast = head->next;
ListNode *slow = head;
while(fast!=NULL){
if (fast==slow){
return true;
}
fast = fast->next;
if (fast==NULL){
return false;
}
fast = fast->next;
slow = slow->next;
}
return false;
}
};

2. 两数相加

这里注意

  1. 结构体指针取当中的值用->
  2. 根据其构造函数创建新的结构体用new e.g. new ListNode(10);
  3. ListNode(): val(0),next(nullptr) {}
  4. ListNode(int x): val(x), next(nullptr) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* c1 = l1;
ListNode* c2 = l2;
int pre=0;
ListNode* ans = NULL;
ListNode* tail =NULL;
while (c1 !=NULL || c2 != NULL){
int cur = 0;
if (c1){
cur +=c1->val;
c1=c1->next;
}
if (c2){
cur += c2->val;
c2=c2->next;
}
cur+=pre;
pre = cur/10;
if (ans == NULL){
ans =new ListNode(cur%10);
tail = ans;
}else{
tail->next =new ListNode(cur%10);
tail=tail->next;
}
}
if (pre>0){
tail->next =new ListNode(pre);
}
return ans;
}

};

21. 合并两个有序链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
// 使用虚拟头节点简化操作
ListNode* dummy = new ListNode(-1);
ListNode* tail = dummy;

// 同时遍历两个链表
while (list1 != nullptr && list2 != nullptr) {
if (list1->val <= list2->val) {
tail->next = list1;
list1 = list1->next;
} else {
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}

// 处理剩余节点
tail->next = (list1 != nullptr) ? list1 : list2;

ListNode* result = dummy->next;
delete dummy; // 释放虚拟头节点
return result;
}
};

138. 随机链表的复制:star:

这题有点意思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;

Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/

class Solution {
public:
Node* copyRandomList(Node* head) {
if (head==NULL){
return NULL;
}
map<Node*,Node*>mapping;
Node* cur =head;
while (cur !=NULL){
Node *temp = new Node(cur->val);
mapping[cur]=temp;
cur=cur->next;
}
cur = head;
while (cur!=NULL){
Node * map_cur = mapping[cur];
map_cur->random = mapping[cur->random];
map_cur->next = mapping[cur->next];
cur=cur->next;
}
return mapping[head];
}
};

LCR 024. 反转链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur){
ListNode* next = cur->next;
cur->next = pre;
pre=cur;
cur=next;
}
return pre;
}
};

92. 反转链表 II

用vector的解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
vector<ListNode*>ns;
ListNode*cur =head;
ListNode*dump = new ListNode(-1);
ns.push_back(dump);
dump->next = head;
while (cur !=NULL){
ns.push_back(cur);
cur= cur->next;
}
for (int i=left;i<right;i++){
ns[i+1]->next = ns[i];
}
ns[left-1]->next=ns[right];
ns[left]->next=right+1<ns.size()?ns[right+1]:NULL;
return dump->next;
}
};

这种原地转圈的巨恶心:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* pre = dummy;
for (int i=0;i<left-1;i++){
pre = pre->next;
}
ListNode *cur = pre->next;
ListNode *next;
for (int i=0;i<right-left;i++){
next = cur->next;
cur->next =next->next ;
next->next = pre->next;
pre->next = next;
}
return dummy->next;
}
};

12.21

25. K 个一组翻转链表

vector的做法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode * dummy = new ListNode(-1);
dummy->next = head;
vector<ListNode*>nodes;
ListNode *temp = dummy->next;
while (temp!=NULL){
nodes.push_back(temp);
temp=temp->next;
}
int i = 0;
int n = nodes.size();
ListNode* prev_tail = dummy; // 上一组的尾节点

for (int i = 0; i + k <= n; i += k) {
int start = i;
int end = i + k - 1;

// 反转当前组内的节点
for (int j = end; j > start; j--) {
nodes[j]->next = nodes[j - 1];
}

// 连接前一组和当前组
prev_tail->next = nodes[end];

// 连接当前组和下一组
nodes[start]->next = (end + 1 < n) ? nodes[end + 1] : nullptr;

// 更新 prev_tail
prev_tail = nodes[start];
}
return dummy->next;
}

int min(int a, int b){
if (a>b){
return b;
}
return a;
}
};

空间复杂度为1的做法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
public:
// 翻转一个子链表,并且返回新的头与尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
ListNode* prev = tail->next;
ListNode* p = head;
while (prev != tail) {
ListNode* nex = p->next;
p->next = prev;
prev = p;
p = nex;
}
return {tail, head};
}

ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* hair = new ListNode(0);
hair->next = head;
ListNode* pre = hair;

while (head) {
ListNode* tail = pre;
// 查看剩余部分长度是否大于等于 k
for (int i = 0; i < k; ++i) {
tail = tail->next;
if (!tail) {
return hair->next;
}
}
ListNode* nex = tail->next;
// 这里是 C++17 的写法,也可以写成
// pair<ListNode*, ListNode*> result = myReverse(head, tail);
// head = result.first;
// tail = result.second;
tie(head, tail) = myReverse(head, tail);
// 把子链表重新接回原链表
pre->next = head;
tail->next = nex;
pre = tail;
head = tail->next;
}

return hair->next;
}
};

19. 删除链表的倒数第 N 个结点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
vector<ListNode*>nodes;
ListNode *temp = head;
while (temp!=NULL){
nodes.push_back(temp);
temp=temp->next;
}
int index = nodes.size()-n;
if (index!=0){
nodes[index-1]->next = nodes[index]->next;
return head;
}else{
return head->next;
}
return NULL;

}
};

82. 删除排序链表中的重复元素 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* prev = dummy;

while (head) {
bool isDuplicate = false;

// 检查当前节点是否有重复
while (head->next && head->val == head->next->val) {
isDuplicate = true;
head = head->next; // 跳过重复节点
}

if (isDuplicate) {
// 删除所有重复节点
prev->next = head->next;
} else {
// 当前节点不重复,保留
prev = head;
}

head = head->next;
}

return dummy->next;
}
};

61. 旋转链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
vector<ListNode*>nodes;
while (head){
nodes.push_back(head);
head=head->next;
}
int n = nodes.size();
if (n==0){
return NULL;
}
k = k%nodes.size();
nodes[n-k-1]->next =NULL;
if (k!=0){
nodes[n-1]->next=nodes[0];
}
return nodes[n-k];
}
};

86. 分隔链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if (!head) return nullptr;

vector<ListNode*> small;
vector<ListNode*> big;

// 分离节点
while (head) {
if (head->val < x) {
small.push_back(head);
} else {
big.push_back(head);
}
head = head->next;
}

ListNode* ans = nullptr;

// 重建链表
if (!small.empty()) {
// 连接 small 部分
for (int i = 0; i < (int)small.size() - 1; i++) {
small[i]->next = small[i + 1];
}
ans = small[0];

// 连接 small 和 big
if (!big.empty()) {
small.back()->next = big[0];
} else {
small.back()->next = nullptr;
}
}

if (!big.empty()) {
// 连接 big 部分
for (int i = 0; i < (int)big.size() - 1; i++) {
big[i]->next = big[i + 1];
}
big.back()->next = nullptr;

// 如果 small 为空,设置 ans 为 big 的头节点
if (small.empty()) {
ans = big[0];
}
}

return ans;
}
};

146. LRU 缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
struct DoubleListNode{
int key;
int val;
DoubleListNode *pre;
DoubleListNode *next;
DoubleListNode():val(0),next(nullptr),pre(nullptr){}
DoubleListNode(int x):val(x),next(nullptr),pre(nullptr){}
DoubleListNode(int x,int y): key(x),val(y),next(nullptr),pre(nullptr){}
};

class LRUCache {
map<int,DoubleListNode*>mapping;
int capacity;
int current_size=0;
DoubleListNode* head;
DoubleListNode* tail;
public:
LRUCache(int capacity) {
this->capacity=capacity;
this->current_size=0;
this->head = new DoubleListNode(-100);
this->tail = new DoubleListNode(-100);
head->next= tail;
tail->pre=head;
}

void erase_node(DoubleListNode *node){
node->pre->next=node->next;
if (node->next)
node->next->pre=node->pre;
}

void move_to_head(DoubleListNode* node){
node->next = head->next;
if (head->next)
head->next->pre=node;
head->next= node;
node->pre=head;
}

int get(int key) {
int ans = -1;
if (mapping.count(key)){
ans = mapping[key]->val;
erase_node(mapping[key]);
move_to_head(mapping[key]);
}
return ans;
}

void put(int key, int value) {
if (mapping.count(key)){
mapping[key]->val=value;
erase_node(mapping[key]);
move_to_head(mapping[key]);
}else{
if (this->current_size==this->capacity){
DoubleListNode *node = tail->pre;
erase_node(node);
mapping.erase(node->key);
}else{
this->current_size++;
}
DoubleListNode* new_node = new DoubleListNode(key,value);
mapping[key]=new_node;
move_to_head(new_node);
}
}
};

/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/

104. 二叉树的最大深度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
int depth = 0;
return getDepth(root,depth);
}
int getDepth(TreeNode* node,int cur_depth){
if (!node){
return cur_depth;
}
cur_depth++;
int left_depth = getDepth(node->left,cur_depth);
int right_depth = getDepth(node->right,cur_depth);
return left_depth>right_depth?left_depth:right_depth;
}
};

100. 相同的树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p==nullptr && q==nullptr){
return true;
}else if (p==nullptr||q==nullptr){
return false;
}else if ( p->val!=q->val){
return false;
}else{
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}


}
};

226. 翻转二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
exchangeNode(root);
return root;
}
void exchangeNode(TreeNode* node){
if (node==NULL)return;
TreeNode* temp = node->left;
node->left = node->right;
node->right = temp;
exchangeNode(node->left);
exchangeNode(node->right);
}
};

101. 对称二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool check(TreeNode* node1, TreeNode* node2){
if (!node1 && !node2){
return true;
}
if (!node1 || !node2){
return false;
}
if (node1->val != node2->val){
return false;
}
return check(node1->left,node2->right)&&check(node1->right,node2->left);
}
bool isSymmetric(TreeNode* root) {
return check(root->left,root->right);
}
};

105. 从前序与中序遍历序列构造二叉树:star:

这个和下一题都记住各自的原则,先序的第一个对应根节点,后序的第一个对应根节点,然后都要维护各自list的边界范围(左右子树)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
unordered_map<int, int> index;
public:
TreeNode* recurisve_buildTree(vector<int>& preorder, vector<int>& inorder,int leftp,int rightp,int leftin,int rightin){
if (leftp>rightp){
return nullptr;
}
int inorder_index = index[preorder[leftp]];
TreeNode *root = new TreeNode(preorder[leftp]);
int left_nodes_num = inorder_index-leftin;
root->left = recurisve_buildTree(preorder,inorder,leftp+1,leftp+left_nodes_num,leftin,inorder_index-1);
root->right = recurisve_buildTree(preorder,inorder,leftp+left_nodes_num+1,rightp,inorder_index+1,rightin);
return root;

}

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
for (int i=0;i<n;i++){
index[inorder[i]]=i;
}
return recurisve_buildTree(preorder,inorder,0,n-1,0,n-1);
}
};

106. 从中序与后序遍历序列构造二叉树:star:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
unordered_map<int,int>mapping;
public:
TreeNode* recursive_build_tree(vector<int>& inorder, vector<int>& postorder,int post_left,int post_right,int in_left,int in_right){
if (post_left>post_right){
return nullptr;
}
int in_index= mapping[postorder[post_right]];
int num_right_nodes = in_right-in_index;
int num_left_nodes = in_index-in_left;
TreeNode *root = new TreeNode(postorder[post_right]);
root->left= recursive_build_tree(inorder,postorder,post_left,post_right-num_right_nodes-1,in_left,in_index-1);
root->right = recursive_build_tree(inorder,postorder,post_right-num_right_nodes,post_right-1,in_index+1,in_right);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int n = inorder.size();
for (int i=0;i<n;i++){
mapping[inorder[i]]=i;
}
return recursive_build_tree(inorder,postorder,0,n-1,0,n-1);
}
};



117. 填充每个节点的下一个右侧节点指针 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;

Node() : val(0), left(NULL), right(NULL), next(NULL) {}

Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
Node* connect(Node* root) {
if (!root){
return root;
}
map<int,vector<Node*>>mapping;
vector<Node*>start={root};
mapping[0]=start;
for (auto [k,nodes]:mapping){
for (auto node: nodes){
if (node->left){
if (!mapping.count(k+1)){
vector<Node*>temp;
temp.push_back(node->left);
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(node->left);
}
}
if (node->right){
if (!mapping.count(k+1)){
vector<Node*>temp;
temp.push_back(node->right);
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(node->right);
}
}
}

}
for (auto [k,v]:mapping){
if (v.size()>1){
for (int i=0;i<v.size()-1;i++){
v[i]->next=v[i+1];
}
}
}
return root;
}
};

更简单的解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
Node* connect(Node* root) {
if (!root) {
return nullptr;
}
queue<Node*> q;
q.push(root);
while (!q.empty()) {
int n = q.size();
Node *last = nullptr;
for (int i = 1; i <= n; ++i) {
Node *f = q.front();
q.pop();
if (f->left) {
q.push(f->left);
}
if (f->right) {
q.push(f->right);
}
if (i != 1) {
last->next = f;
}
last = f;
}
}
return root;
}
};

114. 二叉树展开为链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<TreeNode*>nodes;
public:
void flatten(TreeNode* root) {
if (root==nullptr){
return;
}
pre(root);
int size = nodes.size();
for (int i=0;i<size-1;i++){
nodes[i]->left=nullptr;
nodes[i]->right=nodes[i+1];
}
nodes[size-1]->left=nullptr;
nodes[size-1]->right=nullptr;
}
void pre(TreeNode* root){
if (!root){
return;
}
nodes.push_back(root);
pre(root->left);
pre(root->right);
}
};

112. 路径总和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
bool flag= false;
public:
bool hasPathSum(TreeNode* root, int targetSum) {
getSum(root,0,targetSum);
return flag;
}
void getSum(TreeNode* node,int sum,int targetSum){
if (!node){
return;
}
sum=sum+node->val;
if (node->left==nullptr && node->right==nullptr && sum==targetSum){
flag=true;
}
getSum(node->left,sum,targetSum);
getSum(node->right,sum,targetSum);
}
};

129. 求根节点到叶节点数字之和

依旧注意stoi用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
int sum=0;
public:
int sumNumbers(TreeNode* root) {
string cur="";
getSum(root,cur);
return sum;
}
void getSum(TreeNode* node,string cur){
if (!node){
return;
}
cur +=to_string(node->val);
if (node->left==nullptr && node->right==nullptr){
sum+=stoi(cur);
}
getSum(node->left,cur);
getSum(node->right,cur);
}
};

124. 二叉树中的最大路径和:star:

我嘞个最大贡献值

其实这个最大贡献值就看成从这个节点往下走能够sum到的最大值就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
int max_num = -INT_MAX;
public:
// 获取最大贡献值并更新max_num
int maxGain(TreeNode*node){
if (node==nullptr){
return 0;
}

int max_left = max(maxGain(node->left),0);
int max_right = max(maxGain(node->right),0);

max_num = max(max_num,node->val+max_left+max_right);
return node->val+max(max_left,max_right);
}

int maxPathSum(TreeNode* root) {
maxGain(root);
return max_num;
}
};

173. 二叉搜索树迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class BSTIterator {
vector<TreeNode*>nodes;
int index =0;
int size=-1;
public:
BSTIterator(TreeNode* root) {
inorder(root);
this->size=nodes.size();
}
void inorder(TreeNode *node){
if (node==nullptr){
return;
}
inorder(node->left);
nodes.push_back(node);
inorder(node->right);
}

int next() {
int ans = nodes[this->index]->val;
this->index++;
return ans;
}

bool hasNext() {
if (index<size){
return true;
}
return false;
}
};

/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator* obj = new BSTIterator(root);
* int param_1 = obj->next();
* bool param_2 = obj->hasNext();
*/

222. 完全二叉树的节点个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
int num=0;
public:
int countNodes(TreeNode* root) {
pre(root);
return num;
}
void pre(TreeNode* node){
if (node==nullptr){
return;
}
num++;
pre(node->left);
pre(node->right);
}
};

236. 二叉树的最近公共祖先

这是递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};

还有一种就是记录父节点的,设置一个visited模块,从下往上找就行

12.23

199. 二叉树的右视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
map<int,vector<TreeNode*>>mapping;
vector<int>ans;
if (!root){
return ans;
}
vector<TreeNode*>start={root};
mapping[0]=start;
for (auto [k,vs]:mapping){
for (auto v:vs){
if (v->left){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->left};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->left);
}
}
if (v->right){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->right};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->right);
}
}
}

}
for (auto [k,v]:mapping){
ans.push_back(v[v.size()-1]->val);
}
return ans;
}
};

637. 二叉树的层平均值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double>ans;
if (!root){
return ans;
}
map<int,vector<TreeNode*>>mapping;
vector<TreeNode*>start={root};
mapping[0]=start;
for (auto [k,vs]:mapping){
for (auto v:vs){
if (v->left){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->left};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->left);
}
}
if (v->right){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->right};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->right);
}
}
}

}
for (auto [k,v]:mapping){
double temp_num = get_avg(v);
ans.push_back(temp_num);
}
return ans;
}

double get_avg(vector<TreeNode*>nodes){
double sum=0.0;
for (auto node:nodes){
sum+=double(node->val);
}
return double(sum/nodes.size());
}
};

下面的才是最简单的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
auto counts = vector<int>();
auto sums = vector<double>();
dfs(root, 0, counts, sums);
auto averages = vector<double>();
int size = sums.size();
for (int i = 0; i < size; i++) {
averages.push_back(sums[i] / counts[i]);
}
return averages;
}

void dfs(TreeNode* root, int level, vector<int> &counts, vector<double> &sums) {
if (root == nullptr) {
return;
}
if (level < sums.size()) {
sums[level] += root->val;
counts[level] += 1;
} else {
sums.push_back(1.0 * root->val);
counts.push_back(1);
}
dfs(root->left, level + 1, counts, sums);
dfs(root->right, level + 1, counts, sums);
}
};

102. 二叉树的层序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>>ans;
if (!root){
return ans;
}
map<int,vector<TreeNode*>>mapping;
vector<TreeNode*>start={root};
mapping[0]=start;
for (auto [k,vs]:mapping){
for (auto v:vs){
if (v->left){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->left};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->left);
}
}
if (v->right){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->right};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->right);
}
}
}

}
for (auto [k,vs]: mapping){
vector<int>temp;
for (auto v:vs){
temp.push_back(v->val);
}
ans.push_back(temp);
}
return ans;
}
};

103. 二叉树的锯齿形层序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>>ans;
if (root==nullptr){
return ans;
}
int flag=0;
map<int,vector<TreeNode*>>mapping;
vector<TreeNode*>start={root};
mapping[0]=start;
for (auto [k,vs]:mapping){
for (auto v:vs){
if (v->left){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->left};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->left);
}
}
if (v->right){
if (!mapping.count(k+1)){
vector<TreeNode*>temp={v->right};
mapping[k+1]=temp;
}else{
mapping[k+1].push_back(v->right);
}
}
}

}
for (auto [k,vs]: mapping){
vector<int>temp;
if (flag==1){
reverse(vs.begin(),vs.end());
flag=0;
}else{
flag=1;
}
for (auto v:vs){
temp.push_back(v->val);
}
ans.push_back(temp);
}
return ans;
}
};

12.24

530. 二叉搜索树的最小绝对差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<int>nums;
public:
int getMinimumDifference(TreeNode* root) {
getNums(root);
int ans = INT_MAX;
for (int i=0;i<nums.size()-1;i++){
int temp = abs(nums[i],nums[i+1]);
ans = min(temp,ans);
}
return ans;
}
int min(int a, int b){
return a>b?b:a;
}
int abs(int a, int b){
int res = a-b;
if (res>0){
return res;
}
return -res;
}
void getNums(TreeNode* node){
if (node==nullptr){
return;
}
getNums(node->left);
nums.push_back(node->val);
getNums(node->right);
}
};

230. 二叉搜索树中第 K 小的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<int>nums;
public:
int kthSmallest(TreeNode* root, int k) {
getNums(root);
return nums[k-1];
}
void getNums(TreeNode* node){
if (node==nullptr){
return;
}
getNums(node->left);
nums.push_back(node->val);
getNums(node->right);
}
};

98. 验证二叉搜索树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<int>nums;
public:
bool isValidBST(TreeNode* root) {
getNums(root);
if (nums.size()==1){
return true;
}
for (int i=0;i<nums.size()-1;i++){
if (nums[i]>=nums[i+1]){
return false;
}
}
return true;
}
void getNums(TreeNode* node){
if (node==nullptr){
return;
}
getNums(node->left);
nums.push_back(node->val);
getNums(node->right);
}
};

200. 岛屿数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int m = grid.size();
int n = grid[0].size();
bool visited[m][n];
memset(visited,false,sizeof(visited));
int ans =0;
for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
if (grid[i][j]=='1'){
ans++;
dfs(grid,i,j,m,n);
}
}
}
return ans;
}
void dfs(vector<vector<char>>& grid,int i ,int j,int m,int n){
grid[i][j]='0';
if (i-1>=0&&grid[i-1][j]=='1')dfs(grid,i-1,j,m,n);
if (i+1<m&&grid[i+1][j]=='1')dfs(grid,i+1,j,m,n);
if (j-1>=0&&grid[i][j-1]=='1')dfs(grid,i,j-1,m,n);
if (j+1<n&&grid[i][j+1]=='1')dfs(grid,i,j+1,m,n);
}
};

130. 被围绕的区域:star:

还有点小巧思,先dfs周围的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
void solve(vector<vector<char>>& board) {
int m = board.size();
int n = board[0].size();
for (int i=0;i<m;i++){
dfs(board,i,0);
dfs(board,i,n-1);
}
for (int i=1;i<n-1;i++){
dfs(board,0,i);
dfs(board,m-1,i);
}


for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
if (board[i][j]=='O'){
board[i][j]='X';
}else if (board[i][j]=='C'){
board[i][j]='O';
}
}
}
return;
}
void dfs(vector<vector<char>>& board,int i,int j){
int m=board.size();
int n =board[0].size();
if (i<0||j<0||i>=m||j>=n||board[i][j]!='O'){
return;
}
board[i][j]='C';
dfs(board,i+1,j);
dfs(board,i-1,j);
dfs(board,i,j-1);
dfs(board,i,j+1);

}

};

133. 克隆图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/

class Solution {
map<Node*,Node*>mapping;
public:
Node* cloneGraph(Node* node) {
if (node==nullptr){
return nullptr;
}
Node* start= new Node(node->val);
mapping[node]=start;
queue<Node*>q;
q.push(node);
while(!q.empty()){
Node* temp = q.front();
q.pop();
for (auto n: temp->neighbors){
if (!mapping.count(n)){
Node* neighbor_node = new Node(n->val);
mapping[n]=neighbor_node;
q.push(n);
}
mapping[temp]->neighbors.push_back(mapping[n]);
}
}
return mapping[node];
}
};

399. 除法求值:star:

这里掌握两种解法,一种是并查集,一种是直接bfs

bfs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries)
{
//建图:graph[a][b] = value 表示 a / b = value
unordered_map<string, unordered_map<string, double>> graph;
for (int i = 0; i < equations.size(); i++)
{
string a = equations[i][0];
string b = equations[i][1];
double val = values[i];
graph[a][b] = val;
graph[b][a] = 1.0 / val;
}
//循环处理queries
vector<double> ans;
for (auto query : queries)
{
string start = query[0];
string end = query[1];
//特殊情况处理
if (!graph.count(start) || !graph.count(end))
{
ans.push_back(double(-1.0));
continue;
}
if (start == end)
{
ans.push_back(1.0);
continue;
}
//BFS:队列存储 {当前节点, 当前累计的乘积}
bool found = false;
unordered_set<string> visited;
queue<pair<string, double>> q;
q.push({ start, 1.0 });
visited.insert(start);
//队列两个条件&&
while (!q.empty() && !found)
{
auto curQ = q.front();
q.pop();
string curNode = curQ.first;
double sum = curQ.second;
//找邻接节点
for (auto neighbor : graph[curNode])
{
string nextNode = neighbor.first;
double nextVal = neighbor.second;
// 如果找到目标节点,计算最终结果并标记找到
if (nextNode == end)
{
ans.push_back(sum * nextVal);
found = true;
break;
}
// 如果未访问过该节点,加入队列继续搜索
if (!visited.count(nextNode))
{
visited.insert(nextNode);
q.push({ nextNode, sum * nextVal });
}
}
}
// 如果不存在从start到end的路径,返回 -1.0
if (!found)ans.push_back(-1.0);
}
return ans;
}
};

并查集代码实在是过长(实际上我自己有点忘了)。这里用另一个例子来回忆:

并查集最常用来 判断图是否为连通图,或用来求图的连通分量。
无向图G的一个极大连通子图称为G的一个连通分量

下面这个就是求联通分量的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//将每个元素看为一个集合,然后通过并查集合并集合,然后再将余下的集合连接起来即可
#include<iostream>
#include<vector>

using namespace std;
int main(){
int n,m;
while(cin>>n>>m){
int t = n;
//vector(int nSize,const t& t):创建一个vector,元素个数nSize,且值均为t
vector<int> v(n+1,-1);
while(m--){
int x,y;
cin>>x>>y;
int a=x,b=y;
while(v[a]!=-1) a=v[a];//找代表元素
while(v[b]!=-1) b=v[b];
if(a==b) continue;
else {
v[b]=x;
t-=1;//合并
}
}
v.clear();
cout<<t-1<<endl;
}
}

207. 课程表

经典求入度的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int>indgree(numCourses,0);
map<int,vector<int>>mapping;
for (auto v:prerequisites){
int start=v[1];
int end=v[0];
if (!mapping.count(start)){
vector<int>temp;
temp.push_back(end);
mapping[start]=temp;
}else{
mapping[start].push_back(end);
}
indgree[end]++;
}
queue<int>q;
for (int i=0;i<numCourses;i++){
if (indgree[i]==0){
q.push(i);
}
}
while (!q.empty()){
int course = q.front();
q.pop();
for (auto end:mapping[course]){
indgree[end]--;
if (indgree[end]==0){
q.push(end);
}
}

}
for (int i=0;i<numCourses;i++){
if (indgree[i]>0){
return false;
}
}
return true;
}
};

210. 课程表 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int>indgree(numCourses,0);
map<int,vector<int>>mapping;
vector<int>ans;
for (auto v:prerequisites){
int start=v[1];
int end=v[0];
if (!mapping.count(start)){
vector<int>temp;
temp.push_back(end);
mapping[start]=temp;
}else{
mapping[start].push_back(end);
}
indgree[end]++;
}
queue<int>q;
for (int i=0;i<numCourses;i++){
if (indgree[i]==0){
q.push(i);
ans.push_back(i);
}
}
while (!q.empty()){
int course = q.front();
q.pop();
for (auto end:mapping[course]){
indgree[end]--;
if (indgree[end]==0){
q.push(end);
ans.push_back(end);
}
}

}
for (int i=0;i<numCourses;i++){
if (indgree[i]>0){
vector<int>nothing;
return nothing;
}
}
return ans;
}
};

12.25

909. 蛇梯棋

其实不难,就是题意描述得有点恶心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
pair<int, int> id2rc(int id, int n) {
int r = (id - 1) / n, c = (id - 1) % n;
if (r % 2 == 1) {
c = n - 1 - c;
}
return {n - 1 - r, c};
}

public:
int snakesAndLadders(vector<vector<int>> &board) {
int n = board.size();
vector<int> vis(n * n + 1);
queue<pair<int, int>> q;
q.emplace(1, 0);
while (!q.empty()) {
auto p = q.front();
q.pop();
for (int i = 1; i <= 6; ++i) {
int nxt = p.first + i;
if (nxt > n * n) { // 超出边界
break;
}
auto rc = id2rc(nxt, n); // 得到下一步的行列
if (board[rc.first][rc.second] > 0) { // 存在蛇或梯子
nxt = board[rc.first][rc.second];
}
if (nxt == n * n) { // 到达终点
return p.second + 1;
}
if (!vis[nxt]) {
vis[nxt] = true;
q.emplace(nxt, p.second + 1); // 扩展新状态
}
}
}
return -1;
}
};

433. 最小基因变化:star:

原谅我题都没看懂。不过也就那回事吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
public:
int minMutation(string start, string end, vector<string>& bank) {
unordered_set<string> cnt;
unordered_set<string> visited;
char keys[4] = {'A', 'C', 'G', 'T'};
for (auto & w : bank) {
cnt.emplace(w);
}
if (start == end) {
return 0;
}
if (!cnt.count(end)) {
return -1;
}
queue<string> qu;
qu.emplace(start);
visited.emplace(start);
int step = 1;
while (!qu.empty()) {
int sz = qu.size();
for (int i = 0; i < sz; i++) {
string curr = qu.front();
qu.pop();
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 4; k++) {
if (keys[k] != curr[j]) {
string next = curr;
next[j] = keys[k];
if (!visited.count(next) && cnt.count(next)) {
if (next == end) {
return step;
}
qu.emplace(next);
visited.emplace(next);
}
}
}
}
}
step++;
}
return -1;
}
};

127. 单词接龙:star:

很具有想象力了…有点阴说实话,这谁想得到。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Solution {
public:
unordered_map<string, int> wordId;
vector<vector<int>> edge;
int nodeNum = 0;

void addWord(string& word) {
if (!wordId.count(word)) {
wordId[word] = nodeNum++;
edge.emplace_back(); // 密码的emplace_back这里还能传空的
}
}

void addEdge(string& word) {
addWord(word);
int id1 = wordId[word];
for (char& it : word) {
char tmp = it;
it = '*';
addWord(word);
int id2 = wordId[word];
edge[id1].push_back(id2);
edge[id2].push_back(id1);
it = tmp;
}
}

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
for (string& word : wordList) {
addEdge(word);
}
addEdge(beginWord);
if (!wordId.count(endWord)) {
return 0;
}
vector<int> dis(nodeNum, INT_MAX);
int beginId = wordId[beginWord], endId = wordId[endWord];
dis[beginId] = 0;

queue<int> que;
que.push(beginId);
while (!que.empty()) {
int x = que.front();
que.pop();
if (x == endId) {
return dis[endId] / 2 + 1;
}
for (int& it : edge[x]) {
if (dis[it] == INT_MAX) {
dis[it] = dis[x] + 1;
que.push(it);
}
}
}
return 0;
}
};

208. 实现 Trie (前缀树)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Trie {
vector<Trie*>children;
bool isEnd;
Trie* searchPrefix(string prefix){
Trie* node =this;
for (char ch: prefix){
ch-='a';
if (node->children[ch]!=nullptr){
node=node->children[ch];
}else{
return nullptr;
}
}
return node;
}
public:
Trie(){

this->children= vector<Trie*>(26,nullptr);
this->isEnd=false;
}

void insert(string word) {
Trie* node = this;
for (char ch:word){
ch -='a';
if (node->children[ch]==nullptr){
node->children[ch]=new Trie();
}
node = node->children[ch];
}
node->isEnd=true;
}

bool search(string word) {
Trie* node = searchPrefix(word);
return node!=nullptr&&node->isEnd;
}

bool startsWith(string prefix) {
Trie* node = searchPrefix(prefix);
return node!=nullptr;
}
};

/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/

211. 添加与搜索单词 - 数据结构设计:star:

这个也还可以,前缀树+dfs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class WordDictionary {
private Trie root;

public WordDictionary() {
root = new Trie();
}

public void addWord(String word) {
root.insert(word);
}

public boolean search(String word) {
return dfs(word, 0, root);
}

private boolean dfs(String word, int index, Trie node) {
if (index == word.length()) {
return node.isEnd();
}
char ch = word.charAt(index);
if (Character.isLetter(ch)) {
int childIndex = ch - 'a';
Trie child = node.getChildren()[childIndex];
if (child != null && dfs(word, index + 1, child)) {
return true;
}
} else {
for (int i = 0; i < 26; i++) {
Trie child = node.getChildren()[i];
if (child != null && dfs(word, index + 1, child)) {
return true;
}
}
}
return false;
}
}

class Trie {
private Trie[] children;
private boolean isEnd;

public Trie() {
children = new Trie[26];
isEnd = false;
}

public void insert(String word) {
Trie node = this;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
int index = ch - 'a';
if (node.children[index] == null) {
node.children[index] = new Trie();
}
node = node.children[index];
}
node.isEnd = true;
}

public Trie[] getChildren() {
return children;
}

public boolean isEnd() {
return isEnd;
}
}

12.27

212. 单词搜索 II:star:

可以,代码手撕很简单,就是想思路挺难

前缀树+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
struct Trie{
string word;
map<char,Trie*>children;
Trie(){
this->word="";
}
};

void insertWord(Trie* root,string word){
Trie* node = root;
for (char c: word){
if (!node->children.count(c)){
node->children[c]= new Trie();
}
node=node->children[c];
}
node->word=word;
}

class Solution {
vector<vector<int>>steps={
{1,0},
{-1,0},
{0,-1},
{0,1}
};
public:
void dfs(Trie* root,vector<vector<char>>& board,int i,int j,set<string>&res){
Trie*node =root;
char c = board[i][j];
if (!node->children.count(board[i][j])){
return ;
}
node=node->children[board[i][j]];
if (node->word.size()>0){
res.insert(node->word);
}
board[i][j]='#';
int m =board.size();
int n = board[0].size();
for (int k=0;k<4;k++){
int nextX=i+steps[k][0];
int nextY=j+steps[k][1];
if (nextX>=0&&nextY>=0&&nextX<m&&nextY<n&&board[nextX][nextY]!='#'){
dfs(node,board,nextX,nextY,res);
}
}
board[i][j]=c;
return;
}
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
Trie* root = new Trie();
for (auto word:words){
insertWord(root,word);
}
int m =board.size();
int n = board[0].size();
set<string>res;
vector<string>ans;
for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
dfs(root,board,i,j,res);
}
}
for (auto word:res){
ans.emplace_back(word);
}
return ans;


}
};

17. 电话号码的字母组合

有一个需要注意的是,初始化要留在函数里面去初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
map<char,vector<string>>mapping;


public:
void dfs(string temp,string digits,int i,vector<string>&res){
string start = temp;
if (i>=digits.size()){
return;
}
for (auto v:mapping[digits[i]]){
temp+=v;
if (i==digits.size()-1){
res.push_back(temp);
}
dfs(temp,digits,i+1,res);
temp=temp.substr(0,temp.size()-1);
}
return ;
}
vector<string> letterCombinations(string digits) {
mapping['2']={"a","b","c"};
mapping['3']={"d","e","f"};
mapping['4']={"g","h","i"};
mapping['5']={"j","k","l"};
mapping['6']={"m","n","o"};
mapping['7']={"p","q","r","s"};
mapping['8']={"t","u","v"};
mapping['9']={"w","x","y","z"};
vector<string>ans;
string temp="";
dfs("",digits,0,ans);
return ans;
}
};

77. 组合

这里不剪枝内存还要爆,春傻比来着

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
void dfs(int n,int i,vector<int>cur, int k,vector<vector<int>>&ans){
if (cur.size()==k){
ans.push_back(cur);
return;
}
if (i>n||cur.size() + (n - i + 1) < k){
return;
}
cur.push_back(i);
dfs(n,i+1,cur,k,ans);
cur.pop_back();
dfs(n,i+1,cur,k,ans);

return;
}
vector<vector<int>> combine(int n, int k) {
vector<vector<int>>ans;
vector<int>start;
dfs(n,1,start,k,ans);
return ans;
}
};

46. 全排列

其实会往底层去想,这个为什么就是全排列了

我们定义递归函数 backtrack(first,output) 表示从左往右填到第 first 个位置,当前排列为 output。 那么整个递归函数分为两个情况:

如果 first=n,说明我们已经填完了 n 个位置(注意下标从 0 开始),找到了一个可行的解,我们将 output 放入答案数组中,递归结束。
如果 first<n,我们要考虑这第 first 个位置我们要填哪个数。根据题目要求我们肯定不能填已经填过的数,因此很容易想到的一个处理手段是我们定义一个标记数组 vis 来标记已经填过的数,那么在填第 first 个数的时候我们遍历题目给定的 n 个数,如果这个数没有被标记过,我们就尝试填入,并将其标记,继续尝试填下一个位置,即调用函数 backtrack(first+1,output)。回溯的时候要撤销这一个位置填的数以及标记,并继续尝试其他没被标记过的数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
vector<vector<int>>ans;
public:
void backtrack(vector<int>temp,int start){
if (start==temp.size()){
ans.emplace_back(temp);
return;
}
for (int i=start;i<temp.size();i++){
swap(temp[i],temp[start]);
backtrack(temp,start+1);
swap(temp[i],temp[start]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
backtrack(nums,0);
return ans;
}
};

39. 组合总和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
vector<vector<int>>ans;

public:
int sum(vector<int>nums){
int res = 0;
for (int num:nums){
res+=num;
}
return res;
}
void backtrack(int target,int i,vector<int>& candidates,vector<int>&temp){
if (i>=candidates.size())return;
if (sum(temp)==target){
ans.push_back(temp);
return;
}
if (sum(temp)>target){
return;
}
backtrack(target,i+1,candidates,temp);
if (target-sum(temp)-candidates[i]>=0){
temp.push_back(candidates[i]);
backtrack(target,i,candidates,temp);
temp.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<int>temp;
backtrack(target,0,candidates,temp);
return ans;
}

};

12.28

51. N 皇后:star:

按照三种set进行区分就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>>ans;
unordered_set<int>columns;
unordered_set<int>t_pie;
unordered_set<int>t_na;
vector<int>queens=vector<int>(n,-1);
backtrack(0,ans,columns,t_pie,t_na,queens,n);
return ans;
}
void backtrack(int row,vector<vector<string>>&ans,unordered_set<int>&columns,unordered_set<int>&t_pie,unordered_set<int>&t_na,vector<int>&queens,int n){
if (row==n){
vector<string>temp = print_board(queens,n);
ans.push_back(temp);
}else{
for (int i=0;i<n;i++){
int index1=i;
if (columns.count(index1)){
continue;
}
int index2 = row-i;
if (t_na.count(index2)){
continue;
}
int index3 = row+i;
if (t_pie.count(index3)){
continue;
}
queens[row]=i;
columns.insert(index1);
t_na.insert(index2);
t_pie.insert(index3);
backtrack(row+1,ans,columns,t_pie,t_na,queens,n);
columns.erase(index1);
t_na.erase(index2);
t_pie.erase(index3);
}
}
}
vector<string>print_board(vector<int>&queens,int n){
vector<string>res;
for (int i=0;i<n;i++){
string temp=string(n,'.');
temp[queens[i]]='Q';
res.push_back(temp);
}
return res;
}


};

52. N 皇后 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Solution {
public:
int totalNQueens(int n) {
auto ans=solveNQueens(n);
return ans.size();
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>>ans;
unordered_set<int>columns;
unordered_set<int>t_pie;
unordered_set<int>t_na;
vector<int>queens=vector<int>(n,-1);
backtrack(0,ans,columns,t_pie,t_na,queens,n);
return ans;
}
void backtrack(int row,vector<vector<string>>&ans,unordered_set<int>&columns,unordered_set<int>&t_pie,unordered_set<int>&t_na,vector<int>&queens,int n){
if (row==n){
vector<string>temp = print_board(queens,n);
ans.push_back(temp);
}else{
for (int i=0;i<n;i++){
int index1=i;
if (columns.count(index1)){
continue;
}
int index2 = row-i;
if (t_na.count(index2)){
continue;
}
int index3 = row+i;
if (t_pie.count(index3)){
continue;
}
queens[row]=i;
columns.insert(index1);
t_na.insert(index2);
t_pie.insert(index3);
backtrack(row+1,ans,columns,t_pie,t_na,queens,n);
columns.erase(index1);
t_na.erase(index2);
t_pie.erase(index3);
}
}
}
vector<string>print_board(vector<int>&queens,int n){
vector<string>res;
for (int i=0;i<n;i++){
string temp=string(n,'.');
temp[queens[i]]='Q';
res.push_back(temp);
}
return res;
}
};

22. 括号生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string>ans;
string temp="";
backtrack(ans,temp,0,n,0,0);
return ans;
}
void backtrack(vector<string>&ans,string &temp,int i,int n,int left_num,int right_num){
if (i==2*n){
ans.push_back(temp);
}
if (left_num<n&&left_num>=right_num){
temp+="(";
backtrack(ans,temp,i+1,n,left_num+1,right_num);
temp=temp.substr(0,temp.size()-1);
}
if (left_num>right_num){
temp+=")";
backtrack(ans,temp,i+1,n,left_num,right_num+1);
temp=temp.substr(0,temp.size()-1);
}
}
};

79. 单词搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
struct Trie{
string word;
map<char,Trie*>children;
Trie(){
this->word="";
}
};

void insert_word(Trie* root,string word){
for (auto ch :word){
if (!root->children.count(ch)){
root->children[ch]=new Trie();
}
root=root->children[ch];
}
root->word = word;
}

class Solution {
bool flag =false;
vector<vector<int>>steps={
{1,0},
{-1,0},
{0,1},
{0,-1}
};
public:
bool exist(vector<vector<char>>& board, string word) {

Trie* root = new Trie();
insert_word(root,word);
int m = board.size();
int n = board[0].size();
for (int i=0;i<m;i++){
for (int j=0;j<n;j++){
dfs(board,word,0,root,i,j);
if (flag){
return flag;
}
}
}
return flag;
}
void dfs(vector<vector<char>>& board,string word,int index,Trie* node,int i,int j){
if (!node->children.count(board[i][j]))return;
char ch = board[i][j];
node=node->children[board[i][j]];
if (node->word==word){
flag=true;
return;
}
for (int k=0;k<4;k++){
int nextX = i+steps[k][0];
int nextY = j+steps[k][1];
board[i][j]='#';
if (nextX>=0&&nextY>=0&&nextX<board.size()&&nextY<board[0].size()&&board[nextX][nextY]!='#'){
dfs(board,word,index+1,node,nextX,nextY);
}
board[i][j]=ch;
}
}
};

108. 将有序数组转换为二叉搜索树

注意这里是平衡二叉搜索树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/

TreeNode* insert_node(vector<int>nums,int left,int right){
if (left>right){
return nullptr;
}
int mid = (left+right)/2;
int num = nums[mid];
TreeNode * root = new TreeNode(num);
root->left = insert_node(nums,left,mid-1);
root->right = insert_node(nums,mid+1,right);
return root;
}

class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
int size = nums.size();
TreeNode* root = insert_node(nums,0,size-1);
return root;
}
};

148. 排序链表

唯一需要注意的是这里的sort的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
vector<ListNode*>nodes;
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* temp = head;
while (temp!=nullptr){
nodes.push_back(temp);
temp=temp->next;
}
sort(nodes.begin(),nodes.end(),[](ListNode*a ,ListNode*b){
return a->val<b->val;
});
for (int i=0;i<nodes.size()-1;i++){
nodes[i]->next=nodes[i+1];
}
nodes.back()->next = nullptr;
return nodes[0];
}
};

还有一种做法是归并的做法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
public ListNode sortList(ListNode head) {
return sortList(head, null);
}

public ListNode sortList(ListNode head, ListNode tail) {
if (head == null) {
return head;
}
if (head.next == tail) {
head.next = null;
return head;
}
ListNode slow = head, fast = head;
while (fast != tail) {
slow = slow.next;
fast = fast.next;
if (fast != tail) {
fast = fast.next;
}
}
ListNode mid = slow;
ListNode list1 = sortList(head, mid);
ListNode list2 = sortList(mid, tail);
ListNode sorted = merge(list1, list2);
return sorted;
}

public ListNode merge(ListNode head1, ListNode head2) {
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 != null && temp2 != null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummyHead.next;
}
}

427. 建立四叉树:star:

最大难度在于读懂题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
// Definition for a QuadTree node.
class Node {
public:
bool val;
bool isLeaf;
Node* topLeft;
Node* topRight;
Node* bottomLeft;
Node* bottomRight;

Node() {
val = false;
isLeaf = false;
topLeft = NULL;
topRight = NULL;
bottomLeft = NULL;
bottomRight = NULL;
}

Node(bool _val, bool _isLeaf) {
val = _val;
isLeaf = _isLeaf;
topLeft = NULL;
topRight = NULL;
bottomLeft = NULL;
bottomRight = NULL;
}

Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) {
val = _val;
isLeaf = _isLeaf;
topLeft = _topLeft;
topRight = _topRight;
bottomLeft = _bottomLeft;
bottomRight = _bottomRight;
}
};
*/
Node* dfs(vector<vector<int>>& grid,int r0,int c0,int r1,int c1){
for (int i=r0;i<r1;i++){
for (int j=c0;j<c1;j++){
if (grid[i][j]!=grid[r0][c0]){
return new Node(
true,false,
dfs(grid,r0, c0, (r0 + r1) / 2, (c0 + c1) / 2),
dfs(grid,r0, (c0 + c1) / 2, (r0 + r1) / 2, c1),
dfs(grid,(r0 + r1) / 2, c0, r1, (c0 + c1) / 2),
dfs(grid,(r0 + r1) / 2, (c0 + c1) / 2, r1, c1)
);
}
}
}
return new Node(grid[r0][c0],true);
}


class Solution {
public:
Node* construct(vector<vector<int>>& grid) {
return dfs(grid,0,0,grid.size(),grid.size());
}
};

23. 合并 K 个升序链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.size()==0){
return nullptr;
}
int flag =0;
for (int i=0;i<lists.size();i++){
if (lists[i]!=nullptr){
flag++;
}
}
if (flag==0){
return nullptr;
}

vector<ListNode*>nodes;
for (auto n:lists){
auto head = n;
while(head){
nodes.push_back(head);
head=head->next;
}
}
sort(nodes.begin(),nodes.end(),[](ListNode* node_a,ListNode* node_b){
return node_a->val<node_b->val;
});
for (int i=0;i<nodes.size();i++){
if (i+1<nodes.size()){
nodes[i]->next=nodes[i+1];
}
}
nodes[nodes.size()-1]->next=nullptr;
return nodes[0];
}
};

另一种做法是分治的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* merge_2_lists(ListNode* a,ListNode* b){
ListNode* head = new ListNode(-1);
ListNode* tail = head;
ListNode* ptra = a;
ListNode* ptrb = b;
while(ptra&&ptrb){
if (ptra->val<ptrb->val){
tail->next = ptra;
ptra=ptra->next;
}else{
tail->next = ptrb;
ptrb=ptrb->next;
}
tail=tail->next;
}
if (ptra!=nullptr){
tail->next=ptra;
}
if (ptrb!=nullptr){
tail->next=ptrb;
}
return head->next;
}

ListNode* merge_all(vector<ListNode*>& lists,int left,int right){
if (left>right){
return nullptr;
}
if (left==right){
return lists[left];
}
int mid=(left+right)/2;
return merge_2_lists(merge_all(lists,left,mid),merge_all(lists,mid+1,right));
}

ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge_all(lists,0,lists.size()-1);
}
};

53. 最大子数组和

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x: nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};

01.01

918. 环形子数组的最大和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int curMax = 0;
int maxSum = nums[0];
int curMin = 0;
int minSum = nums[0];
int total =0;
for (auto num : nums){
curMax = max(curMax+num,num);
maxSum = max(curMax,maxSum);
curMin = min(num,curMin+num);
minSum = min(curMin,minSum);
total += num;
}
if (maxSum<0)return maxSum;
return max(maxSum,total-minSum);

}
};

35. 搜索插入位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;

while (left <= right) {
int mid = left + (right - left) / 2; // 防止溢出

if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}

// 如果没找到,left 就是应该插入的位置
return left;
}
};

74. 搜索二维矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
for (int i=0;i<matrix.size();i++){
if (target>matrix[i][matrix[0].size()-1])continue;
return searchVector(matrix[i],target);
}
return false;
}
bool searchVector(vector<int>nums,int target){
int left =0;
int right = nums.size()-1;
while (left<=right){
int mid = left+(right-left)/2;
if (nums[mid]==target){
return true;
}
if (nums[mid]>target){
right = mid-1;
}else{
left = mid+1;
}
}
return false;
}
};

162. 寻找峰值 :star:

阴的没边了,这玩意儿靠一个证明,即上升趋势,进行一个爬坡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
while (left<right){
int mid = left+(right-left)/2;
if (nums[mid]>nums[mid+1]){
right = mid;
}else{
left=mid+1;
}
}
return left;
}
};

搜索旋转排序数组:star:

这个也挺阴的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
int search(vector<int>& nums, int target) {
int l =0;
int r = nums.size()-1;
int n = nums.size();
if (n==0)return -1;
while (l<=r){
int mid = l + (r-l)/2;
if (nums[mid]==target){
return mid;
}
if (nums[0]<=nums[mid]){
if (nums[0]<=target&&target<nums[mid]){
r= mid-1;
}else{
l = mid+1;
}
}else{
if (nums[mid]<target&&target<=nums[n-1]){
l = mid+1;
}else{
r = mid-1;
}
}
}
return -1;
}
};

01.02

34. 在排序数组中查找元素的第一个和最后一个位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int binary_search(vector<int>&nums,int target,bool lower){
int left =0;
int right = nums.size()-1;
int ans = nums.size();
while(left<=right){
int mid = left + (right-left)/2;
if (nums[mid]>target||(lower&&nums[mid]>=target)){
right = mid-1;
ans = mid;
}else{
left = mid +1;
}
}
return ans;
}
vector<int> searchRange(vector<int>& nums, int target) {
int left = binary_search(nums,target,true);
int right = binary_search(nums,target,false)-1;
if (left<=right&&right<nums.size()&&nums[right]==target&&nums[left]==target){
return {left,right};
}
return {-1,-1};
}
};

153. 寻找旋转排序数组中的最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int findMin(vector<int>& nums) {
int left =0;
int right = nums.size()-1;
while (left<right){
int mid = left +(right-left)/2;
if (nums[mid]<nums[right]){
right = mid;
}else{
left = mid+1;
}
}
return nums[left];
}
};

这里得注意边界条件,left < right

4. 寻找两个正序数组的中位数:star:

巨恶心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int length1 = nums1.length, length2 = nums2.length;
int totalLength = length1 + length2;
if (totalLength % 2 == 1) {
int midIndex = totalLength / 2;
double median = getKthElement(nums1, nums2, midIndex + 1);
return median;
} else {
int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;
double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;
return median;
}
}

public int getKthElement(int[] nums1, int[] nums2, int k) {
/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
* 这里的 "/" 表示整除
* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
* 这样 pivot 本身最大也只能是第 k-1 小的元素
* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
*/

int length1 = nums1.length, length2 = nums2.length;
int index1 = 0, index2 = 0;
int kthElement = 0;

while (true) {
// 边界情况
if (index1 == length1) {
return nums2[index2 + k - 1];
}
if (index2 == length2) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return Math.min(nums1[index1], nums2[index2]);
}

// 正常情况
int half = k / 2;
int newIndex1 = Math.min(index1 + half, length1) - 1;
int newIndex2 = Math.min(index2 + half, length2) - 1;
int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2) {
k -= (newIndex1 - index1 + 1);
index1 = newIndex1 + 1;
} else {
k -= (newIndex2 - index2 + 1);
index2 = newIndex2 + 1;
}
}
}
}

01.11

215. 数组中的第K个最大元素

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int>q;
for (auto num : nums){
q.push(num);
}
for (int i=0;i<k-1;i++){
q.pop();
}
return q.top();
}
};

502. IPO

就稍微还好吧,记住大小顶堆以及pair sort的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
typedef pair<int,int> pii;

class Solution {
public:
int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {
int n = profits.size();
int curr = 0;
priority_queue<int, vector<int>, less<int>> pq;
vector<pii> arr;

for (int i = 0; i < n; ++i) {
arr.push_back({capital[i], profits[i]});
}
sort(arr.begin(), arr.end());
for (int i = 0; i < k; ++i) {
while (curr < n && arr[curr].first <= w) {
pq.push(arr[curr].second);
curr++;
}
if (!pq.empty()) {
w += pq.top();
pq.pop();
} else {
break;
}
}

return w;
}
};

373. 查找和最小的 K 对数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
struct Pair_num {
int val1; // nums1的值
int val2; // nums2的值
int i; // nums1的索引(用于后续添加新配对)
int j; // nums2的索引(用于后续添加新配对)
int sum;

// 构造函数1:存储值和索引
Pair_num(int v1, int v2, int idx1, int idx2):
val1(v1), val2(v2), i(idx1), j(idx2), sum(v1 + v2) {}

// 构造函数2:仅用于比较
Pair_num(int s): sum(s) {}

// 重载比较操作符
bool operator>(const Pair_num& other) const {
return sum > other.sum;
}
};

class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
vector<vector<int>> ans;

if (m == 0 || n == 0) return ans;

// 使用greater创建小顶堆
auto cmp = [](const Pair_num& a, const Pair_num& b) {
return a.sum > b.sum; // 小顶堆
};

priority_queue<Pair_num, vector<Pair_num>, decltype(cmp)> pq(cmp);

// 初始化
for (int i = 0; i < min(k, m); i++) {
pq.emplace(nums1[i], nums2[0], i, 0);
}

while (k-- > 0 && !pq.empty()) {
Pair_num curr = pq.top();
pq.pop();

ans.push_back({curr.val1, curr.val2});

// 添加下一个配对
if (curr.j + 1 < n) {
int next_j = curr.j + 1;
pq.emplace(nums1[curr.i], nums2[next_j], curr.i, next_j);
}
}

return ans;
}
};

763. 划分字母区间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<int> partitionLabels(string s) {
int last[26];
int length = s.size();
for (int i = 0; i < length; i++) {
last[s[i] - 'a'] = i;
}
vector<int> partition;
int start = 0, end = 0;
for (int i = 0; i < length; i++) {
end = max(end, last[s[i] - 'a']);
if (i == end) {
partition.push_back(end - start + 1);
start = end + 1;
}
}
return partition;
}

int main() {
string s;
cin >> s;
vector<int> ans = partitionLabels(s);
for (auto item : ans) {
cout << " " << item;
}
return 0;
}

32. 最长有效括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <stack>
#include <string>

using namespace std;

int longestValidParentheses(string s) {
stack<int> stk;
int num = 0;
int ans = 0;
int len = s.size();
stk.push(-1);
for (int i = 0; i < len; i++) {
if (s[i] == '(') {
stk.push(i);
} else {
stk.pop();
if (stk.empty()) {
stk.push(i);
} else {
num = i - stk.top();
ans = max(num, ans);
}
}
}
return ans;
}

int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}

int main() {
string s = ")()())";
int ans = longestValidParentheses(s);
cout << ans;
}

84. 矩形图中的最大面积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <stack>
#include <vector>

using namespace std;
int largestRectangleArea(vector<int>& heights) {
stack<int> stk;
int ans = 0;
for (int i = 0; i < heights.size(); i++) {
if (stk.empty() || heights[i] > heights[stk.top()]) {
stk.push(i);
} else {
while (!stk.empty() && heights[stk.top()] > heights[i]) {
int length = heights[stk.top()];
stk.pop();
int weight = i;
if (!stk.empty()) {
weight = i - stk.top() - 1;
}
ans = max(ans, length * weight);
}
stk.push(i);
}
}
int right = heights.size();
while (!stk.empty()) {
int h = heights[stk.top()];
stk.pop();
if (!stk.empty()) {
int left = stk.top();
ans = max(ans, h * (right - left - 1));
} else {
ans = max(right * h, ans);
}
}
return ans;
}

int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}

int main() {
vector<int> heights = {2, 1, 5, 6, 2, 3};
int ans = largestRectangleArea(heights);
cout << ans << endl;
}

LCR 153. 二叉树中和为目标值的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> pathTarget(TreeNode* root, int target) {
cur(root,target);
return ans;
}
private:
vector<int>path;
vector<vector<int>>ans;
void cur(TreeNode* node,int target){
if (node == nullptr) return;
path.push_back(node->val);
target = target-node->val;
if (target==0&&node->left==nullptr&&node->right==nullptr){
ans.push_back(path);
}
cur(node->left,target);
cur(node->right,target);
path.pop_back();
}
};

153. 寻找旋转排序数组中的最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int findMin(vector<int>& nums) {
int i =0;
int j = nums.size()-1;
while(i<j){
int middle = (i+j)/2;
if (nums[middle]<nums[j]){
j = middle;
}else{
i = middle+1;
}
}
return nums[i];
}
};

33. 搜索旋转排序数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};

76. 最小覆盖子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
private:

public:
unordered_map<char,int> m1,m2;
string minWindow(string s, string t) {
int len=s.size()+100;
int ans_left = -1;
int left=0;
int right =-1;
for (int i=0;i<t.size();i++){
m1[t[i]]++;
}
while (right<s.size()){
if (m1.find(s[++right])!=m1.end()){
m2[s[right]]++;
}
while(checkReady()&&left<=right){
if(right-left+1<len){
len = right-left+1;
ans_left = left;
}
if (m1.find(s[left])!=m1.end()){
m2[s[left]]--;
}
left++;
}
}
if (ans_left!=-1){
return s.substr(ans_left,len);
}
return "";
}
bool checkReady(){
for (auto it=m1.begin();it!=m1.end();it++){
if (m2[it->first]<it->second){
return false;
}
}
return true;
}
};

LRU

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class LRUCache {
private:
struct Node {
int key, value;
Node* prev;
Node* next;
Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};

int capacity;
std::unordered_map<int, Node*> cache;
Node* head;
Node* tail;

// 删除节点
void removeNode(Node* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}

// 在头部添加节点
void addToHead(Node* node) {
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}

// 移动节点到头部
void moveToHead(Node* node) {
removeNode(node);
addToHead(node);
}

// 删除尾部节点
Node* removeTail() {
Node* node = tail->prev;
removeNode(node);
return node;
}

public:
LRUCache(int capacity) {
this->capacity = capacity;
head = new Node(0, 0);
tail = new Node(0, 0);
head->next = tail;
tail->prev = head;
}

int get(int key) {
if (cache.find(key) == cache.end()) {
return -1;
}

Node* node = cache[key];
// 移动到头部
moveToHead(node);
return node->value;
}

void put(int key, int value) {
if (cache.find(key) == cache.end()) {
// 新节点
Node* node = new Node(key, value);
cache[key] = node;
addToHead(node);

if (cache.size() > capacity) {
// 超出容量,删除尾部节点
Node* tail = removeTail();
cache.erase(tail->key);
delete tail;
}
} else {
// 更新现有节点
Node* node = cache[key];
node->value = value;
moveToHead(node);
}
}
};

三数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({nums[first], nums[second], nums[third]});
}
}
}
return ans;
}
};

无重复字符的最长子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int>m;
int left =0;
int right = 0;
int ans=0;
while(left<=right&&right<s.size()){
m[s[right]]++;
if (m[s[right]]>1){
while(left<=right){
m[s[left]]--;
left++;
if (m[s[right]]==1){
break;
}
}
}else{
ans = max(ans,right-left+1);
}
right++;
}
return ans;

}
};

和为k的子数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
vector<int>prifix_sum(nums.size()+1);
for (int i=0;i<nums.size();i++){
prifix_sum[i+1] = prifix_sum[i]+nums[i];
}
int ans = 0;
unordered_map<int,int> m ;
for (int i=0;i<prifix_sum.size();i++){
if (m.find(prifix_sum[i]-k)!=m.end()){
ans =ans+m[prifix_sum[i]-k];
}
m[prifix_sum[i]]++;
}
return ans;
}
};

二叉树的最近公共祖先

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};

每日一题

3227.字符串元音游戏

感觉就是个博弈问题。

如果当前剩下的所有的字符中包含元音个数为奇数个,她直接赢,反之就是小明赢。

1935. 可以输入的最大单词数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
int canBeTypedWords(string text, string brokenLetters) {
set<char> s;
for (int i=0;i<brokenLetters.size();i++){
s.insert(brokenLetters[i]);
}
bool flag = true;
int ans =0;
for (int i=0;i<text.size();i++){
if (text[i]==' '){
if (flag){
ans++;
}
flag = true;
}else{
if (s.find(text[i])!=s.end()){
flag = false;
}
}
}
if (flag){
ans++;
}
return ans;
}
};

2197. 替换数组中的非互质数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
vector<int> replaceNonCoprimes(vector<int>& nums) {
vector<int> ans;

for (int num : nums) {
ans.push_back(num);

// 持续合并非互质相邻元素
while (ans.size() > 1) {
int g = gcd(ans[ans.size()-1], ans[ans.size()-2]);
if (g > 1) {
long long lcm = (long long)ans[ans.size()-1] * ans[ans.size()-2] / g;
ans.pop_back();
ans.pop_back();
ans.push_back(lcm);
} else {
break;
}
}
}

return ans;
}

private:
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
};

2349. 设计数字容器系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class NumberContainers {
private:
unordered_map<int, int> nums;
unordered_map<int, set<int>> us;
public:
NumberContainers() {

}

void change(int index, int number) {
if (nums[index] != 0) {
us[nums[index]].erase(index);
}
us[number].insert(index);
nums[index] = number;
}

int find(int number) {
if (us[number].empty()) {
return -1;
}
return *us[number].begin();
}
};

另一个办法是优先队列

3408. 设计任务管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class TaskManager {
private:
unordered_map<int, pair<int, int>> taskInfo;
priority_queue<pair<int, int>> heap;

public:
TaskManager(vector<vector<int>> tasks) {
for (auto& task : tasks) {
int userId = task[0], taskId = task[1], priority = task[2];
taskInfo[taskId] = {priority, userId};
pair<int,int> p {priority,taskId};
heap.push(p);
}
}

void add(int userId, int taskId, int priority) {
taskInfo[taskId] = {priority, userId};
pair<int,int> p {priority,taskId};
heap.push(p);
}

void edit(int taskId, int newPriority) {
if (taskInfo.find(taskId) != taskInfo.end()) {
taskInfo[taskId].first = newPriority;
pair<int,int> p {newPriority,taskId};
heap.push(p);
}
}

void rmv(int taskId) {
taskInfo.erase(taskId);
}

int execTop() {
while (!heap.empty()) {
auto [priority, taskId] = heap.top();
heap.pop();

if (taskInfo.find(taskId) != taskInfo.end() &&
taskInfo[taskId].first == priority) {
int userId = taskInfo[taskId].second;
taskInfo.erase(taskId);
return userId;
}
}
return -1;
}
};

3370. 仅含置位位的最小整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int smallestNumber(int n) {
if (n==1)return 1;
int small = get_small(n);
int big = small*2;
if (big == n){
return big*2-1;
}else{
return big-1;
}
}

int get_small( int num){
int i=1;
while(i<num){
i=i*2;
}
return i/2;
}
};

135. 分发糖果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size();
int pre = 1;
int ans = 1;
int inc =1;
int dec = 0;
for (int i=1;i<n;i++){
if (ratings[i]>ratings[i-1]){
pre = pre+1;
ans +=pre;
inc = pre;
dec =0;
}else if(ratings[i]==ratings[i-1]){
pre =1;
ans+=pre;
inc=pre;
dec =0;
}else{
dec++;
if (dec==inc){
dec++;
}
ans +=dec;
pre = 1;
}
}
return ans;

}
};

1526. 形成目标数组的子数组最少增加次数

这个题有点巧妙,证明用差分数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int minNumberOperations(vector<int>& target) {
int length = target.size();
int ans =target[0];
for (int i=1;i<length;i++){
ans +=max(0,target[i]-target[i-1]);
}
return ans;
}

int max(int a, int b){
if (a>b){
return a;
}
return b;
}
};

1298. 你能从盒子里获得的最大糖果数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
int maxCandies(vector<int>& status, vector<int>& candies,
vector<vector<int>>& keys, vector<vector<int>>& containedBoxes,
vector<int>& initialBoxes) {
int n = status.size();
vector<bool> has_key(n, false), has_box(n, false), opened(n, false);
queue<int> q;
int ans = 0;

// 初始化:拿到的盒子
for (int b : initialBoxes) {
has_box[b] = true;
if (status[b] == 1) q.push(b);
}

while (!q.empty()) {
int box = q.front(); q.pop();
if (opened[box]) continue;
opened[box] = true;
ans += candies[box];

// 获得钥匙
for (int k : keys[box]) {
if (!has_key[k]) {
has_key[k] = true;
if (has_box[k] && !opened[k]) q.push(k);
}
}

// 获得新盒子
for (int b : containedBoxes[box]) {
if (!has_box[b]) has_box[b] = true;
if ((status[b] == 1 || has_key[b]) && !opened[b]) q.push(b);
}
}

return ans;
}
};