![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C++刷题
文章平均质量分 72
三公子Tjq
三少爷的剑:剑气纵横三万里,一剑光寒十九洲!
展开
-
设计一个LRU(最近最少使用缓存)结构——C++
本体主要是设计一个LRU结构,LRU主要用在缓存策略上保证最近最少使用的数据页换出,从而提高CPU查找缓存的命中率。题目主要是设计一个结构类型struct Lru{};该类型包含两个成员方法get(int)和set(int,int),且要求这两个方法的时间复杂度为O(1)。查找时间复杂度为O(1)我们一般想到查表,比如std::unordered_map和std::unordered_set,但是题目还要求插入和删除数据也是O(1),这时一般的map和set和vector都不能满足要求,只有链表可以符合要求原创 2022-02-26 20:56:43 · 1111 阅读 · 0 评论 -
求最长不含重复字符的子字符串——C++
拿到题目第一想法是滑动窗口,用左left右right指针只差表示不重复子字符串长度,然后右指针依次右移动,假如入到重复字符,则更新左指针到不重复的字符串位置。比如abba,此时ab为不重复,当右指针移到abb时有重复字符,此时需要更新左指针到不重复的字符位置,也即abb的最后一个b的位置,此时左右指针指向同一个值。如何更新左指针到最近重复字符位置呢,此时需要用一个哈希表记录每个字符和对应字符的下标,并且遇到重复字符则更新为最近位置。关键代码如下:原创 2022-02-22 23:21:41 · 2644 阅读 · 0 评论 -
求回文链表——C++
2.1题目分析该题有三种常见解法,分别是递归、拷贝到数组再判断回文、反转后半部分链表。下面是采用后面两种方法解题。2.2反转后半部分链表由于回文是前后对称,故只需要反转链表后半部分内容,再与前面进行比较即可。找到链表后半部分源码如下:原创 2022-02-19 20:28:39 · 415 阅读 · 0 评论 -
一个简单计算器(不含括号和负数)实现——C++
根据题意要求,分析出需要给字符串去空格,以及采用栈方式将加减符号先压入栈,然后把乘除符号后面压入,并且最多压入两个元符号(+ *)就要清空符号栈。思路:1. 先去空格2. 符号栈,数字栈3. 提取字符+、-、*、/,提取数字val=val*10+str[i]-'0'4. 先运算*、/,结果压入栈,再把压入栈的+、-弹出运算5. 先遍历字符串数组,然后区分是加减号和乘除号。如果是加减号,则判空。如果为空则直接压入符号栈;非空则循环计算和消耗符号栈,知道符号栈为空为止。如果是乘除号,则判断。如果为原创 2022-02-08 23:09:39 · 777 阅读 · 0 评论 -
求最长回文子串——C++ (动态规划+暴力解法)
看到该题第一想法是暴力解法,即最长子串的长度从最长到最短开始遍历,假如前面出现回文则直接返回,代码可以参考最后面代码,不过该解法时间复杂度为O(^3)超过时间限制,故考虑动态规划。本题也是采用动态规划才通过啊,下面是具体分析1. 状态方程: f(i, j) = true 表示回文2. 状态转移方程: f(i, j) = f(i + 1, j - 1); i > 2, 考虑i = 0,i = 1边界3. 边界条件: f(i, i) = true; (i < n) f(i, i + 1) =原创 2022-02-07 23:15:23 · 2106 阅读 · 0 评论 -
求有向图起点0到终点n-1所有可能路径(深搜dfs)——C++
二、题目分析2.1思路分析该题主要求有向图起点到终点的所有可能路径。我们以前学过图的遍历分为深度优先搜索(DFS)和广度优先搜索(BFS),该题可以采用图的深度优先搜索(DFS)进行解题。进行DFS时从起点开始搜索,直到遇到终点n-1结束当前轮次搜索,此时说明已经找到一条连通路径。当从起点到终点的DFS所有可能经过节点全部遍历完一次后,所有可能的路径结果也就出来了。2.2代码实现分析知道思路,那么我们开始代码实现分析。首先需要封装一个dfs()函数,该函数输入四个参数分别为图数组gra原创 2022-01-22 22:35:22 · 1733 阅读 · 1 评论 -
求俄罗斯套娃信封问题——C++
如果前面掌握了最长上升子序列长度——C++题目,那么这题俄罗斯套娃信封问题将是非常简单,区别只在于在状态转移方程比较判断是将一维数组判断换成二维数组判断即可。原创 2022-01-14 23:46:42 · 700 阅读 · 0 评论 -
求最长递增子序列个数——C++
由于上一篇博客已经分析过求最长上升子序列长度——C++的经典LIS问题,该题是求最长增长子序列个数,经过分析,这题也只是经典LIS(Longest Increasing Subsequence)问题的变种,也就是用同样的LIS框架,区别在于本体需要额外记录每个最长子序列个数。下面是具体实现思路。用dp[i]记录最长子序列长度maxLen,count[i]记录最长子序列个数,其中i表示数组的元素个数,0 <= i < n;如果求出前dp[i]和count[i]的i-1元素的值,则可以推导出:1.2代码实现原创 2022-01-13 00:14:33 · 2570 阅读 · 0 评论 -
求最长上升子序列长度——C++
拿道题目,第一思路是先分析。求数组最长上升子序列,也就是意味着要遍历整个数组中所有子序列,这时可以考虑是否可以用动态规划。由于动态规划知识,知道这是一题线性动态规划的题目,可以采用线性动态规划解法,即使经典的LIS(Longest Increasing Subsequence)。动态规划满足三个条件:状态方程、状态转移方程、边界条件,根据分析可知该题满足条件,下面是分析的动态转移方程:1.2代码实现分析由上面的状态转移方程和表格可知,需要求有n个子序列长度的LIS,就必须先求出第0个,然后退出第原创 2022-01-05 23:49:16 · 1778 阅读 · 0 评论 -
二叉树的序列化和反序列化——C++
总体解题思想为先用层次遍历存储包括空节点的每个节点,存储是每个节点都存储左右子节点,如果节点为空,则存储"#,",否则存储节点的值val,同时用逗号','分割每个节点内容,存储完后进行序列化string。反序列化则先按逗号','分割每个字符串为数组字符串vector<string> valStrArr,该valStrArr存储每个节点的值,包括空节点;然后遍历valStrArr,反向构建原始二叉树。反向构建二叉树时由于存储是按层次遍历存入的,所以反向遍历时也需要按照层次遍历依次将非空节点压栈和弹出栈。由于层原创 2021-12-15 23:07:36 · 2523 阅读 · 0 评论 -
二叉树层次遍历(队列法、每层打印)——C++
由上面题目可知,输入是一个一维数组,输出是一个二维数组。其中输入一维数组中存储的是节点元素,输出二维数组是每层节点关键字打印。故知道该题主要考察二叉树基本的层次遍历方法,需要打印出每层节点的关键字。二叉树的层次遍历实现思路是用一个队列记录每层节点,当记录第一层节点时,弹出第一层节点进行访问,访问的同时需要遍历对应节点的左右子节点压栈;当访问完一层节点时,此时改成节点所有左右子节点都已经压栈,由于先前循环弹出了第一层的n个节点,故当前队列只存储下一层所有节点,所以只需要将该队列大小保存,然后该轮循环中弹出这原创 2021-12-08 21:12:47 · 2850 阅读 · 0 评论 -
二叉树后序遍历(递归法和迭代法(非递归法))——C++
一、二叉树后序遍历后序遍历是先遍历左子节点left,在遍历右子节点right,最后遍历父节点parent,即遍历顺序:1.2 迭代法由于后续遍历如果按照正常迭代思路去实现将不好理解和实现,仔细观察下面前序和后续遍历顺序,可以发现一个规律:前序遍历:parent ——> left ——> right前序遍历: left ——> right ——>parent,将后续遍历逆序过来遍历,则:parent ——> right ——>left通过观察1和3可以发现,两者都是先遍历父节点,再遍历左原创 2021-12-04 22:50:25 · 1858 阅读 · 1 评论 -
二叉树中序遍历(递归法和迭代法(非递归法))——C++
1.2迭代法迭代法是采用非递归方法实现二叉树的中序遍历,主要利用数据结构std::stack来实现,利用栈std::stack的先进后出特性依次压入待访问的节点,然后依次按照中序遍历顺序弹出和访问节点,确保每个节点有且仅有一次访问。具体步骤如下:a1 先将所有父节点和左子节点依次压入栈;这样做的目的是为了先弹出左子节点,再弹出父节点,可以在弹出左子节点的时候进行遍历,同时处理右节点,比如将右节点压入栈,这样就实现了先访问左节点,然后父节点,最后右子节点。a2 然后弹出一个节点,进行遍历;此时弹出a原创 2021-12-04 20:45:55 · 1763 阅读 · 1 评论 -
二叉树前序遍历(递归法和迭代法(即非递归法))——C++
一、前序遍历递归法前序遍历递归法主要是先遍历父节点parent,然后遍历左子节点,最后遍历右子节点,具体可以参考博客:二叉树基本知识点图文介绍(全网最简洁)_净无邪博客-CSDN博客。1.1具体解法如下:递归法的要诀是找到递归退出条件和按条件分步进行递归。具体解法比较简单,直接看代码和解释即可理解。二、前序遍历迭代法迭代法,也成为非递归法解前序遍历时,需要依靠一个栈数据结构依次遍历每一个节点。实现方法为将每个节点压入栈。注意,栈是先进后出结构,所以需要先压入右节点,再压入左节点,弹出的时候才能先原创 2021-12-03 22:31:03 · 4225 阅读 · 0 评论 -
桶排序算法——C++
桶排序算法是“分治法”的典型应用,主要思路是先“分桶”(或建捅)再“合桶”。其中最关键的是“分桶”,这一步最佳的时将整个待排序数组均匀分布在每个“分桶”内,然后再对每个“分桶”内部进行排序,最后将所有排序好的“分桶”依次遍历输出即可。这个思路感觉跟“计数排序算法”和“基数排序算法”十分相识。“计数排序”是通过下标将待排序数映射到“一个桶”内,然后再逐个取出;而“基数排序”是遍历所有“基数”,然后对每个基数进行一轮“计数排序”,最后完成整个数组排序。“桶排序”的“分桶”过程也是需要将待排序元素映射到“桶”原创 2021-12-01 23:58:31 · 1698 阅读 · 0 评论 -
基数排序算法——C++
基数排序的主要思想是选择多位基数依次进行排序,利用每次排序后还是相对有序,也就是稳定排序性质,依次比较完所有基数后,完成整个数组排序。其中,每次比较基数比如对整数进行排序时可以采用计数排序,因为整数位数有限并且每个位上的数值范围是0-9,所以最适合采用优化后计数排序对每个基数进行排序。时间复杂度为O(n + m),空间复杂度为O(n + m),其中n为数组个数,m为数组最大值位数。基数排序跟数组规模有关,假如规模很大的话,不一定比快速排序更优,故需要就具体数据模块进行分析。一、代码实现分原创 2021-11-26 23:53:11 · 2693 阅读 · 3 评论 -
计数排序算法——C++
计数排序是时间复杂度为O(n + m)的算法,空间复杂度为O(n + m);算法思想跟散列表哈希hash有些类似,主要是利用一段有序数组计算对应元素的下表个数,然后依次输出有数组元素进行排列。基本计数排序是不稳定算法,但是优化后计数排序是稳定算法。本文主要讲解基本计数排序和优化后计数排序。使用条件:数组必须是整数或者能全部映射为整数,数组所有元素必须在有限较集中范围;一、具体实现步骤1.计算原始数组的最大值max和最小值min范围,然后创建一个长度为max--min+1的排序数组sortAr原创 2021-11-24 23:48:56 · 3304 阅读 · 4 评论 -
希尔排序算法——C++
希尔排序是第一个在空间复杂度为O(1)条件下,将数组排序的时间复杂度降到O(logn^2)的算法,具有巨大历史意义,为后面的堆排序,快速排序提供了极大的启发和参考。故希尔排序时间复杂度为O(logn^2),空间复杂度为O(1)。希尔排序是对插入排序的一种改进算法,由于插入排序只在数据较少且基本有序时效率才是最佳的,故希尔排序原理将整个数组分为多个分组,然后分别进行排序。分组的其中一个原则是两个分组的元素尽量间隔较远,以消除逆序对,提高排序效率。由上一篇的堆排序可知,排序本质是对逆序对的消除,堆排序就原创 2021-11-18 00:01:58 · 3254 阅读 · 6 评论 -
插入排序算法——C++
插入排序算法主要是将待排序数组依次插入有序数组中,时间复杂度是O(logn^2),空间复杂度为O(1);下面是代码实现步骤:1.先假定数组左边第一个元素是有序的void Sorts::insert(vector<int>& nums){ if (nums.size() <= 1) return; ......}2.依次遍历待排数组的右边第二个元素到最后一个元素void Sorts::insert(vector<int原创 2021-11-13 18:06:26 · 2003 阅读 · 0 评论 -
求数组中的逆序对(时间复杂度为O(nlogn))C++代码实现
求数组中的逆序对,要求时间复杂度为O(nlogn),空间复杂度O(n)题目如下:(注:原题来自力扣的剑指 Offer 51. 数组中的逆序对)在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。示例 1:输入: [7,5,6,4]输出: 5思路分析:1.如果不考虑时间复杂度限制,则可以考虑暴力解法,即用双层循环即可遍历整个数组完成逆序对统计。int reversePairs(vector<int&g原创 2021-11-11 00:17:13 · 1075 阅读 · 0 评论 -
归并排序算法(优化版)——C++
关于归并排序的介绍可以参考这边博客:归并排序算法(经典返回变量版)——C++_净无邪博客-CSDN博客。本文主要是对递归排序进行优化。由于经典版本返回临时变量的归并排序效率比较低,需要多每次创建临时空间进行优化,使用一个固定内存空间,这样可以减少每次创建和销毁内存空间的时间消耗,由于这部分很费时间,所以优化效果是比较明显的。优化版跟基本版的区别主要区别如下:1.归并函数原来是入参两个数组,优化后入参为两个待排序数组合并在一起的起始和截止位置,如下所示:void merge1(vector&原创 2021-11-07 00:36:02 · 1160 阅读 · 0 评论 -
归并排序算法(经典返回临时变量版)——C++
归并排序算法思想主要是将两个有序数组合并成为一个有序数组,其关键点采用“分治思想”,“分”是二分法,将无序数组分割成为一个个有序数组,然后通过“治” 将两个有序数组合并成为一个有序数组。时间时间复杂度为为O(nlogn),空间复杂度是O(n)的常量级临时变量,是稳定排序算法。归并排序主要实现思想:采用“分治思想”,先“分”将整个无序数组先左边递归,再右边递归,类似二叉树先序遍历方法,将数组分为一个个有序数组;然后通过“治”将一个个有序数组通过合并merge方法组合成一个有序数组;1.“分”ve.原创 2021-11-06 22:06:56 · 626 阅读 · 2 评论 -
堆排序算法——C++
堆排序分为大顶堆排序和小顶堆排序,两者都是平均时间复杂度是O(nlogn),最坏时间复杂度是O(n^2),空间复杂度是O(1),是不稳定排序算法。大顶堆主要实现思想:1.初始化构建大顶堆void initMaxHeap(vector<int>& nums);2.将大顶堆的根(最大值)交换到数组最后面,然后将待排序数组长度减一后重新构建大根堆void buildMaxHeap(vector<int>& nums, int waitSortNod.原创 2021-10-30 00:12:34 · 307 阅读 · 0 评论 -
快速排序算法——C++
快速排序平均时间复杂度是O(nlogn),最坏时间复杂度是O(n^2),空间复杂度也是O(nlogn),是不稳定排序算法。主要实现思想:通过分区,首先选取基节点,基节点满足左边数据小于基节点,右边数据大于基节点;当完成一趟分区后,取得中间值,对左边数据同样进行分区满足“基节点左小右大”性质,对右边同样进行分区满足“基节点左小右大”性质,一直递归,直到左边数据哨兵指针大于等于右边哨兵指针即为结束条件。void Sorts::quick(vector<int>& nums, int原创 2021-10-27 23:57:30 · 365 阅读 · 0 评论