力扣刷题_第六周

第六周

注:1、由于主要记录的是刷题的总结和心得,与后端学习有联系但相关度不高,因此该连载系列更名;2、从本周开始不再详细记录具体日期和第几天,不再拘泥于具体的某天做了某些题;3、不再针对每一道题粘贴具体的题解代码,将更多精力放在分析题目和总结部分。具体题解代码可在力口个人主页的题目分析中寻找。

东哥带你刷二叉树(后序篇)

何时要用后序?

由前文学习可知,前序位置的代码只能从函数参数中获取父节点传递来的数据,而后序位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据。

那么换句话说,一旦发现题目和子树有关,那大概率要给函数设置合理的定义和返回值,在后序位置写代码了

652. 寻找重复的子树

652. 寻找重复的子树 - 力扣(LeetCode)

题目描述:给定root,返回所有重复子树。同类子树只用返回其中任意一颗的根节点即可。

分析:1、返回根节点,如叶子结点只返回其本身,如1<- 4 ->2是以4为根节点具有左右节点的子树,需返回根节点4,但是在打印时是[4,1,2]的结构

2、对于每一个节点,需要知道:以我为根的这颗二叉树(子树)是什么样? 以其他节点为根的子树长什么样? 这就需要按后序序列化,并保存每个子树输出的结果以方便比较

3、采用拼接字符串的方式后序序列化,采用unordered_map记录子树(不应有重复)

归并排序详解及应用

912.排序数组

912. 排序数组 - 力扣(LeetCode)

分析:归并排序的核心在于merge()函数,本质是二叉树的后序遍历

315.计算数组右侧小于当前元素的个数(华为5.11机试题T1)

315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)

分析:这题和归并排序什么关系呢,主要在 merge 函数,我们在使用 merge 函数合并两个有序数组的时候,其实是可以知道一个元素 nums[i] 后边有多少个元素比 nums[i] 小的

换句话说,在对 nuns[lo..hi] 合并的过程中,每当执行 nums[p] = temp[i] 时,就可以确定 temp[i] 这个元素后面比它小的元素个数为 j - mid - 1

当然,nums[lo..hi] 本身也只是一个子数组,这个子数组之后还会被执行 merge,其中元素的位置还是会改变。但这是其他递归节点需要考虑的问题,我们只要在 merge 函数中做一些手脚,叠加每次 merge 时记录的结果即可。

快速排序详解及应用

912.排序数组

912. 排序数组 - 力扣(LeetCode)

分析:快速排序的核心在于partition()函数,本质是二叉树的先序遍历,是构造二叉搜索树的过程

注意:1、必须用shuffle洗牌算法打乱数组,否则在精心设计的测试用例上面会导致O(n^2)的时间复杂度,引入随机性可以避免最坏情况的发生

2、快速排序是不稳定的排序,每次只能确定一个元素的最终位置。而归并排序是稳定的排序方式。

在实际工程中我们经常会将一个复杂对象的某一个字段作为排序的 key,所以应该关注编程语言提供的 API 底层使用的到底是什么排序算法,是稳定的还是不稳定的,这很可能影响到代码执行的效率甚至正确性

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

215. 数组中的第K个最大元素 - 力扣(LeetCode)

解法:二叉堆(优先队列)或者快速选择算法

快速选择算法分析:快排算法的变体。找数组的第K大元素其实就是找第k’ = N - K个元素。快排每次partition会确定在nums[p]这个位置上的元素,这时候,虽然还没有把整个数组排好序,但我们已经让 nums[p] 左边的元素都比 nums[p] 小了,也就知道 nums[p] 的排名了。

那么我们可以把 pk' 进行比较,如果 p < k' 说明第 k' 大的元素在 nums[p+1..high] 中,如果 p > k' 说明第 k' 大的元素在 nums[low..p-1]

进一步,去 nums[p+1..hi] 或者 nums[lo..p-1] 这两个子数组中执行 partition 函数,就可以进一步缩小排在第 k' 的元素的范围,最终找到目标元素。

本周小结

近期刷题状态、进度一般,仔细分析后发现主要由以下两个方面原因导致。一是刷题进入瓶颈期,征服新颖题目的新鲜感不如开始那么强烈,往往“欲速则不达”;二是由于题目难度提升,虽然解题思路能理解,但是实现较为困难,因为解题所采用的具体的STL模板和库函数还是不熟练,有好几次需要查新的东西,还有东哥的算法是Java实现的,而我需要改成C++。解决措施是,一是心态上还是不能着急,慢慢来,循序渐进,之前“欠债”太多,现在是痛苦的”还债“过程,不能急于求成;二是对于难题,在现阶段要懂得适当放过,把握其解法思路更为重要。同时,读《C++ Primer》加强对STL模板和库函数的理解;改变优快云的《C++后端学习日记》记录形式,不再粘贴具体的代码,不能为了粘贴代码而记录总结。

### C++ STL 常用于力扣的数据结构与函数示例 #### 数据结构部分 C++ 的 Standard Template Library (STL) 提供了许多高效且易于使用的数据结构,这些工具非常适合解决 LeetCode 上的各种算法。 1. **向量 `std::vector`** 向量是一个动态数组,能够自动调整大小并提供随机访问功能。它是许多目中最常用的基础容器之一。 ```cpp std::vector<int> vec; vec.push_back(10); // 添加元素到末尾 int value = vec.front(); // 访问第一个元素 ``` 2. **哈希表 `std::unordered_map`** 无序映射提供了平均时间复杂度为 O(1) 的键值存储和检索能力,在处理频率统计等问时非常有用。 ```cpp std::unordered_map<int, int> freqMap; freqMap[5]++; // 插入或更新键对应的计数值 if(freqMap.find(key)!=freqMap.end()) { /* 查找 */ } ``` 3. **集合 `std::set` / 多重集 `std::multiset`** 这些基于平衡二叉树实现的有序集合允许高效的去重以及范围查询操作。 ```cpp std::set<int> uniqueSet{7,8}; auto it = uniqueSet.insert(9).first; // 插入新元素并获取迭代器位置 bool exists = uniqueSet.count(7)>0 ? true : false ;// 判断是否存在某个特定值 ``` 4. **堆(优先队列)`std::priority_queue`** 使用大顶堆或者小顶堆来维护一组具有最高/最低优先级的对象列表,适用于求解最大最小K个数之类的问。 ```cpp std::priority_queue<int,std::vector<int>,std::greater<>> minHeap;// 小根堆定义方式 while(!minHeap.empty()){ cout<<minHeap.top()<<" "; // 输出当前堆顶元素 minHeap.pop(); } ``` 5. **双端队列 `std::deque`** 双端队列为两端都支持常数级别插入删除效率的理想选择,尤其适合滑动窗口类场景应用。 ```cpp deque<int> dq={1,2,3}; dq.emplace_front(-1); dq.emplace_back(4); ``` 6. **字符串流 `std::stringstream`** 字符串流可以帮助我们轻松完成格式化输入输出转换工作。 ```cpp string s="hello world"; stringstream ss(s); string word; while(ss>>word){ // 对每个单词做进一步处理... } ``` #### 排序与搜索函数 除了上述提到的标准模板库(STL),还有一些通用的功能性方法也值得了解: 1. **快速排序 `std::sort()` 或者自定义比较逻辑版本 `std::stable_sort()`** 能够方便快捷地对序列进行升序降序排列甚至更复杂的定制需求满足。 ```cpp vector<pair<int,int>> items={{3,'a'},{1,'b'}}; sort(items.begin(),items.end(), [](const pair<int,char>& a,const pair<int,char>& b)->bool{return a.first<b.first;} ); ``` 2. **二分查找 `std::binary_search`, `std::lower_bound`, `std::upper_bound`** 当目标区间已经处于有序状态时候,则可以通过这几个关联密切的方法加速定位过程。 3. **累积计算相关 `std::accumulate`** 方便地累加一系列数值总合或者其他形式的结果汇总运算。 ```cpp double avg= accumulate(v.begin(),v.end(),0)/double(v.size()); ``` 通过以上列举出来的几种核心组成部分及其简单实例演示可以看出,C++语言本身自的强大工具箱确实极大地方便了开发者们构建解决方案流程. ```cpp #include <bits/stdc++.h> using namespace std; int main(){ // Example usage of some structures and algorithms discussed above. } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值