剑指Offer
baixiaofei567
如果十年前没种树,那最好的时间是现在
展开
-
两个链表生成相加链表
可以参考大数相加,只不过加上了链表反转的思想,总的来说就是模板题class Solution {public: /** * * @param head1 ListNode类 * @param head2 ListNode类 * @return ListNode类 */ ListNode* addInList(ListNode* head1, ListNode* head2) { // write code here.原创 2021-04-16 00:47:55 · 149 阅读 · 0 评论 -
最长公共子串
是那题我很喜欢的动态规划的升级版!!法一:二维dp法二:状压dp,从后往前,不用记录,因为不会改变左上的法三:状压dp,从前往后,要记录左上的。状压dp最重要的就是如果不相等记得将dp[j]设为0class Solution {public: /** * longest common substring * @param str1 string字符串 the string * @param str2 string字符串 the string * .原创 2021-04-16 00:47:08 · 139 阅读 · 0 评论 -
大数加法
不难,不管是数组,还是字符串,就用这个模板,不用考虑最后的进位什么的,也不用考虑越界什么的。但是sum是%10得来的,carry是/10得来的别搞反了。class Solution {public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 计算两个数之和 * @param s string字符串 表示第一个整数 * @param t string字符串 表示第二个整数 * @return st.原创 2021-04-14 00:26:26 · 142 阅读 · 0 评论 -
找到字符串的最长无重复字符子串
无重复或者异构就直接滑动窗口因为这里没有直接取出arr[r],当r++之后,我们要判断的是arr[r-1]对应的值,而不是arr[r]!!或者直接提前取出c = arr[r],然后ma[c]就行了。更新res是用max(res,r-l)这样子,没有+1-1哦class Solution {public: /** * * @param arr int整型vector the array * @return int整型 */ int maxLe.原创 2021-04-11 01:40:45 · 194 阅读 · 0 评论 -
剑指offer——剪绳子C++
数学题一向不会做,有点贪心的思想class Solution {public: int cutRope(int number) { //m<=n,m>1 if(number<3) return number-1; int a = number/3, b = number%3; if(b==0) return pow(3,a); if(b==1) return pow(3,a-1)*4; .原创 2021-01-08 02:04:16 · 104 阅读 · 0 评论 -
剑指offer——机器人的运动范围C++
简单的dfs,搞清楚是从一个点出发,还是可以从所有点出发class Solution {public: //dfs且不用回溯,要回头走别的路,但是是递归的自动回头,走过的路不能再走 //最主要是判断这个格子是否能走 void dfs(int rows,int cols,int i, int j, bool vis[], int threshold,int& res){ int index = i*cols+j; if(i<0||i&.原创 2021-01-08 02:02:55 · 200 阅读 · 0 评论 -
剑指offer——矩阵中的路径C++
dfs+回溯。此处回溯的思想大概就是自动回溯?1.char*和string可以直接比较。2.bool数组必须手动fill,不然不是全为false的。3.传输组,形参要写数组,实参写数组名,因为相当于传一个指针,所以回改变实参的值。class Solution {public: //此字符串不是二级指针,不会改变原来的值,所以不用erase尾部 //传的是一个数组,其实相当于传进去一个指向数组首部地址的指针,会改变原数组的值 bool dfs(char* matrix, ..原创 2021-01-07 01:53:23 · 195 阅读 · 0 评论 -
剑指offer——滑动窗口的最大值C++
暴力=easy。deque=hard。由于我们需要求出的是滑动窗口的最大值,如果当前的滑动窗口中有两个下标 ii 和 jj,其中 ii 在 jj 的左侧(i < ji<j),并且 ii 对应的元素不大于 jj 对应的元素(\textit{nums}[i] \leq \textit{nums}[j]nums[i]≤nums[j]),那么会发生什么呢?当滑动窗口向右移动时,只要 ii 还在窗口中,那么 jj 一定也还在窗口中,这是 ii 在 jj 的左侧所保证的。因此,由于 \textit{n.原创 2021-01-07 01:50:34 · 214 阅读 · 0 评论 -
剑指offer——数据流中的中位数C++(堆-优先队列)
vector加sort不香吗,时间复杂度O(nlogn),实际运行比这个更快诶。虽香但滚。因为是中位数,所以把左右分成两块,左边是大顶堆,右边是小顶堆。堆的插入时间复杂度为O(lgn),取值的时间复杂度就是O(1),因为就是取两个堆顶的操作。插入满足两个操作:1.两边的数据量之差不大于1,2.且左边全小于右边。所以我们的插入操作是,当前数据总量是偶数时,将其插入左堆(过程是先插入右,再将右的堆顶插入到左堆),奇数时反向操作。这样子就可以保证左堆>=右堆,且左边一定小于右边。取值时当前为奇数,就去.原创 2021-01-07 01:47:53 · 194 阅读 · 0 评论 -
剑指offer——序列化二叉树C++
/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { }};*/class Solution {public: //二叉树=递归||栈||队列 char* Serialize(TreeNode *root) { .原创 2021-01-06 02:08:43 · 184 阅读 · 0 评论 -
剑指offer——二叉搜索树的第k个结点C++
bst进行中序遍历,来个vector,最后返回第k个就行了,返回之前,判断k是否越界/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { }};*/class Solution {public: void inOrderTr.原创 2021-01-06 01:35:08 · 105 阅读 · 0 评论 -
剑指offer——把二叉树打印成多行C++
比上一题还简单/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { }};*/class Solution {public: void bfs(vector<vector<int>>& res.原创 2021-01-06 01:32:49 · 106 阅读 · 0 评论 -
剑指offer——按之字形顺序打印二叉树C++
按照层来,根为第一层,每一层将值加入vector中,如果当前层是2的倍数,就对该vector进行reverse,然后将该vec加入结果数组中,每一层都要讲vec清空/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { }};*/cla.原创 2021-01-06 01:31:17 · 190 阅读 · 0 评论 -
剑指offer——对称的二叉树C++
树=递归||队列||栈这道题就是用递归,递归入口是判断左右子树。递归边界:有3个,p1和p2均为空就是true,一个为空一个不为空就是false。递归式:如果这两个结点的值相等,才进行接下去的判断,否则返回false。递归式是判断p1的左子树和p2的右子树以及p1的右子树和左子树。均为真才是真。/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(i.原创 2021-01-06 01:26:29 · 126 阅读 · 0 评论 -
剑指offer——二叉树的下一个结点C++
分情况讨论,要画出图来判断/*struct TreeLinkNode { int val; struct TreeLinkNode *left; struct TreeLinkNode *right; struct TreeLinkNode *next; TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { }};*/class Solution {.原创 2021-01-05 02:33:13 · 136 阅读 · 0 评论 -
剑指offer——删除链表中重复的结点C++
因为是有序链表,所以依次和后一个比较即可。三个指针,一个作为pHead的前驱,用来最后返回整条链表。一个是工作结点,一直往后。一个是pre结点,指向确定不是重复的结点。如果下一个结点不为空(必须写)且当前值和下一个结点值相等,就进入循环,一直找到第一个和下一个结点不等的结点,但是此时的cur还是那个重复结点,所以cur要指向下一个,并将pre指向cur。但是现在这一个不能保证它是不重复的,所以再次进入循环。如果当前和下一个不等了,就将pre和cur都往后移一格。/*struct ListNode .原创 2021-01-05 02:32:10 · 168 阅读 · 1 评论 -
剑指offer——链表中环的入口结点C++
链表=空间鲁棒性=双指针法一:map法二:双指针,先通过快慢指针判断是否有环。如果无就直接返回空,如果有,就将一个结点重新放回起点,另一个还在相遇点,让它俩速度一样,一次走一步,最后相遇的点的就是环的入口。链表头到环入口长度为–a环入口到相遇点长度为–b相遇点到环入口长度为–c则:相遇时快指针路程=a+(b+c)k+b ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。慢指针路程=a+b快指针走的路程是慢指.原创 2021-01-05 02:23:35 · 164 阅读 · 0 评论 -
剑指offer——字符流中第一个不重复的字符C++
直接图方便了,来一个string和一个map,每次insert就加在s后面,并记录该字符出现次数。在first函数中,遍历该字符,找到第一个出现一次的返回即可。class Solution{public: //Insert one char from stringstream void Insert(char ch) { s += ch; ma[ch]++; } //return the first appearence once .原创 2021-01-05 02:06:00 · 200 阅读 · 1 评论 -
剑指offer——正则表达式匹配C++
难点有21:理清思路很难。2:"“的匹配有很多情况不知道到底是匹配几个很难。这里我们用的是递归求解。分情况:先看pat的下一个是否为” * “,如果是,那么又有两种情况,当前位是否匹配,如果当前位匹配(可以用两个字符串当前字符相等或者pat当前字符为”.“来判断),那么要看接下来这个”“到底要匹配多少次了。第一种情况aa和aaa,匹配0次;第二种情况aa和aa,匹配1次;第三种情况aaab和a*b匹配多次。所以我们递归判断每一种情况,只要有一种为true,那么就是true,用||运算符。匹配0次是st.原创 2021-01-05 02:04:03 · 252 阅读 · 0 评论 -
剑指offer——构建乘积数组C++
不能用除法,一种方法就是从0遍历到n-1,计算每个B[i],O(n^2)的时间复杂度。另一种方法B[i]可以看做第i行的乘积,也就是A数组的0到i-1相乘 * A数组的i+1到n-1相乘。根据推导可以得B[i]的前一半 = B[i-1]*A[i-1],B[I]的后一半 = B[i+1]*A[i+1],将这两半的结果分别计算再相乘即可。左右分开算时,左右的首尾都先设为1,从第二位开始计算class Solution {public: vector<int> multiply(co.原创 2021-01-05 01:46:49 · 127 阅读 · 0 评论 -
剑指offer——数组中重复的数字C++
法1就是用map,如果map对应的值==1了就证明找到重复了。如果不为1,就对应的值++。法2:高级法,因为所有数字的范围是0到n-1,如果没有重复,那么每一位就在每一位的位置上,0就在0号位,1就在1号位。如果有重复,那么就会发生抢位的情况。遍历该数组,如果在自己的位置上,就continue。如果不在,就判断当前的值和它本来该放的位置的值是否相等,如果相等,那么就是找到重复的了,直接return true。如果不等,就把它放回该放的位置,用swap即可。#include<unordered_m.原创 2021-01-04 02:18:43 · 194 阅读 · 0 评论 -
剑指offer——把字符串转换成整数C++
不难,先记录第一位是否是+or-,设置flag。然后反向遍历字符串,如果不是合法字符,就return0,如果是,就让res+=这一位*pow(10,length-i-1),最后一位是个位就×pow(10,0)class Solution {public: int StrToInt(string str) { //从后往前遍历到第1位,第0位不要,如果遍历到非法字符,直接返回0 //用pow(10,lenght-1-i)*当前位即可 int re..原创 2021-01-04 02:09:27 · 213 阅读 · 0 评论 -
剑指offer——不用加减乘除做加法C++
不能用加减乘除,就想到位运算。异或^,相同为0,相异为1,用来模拟没有进位的加法。与运算&,均为1才是1,得出&结果后左移一位就是进位,要让前面异或后的结果加上这个进位。循环结束的条件是进位为0,证明不用进位了,已经得到结果了。class Solution {public: int Add(int num1, int num2) { //不能用+法就用位运算? //循环结束的条件是进位为0,证明不用进位了,已经得到结果了 .原创 2021-01-04 02:01:13 · 146 阅读 · 0 评论 -
剑指offer——求1+2+3+...+nC++
不能用for和while循环,就要用递归。不能用if判断就用短路求值,短路就相当于一个判断语句。递归:递归边界就是n==0,如果&&前的为false,那么后面的也不执行了,直接返回n。递归式是n += f(n-1),递归加上n-1,如果前面为true,后面的递归式会继续执行。class Solution {public: int Sum_Solution(int n) { //短路求值+递归 //不能用循环就递归,不能判断就用短路 .原创 2021-01-04 01:48:48 · 226 阅读 · 0 评论 -
剑指offer——扑克牌顺子C++
先排序,然后遍历该数组,计算大小王个数。然后再次遍历,判断连续两个数字是否有相同的,如果有就直接false。如果不同就将flag - (后一个数字-前一个数字-1),比如1,2,flag减去的就是0,就是不消耗大小王。如果是1,3那么flag-1,就是要消耗掉一个大小王。最后判断flag是否小于0,如果小于0,就是falseclass Solution {public: bool IsContinuous( vector<int> numbers ) { //用se.原创 2021-01-04 01:45:25 · 259 阅读 · 0 评论 -
剑指offer——翻转单词顺序列C++
不用栈这么麻烦,用好string的加法就行了。逐个遍历该字符串,如果不为空,就将tmp加上该字符。如果为空,证明一个单词结束了,将res 加上空格加上tmp加上res,因为这个后加的tmp其实是在前面的,而且它前面一定有空格,记得清空tmp。遍历完后,判断tmp是否为空,因为遍历到最后一个单词,最后一位可能是空格也可能不是,如果是空格,那么就在循环里搞定了,如果不是,那么最后的tmp还没加上,通过tmp的长度判断,如果不为0,就res = tmp + res。最后返回res。用栈可能还过不了,毕竟这些空.原创 2021-01-03 01:35:26 · 144 阅读 · 0 评论 -
剑指offer——左旋转字符串C++
两个方法(均用了string的内置函数,可能达不到面试官想要的)1.用string的构造函数,参数为两个迭代器,构造出两个string最后返回。注意是前闭后开区间,所以begin()+n和end()都取不到。2.用substr函数,这里两个重载。第一个两个参数分别是起始位置和复制个数,第二个的参数是从第n位开始复制到结尾。class Solution {public: string LeftRotateString(string str, int n) { if(str.l.原创 2021-01-03 01:30:12 · 144 阅读 · 0 评论 -
剑指offer——和为S的连续正数序列C++
两个方法,不知道为什么暴力比滑动窗口更耗时??1.暴力,因为最多只能到sum/2+1,比如9,就有4和5,所以要一直推到5为止。2.滑动窗口,定义两个指针,从1和2开始往后走,如果当前窗口内的值等于sum就加入数组,如果大于就将前一个指针++,缩小窗口。如果小于就将后一个指针++,扩大窗口。当两者相等时退出循环(用Low!=sum/2+1也行)。为什么是相等退出循环呢,因为窗口值太大才会让low++,如果一直加到等于high,证明已经没办法缩小窗口了。区间求和,就要想到滑动窗口class Solu.原创 2021-01-03 01:25:11 · 164 阅读 · 0 评论 -
剑指offer——数组中只出现一次的数字C++
两种方法1.记录次数、个数啥的都考虑哈希表,如果没有好的办法就用这个2.位运算我们先来看一个比较简单的情况,如果数组中只有一个数字出现一次,其他都出现两次。那么我们应该可以想到异或运算(^),与运算(&)是均为1才是1,其他均为0。异或运算有一个比较好的性质是:相同为0,相异为1。也就是说,任何一个数字异或它自己都等于0,而0异或任何数都等于那个数。因此,我们从头到尾依次异或数组中的每个数字,那么最终结果刚好是那个只出现一次的数字,重复的数字在异或过程中被抵消了。这是一种比较巧妙的思路,然.原创 2021-01-03 00:56:53 · 223 阅读 · 0 评论 -
剑指offer——平衡二叉树C++
判断左右子树的高度之差的绝对值是否大于1即可class Solution {public: int getDepth(TreeNode* root){ if(root == nullptr) return 0; return max(getDepth(root->left),getDepth(root->right))+1; } bool IsBalanced_Solution(TreeNode* pRoot) { i.原创 2020-12-30 02:08:33 · 156 阅读 · 0 评论 -
剑指offer——二叉树的深度C++
递归和循环两种方法/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { }};*/class Solution {public: int bfs(TreeNode* root){ queue<TreeNode*> q; q.pus.原创 2020-12-30 02:07:22 · 129 阅读 · 0 评论 -
剑指offer——数字在升序数组中出现的次数
有序数组一定是二分,二分查找查找一个数字的时间复杂度是O(logn),比直接遍历数组好多了。这道题我们找出第一次出现k的下标和第二次出现k的下标,两者相减+1即可,找第一次出现的下标,因为是递归,递归边界就是lo>hi(为啥自己推去)。如果mid位的值小于k,证明去后半部分找,mid位的值大于k,证明去前半部分找。如果等于,就判断mid的前一位是否为k,如果为k,就去前半部分找(mid位直接舍弃,因为它肯定不可能是第一位了),如果前一位不是,就返回mid。找最后一位也是类似。class Solu.原创 2020-12-30 02:05:49 · 128 阅读 · 0 评论 -
剑指offer——两个链表的第一个公共结点C++
链表题一定要想到快慢指针三种方法:1.用一个map记录第一条链表每个结点是否出现,遍历第二条时判断即可。2.我称之为相亲相爱法,因为两条链表的长度不确定,所以让两个指针分别走1+2两条链表的长度就可以了,这样走的就是相等了。两个结点相等时退出循环(这样就算两个结点都指向空结点也不会死循环)。当1为空,就让1指向链表2的头,2为空,就让2指向链表1的头。3.算出两条链表的长度len1和len2,假设len1>len2,就让链表1的指针先走len1-len2步,然后再一起走就行了/*stru.原创 2020-12-30 01:59:26 · 166 阅读 · 0 评论 -
剑指offer——数组中的逆序对C++(75%)
非常好的题,利用了归并排序的特性。#include<vector>class Solution {public: //cop[left...mid]是有序的,cop[mid+1...right]是有序的 /*int mergeAndCount(vector<int>& cop, int left, int mid, int right, vector<int>& fuzhu){ //先全放入辅助数组中,然后按序放回原.原创 2020-12-30 01:52:21 · 263 阅读 · 0 评论 -
剑指offer——第一个只出现一次的字符C++
开一个map,第一遍历记录每个字符出现的顺序,第二次遍历判断该字符是否只出现了一次,如果是就返回它的下标。因为第二次遍历在前面的字符一定先被遍历到,所以就算后面也有只出现了一次的字符也无所谓。class Solution {public: int FirstNotRepeatingChar(string str) { //有可能你把它消掉之后,后面还会再次出现 //暴力试试 if(str.length() == 0) return -1; .原创 2020-12-30 01:05:25 · 198 阅读 · 0 评论 -
剑指offer——丑数C++
hard通俗易懂的解释:首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,我们发现这种方***得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的。那么我们可以维护三个队列:(1)丑数数组: 1乘以2.原创 2020-12-28 00:52:52 · 186 阅读 · 0 评论 -
剑指offer——把数组排成最小的数C++
全部转为字符串存入数组,对其进行sort即可。主要是cmp函数比较难写sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数,否则会报错。因为:非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的,因此无法再sort中调用非静态成员函数。静态成员函数或者全局函数是不依赖于具体对象的,可以独立访问,无须创建任何对象实例就可以访问。同时静态成员函数不可以调用类的非静态成员。C++中的字符串可以直接比较大小,cmp比较的结果,决定了排序方式(升序或者降.原创 2020-12-28 00:50:46 · 189 阅读 · 0 评论 -
剑指offer——整数中1出现的次数(从1到n整数中1出现的次数)C++
我又不是ACMer,我怎么会做这么难的题。设N = abcde ,其中abcde分别为十进制中各位上的数字。如果要计算百位上1出现的次数,它要受到3方面的影响: style=“color: rgb(255,0,0);”>百位上的数字,百位以下(低位)的数字,百位以上(高位)的数字。① 如果 style=“color: rgb(255,0,0);”>百位上数字为0,百位上可能出现1的次数由更高位决定。比如:12013,则可以知道百位出现1的情况可能是:100199,11.原创 2020-12-28 00:39:26 · 135 阅读 · 0 评论 -
剑指offer——连续子数组的最大和C++
动态规划,之前做了几个动态规划都是用dp[i-1]来推导dp[i],但是这里不是这么简单的。https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/1.2-zi-xu-lie-lei-xing-wen-ti/zui-da-zi-shu-zuclass Solution {public: int FindGreatestSumOfSubArray(vector<int> array) { //主要是写出转.原创 2020-12-28 00:36:40 · 163 阅读 · 0 评论 -
剑指offer——最小的K个数C++
现在的Partion法并不能AC有三种方法:1.sort之后,返回vector(input.begin().input.begin()+k);即可2.前一种用了sort,时复为O(NlogN),不行。因为是要k个最小的数,我们应该想到维护一个k个元素的大顶堆,当堆满的时候,将堆顶元素和想要插入进来的元素进行比较,如果比堆顶元素小,就弹出堆顶元素并加入当前元素,内部自动会帮你排序。我们可以用multiset<int,greater>或者priority_queue来实现堆。multiset.原创 2020-12-28 00:29:59 · 139 阅读 · 0 评论