剑指Offer
刷各种算法题时,总结的一些知识点,小技巧
Jiu_R
coder
展开
-
剑指Offer51.数组中的逆序对
题目:剑指Offer51.数组中的逆序对求一个给定数组的逆序对数;数组长度1<= n <= 50000;思路:最坏情况下,数组逆序,则逆序对数为(1 + 49999) * 49999 / 2 ≈12亿,因此用int存是可以的;1.归并排序:时间O(nlogn),空间O(n)分:将整个区间查找逆序对分成左右子区间的问题,整个区间[L,R]的逆序对数 = 左区间[L,mid]的逆序对数 + 右区间[mid,R]的逆序对数 + 左右区间各一个数的逆序对数;治(合并阶段): 本质上是 .原创 2021-03-17 20:22:06 · 157 阅读 · 0 评论 -
剑指Offer68-II.二叉树的最近公共祖先
题目:剑指Offer68-II.二叉树的最近公共祖先给定一棵二叉树和两个目标节点p,q,找到p,q的最近公共祖先;与剑指Offer68-Ⅰ.二叉搜索树的最近公共祖先相比,无法使用有序这一点,因此只能爆搜,找到p,q,再找到最近公共祖先,再一层一层传回根;思路:1.dfs:时间O(n):遍历所有节点,唯一不需要搜的节点是p,q的子孙,因为我们目标是找p,q的祖先,至于p,q的子孙长什么样无所谓,所以找到p或q就直接往上层回退了,无需递归左右孩子,空间O(n):最坏情况是退化为单链表时,递归深度..原创 2021-03-07 23:07:41 · 76 阅读 · 0 评论 -
剑指Offer68-I.二叉搜索树的最近公共祖先
题目:剑指Offer68-I.二叉搜索树的最近公共祖先寻找一棵二叉搜索树中的两个节点p,q的最近公共祖先;思路:1.递归:时间O(n):最坏情况下退化成单链表时,且p,q位于单链表的最后两个节点,空间O(n):同样,最坏情况下,递归深度为n利用二叉搜索树的有序特性,题目给出了p,q节点,因此可以根据两节点大小和当前根节点大小的关系,确定出两节点在何位置;这样从上往下,直接一次性找到最近公共祖先;class Solution {public: TreeNode* lo..原创 2021-03-07 21:13:05 · 76 阅读 · 0 评论 -
剑指Offer67.把字符串转换成整数
题目:剑指Offer67.把字符串转换成整数实现stoi;思路:1.模拟遍历:时间O(n):最多需要编译一次,如果不符合条件的话,甚至不需要遍历结束,空间O(1)class Solution {public: int strToInt(string str) { if (str.empty()) return 0; int n = str.size(); int i = 0; while (i &..原创 2021-03-07 20:36:17 · 169 阅读 · 0 评论 -
剑指Offer66.构建乘积数组
题目:剑指Offer66.构建乘积数组输入一个数组a,要返回一个数组b,且b[ i ]=数组a中除了a[ i ]以外其它所有元素的乘积思路:1.dp两次遍历:O(n),O(1)正常思路是:b[ i ] 相当于在b [ i - 1 ] 的基础上,乘a [ i - 1 ] ,除a [ i ] ,这样只需遍历一次O(n);本题不能使用除法,想到从左往右遍历,若只看b [ i ]和b [ i - 1 ]左侧的区别,就是在b [ i - 1]基础上 多乘了个a [ i - 1 ];但右侧的区别是除了..原创 2021-03-07 19:54:26 · 78 阅读 · 0 评论 -
剑指Offer65.不用加减乘除做加法
题目:剑指Offer65.不用加减乘除做加法求两个int类型数a+b;结果不会溢出 32 位整数思路:这种限制±*/操作符,或者限制if,else,for,while语句的题,可选的方式往往有:利用&&或||的短路效应,位运算1.位运算:将求a+b转换为求进位部分+不进位部分;进位部分:要找到a和b的对应二进制位均为1的地方(用&),然后<<1,就相当于进位操作;不进位部分:a ^ b本身就被称为不进位加法;用a和b分别代表进位部分和不进位部..原创 2021-03-07 19:22:50 · 222 阅读 · 0 评论 -
剑指Offer64.求1+2+...+n
题目:剑指Offer64.求1+2+…+n思路:1.&&或||短路效应实现递归:class Solution {public: int sumNums(int n) { !n || (n += sumNums(n - 1));// ||优先级高于+= return n; }};2.sizeof实现n * (n + 1) / 2:天秀!class Solution {public: int sumNums(int n.原创 2021-03-06 18:10:02 · 81 阅读 · 0 评论 -
剑指Offer63.股票的最大利润
题目:剑指Offer63.股票的最大利润数组prices的每个元素表示当天的股票价格;只能进行一笔交易(即某一天买入,之后的某一天卖出),求最大利润;思路:1.dp:O(n):扫一次,O(1):当天卖出能获得的最大利润只与截止到目前的历史最低值minVal有关;如果第i天我们想卖,那么我们一定希望是历史价格最低的那天买入的,这样利润才会最大;因此我们每天都尝试卖出,并且买入价格都按历史最低算;class Solution {public: int maxProfit(ve..原创 2021-03-06 17:57:36 · 62 阅读 · 0 评论 -
剑指Offer61.扑克牌中的顺子
题目:剑指Offer61.扑克牌中的顺子A对应1,2 ~ 10对应2 ~ 10,JQK对应11,12,13,大小王为万能牌;输入一个长为5的数组,判断是否能构成一个链(类似于1,2,3,4,5)思路:1.益智题:时间O(n):遍历一次,空间O(n):需要一个大小为5的哈希表满足要求的条件:① 非0牌不能重复 ② 非0牌差距不能过大,例如要想构成1,2,3,4,5,非0牌的的边界为1和5,其它牌只能位于1,5之间或有大小王;class Solution {public: bo..原创 2021-03-06 16:57:40 · 237 阅读 · 0 评论 -
剑指Offer59-Ⅱ.队列的最大值
题目:剑指Offer59-Ⅰ.队列的最大值实现三个O(1)的API;思路:1.用deque维护一个不严格单减队列:和剑指Offer59-Ⅰ.滑动窗口的最大值思路一样,只不过59-Ⅰ维护的窗口是固定大小,每当窗口右移的时候都要考虑是否要弹出队首,而本题对大小没有限制,只有调用pop_front()API时才需要考虑弹出的是不是队首(最大值)class MaxQueue {public: queue<int> q; deque<int> dq;..原创 2021-03-06 15:53:55 · 61 阅读 · 0 评论 -
剑指Offer59-Ⅰ.滑动窗口的最大值
题目:剑指Offer59-Ⅰ.滑动窗口的最大值输入一个数组nums和一个int k,k表示窗口大小;返回一个数组,表示nums从左往右的所有大小为k的窗口中的最大值;在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小;思路:若nums长为n,[ 0,k-1 ] 是第一个窗口,[ n - k, n - 1 ]是最后一个窗口,对于每个窗口都要求最大值;首先只能遍历窗口的起始位置O(n);对于每一个长为k的窗口,要想求最大值:① 暴力遍历当前窗口的所有值,需要O(k)时间 ②如何随着..原创 2021-03-06 15:29:42 · 125 阅读 · 0 评论 -
剑指Offer58-Ⅰ.左旋转字符串
题目:剑指Offer58-Ⅰ.左旋转字符串把一个给定字符串s的前k个字符和后面的字符交换位置;思路:1.整体翻转+局部反转2次:时间O(n),空间O(1)class Solution {public: void reverse(string& s, int l, int r) { for (; l < r; ++l, --r) { swap(s[l], s[r]); } } string revers.原创 2021-03-06 10:17:22 · 69 阅读 · 0 评论 -
剑指Offer58-Ⅰ.翻转单词顺序
题目:剑指Offer58-Ⅰ.翻转单词顺序输入一个字符串s表示一句若干单词构成的一句话;s可能前面,后面,或单词之间有若干空格;需要将s的每个单词顺序翻转,但每个单词自身的字母顺序不能翻转;最后得到的字符串首尾不能有空格,且字母之间的空格只留一个;思路:1.快慢双指针:时间O(n):只需快指针从尾遍历到头,空间O(n):额外需要一个字符串res,最坏情况下,s没有多余空格,因此res的大小和s相同;从后往前划分单词,每找到一个单词[ i + 1,j ]就放到res后面,并添加一个空格作..原创 2021-03-06 10:03:32 · 102 阅读 · 0 评论 -
剑指Offer57-Ⅱ.和为s的连续正数序列
题目:剑指Offer57-Ⅱ.和为s的连续正数序列思路:1.暴力双循环:枚举每个位置为起始点 i ,枚举终点 j 从 i+1开始;class Solution {public: vector<vector<int>> findContinuousSequence(int target) { vector<vector<int>> vec; vector<int> res;//重复利用res和su.原创 2021-03-05 20:50:51 · 98 阅读 · 0 评论 -
剑指Offer57.和为s的两个数字
题目:剑指Offer57.和为s的两个数字一个有序数组nums,返回任意一对和为target的数字;思路:1.哈希表:时间O(n):遍历一次,最坏情况下目标数在数组末尾,就需要把n-1个数都insert进哈希表,insert操作是O(1),空间O(n):最坏需要存n-1个数class Solution {public: vector<int> twoSum(vector<int>& nums, int target) { unor..原创 2021-03-05 18:17:50 · 75 阅读 · 0 评论 -
剑指Offer56-Ⅱ.数组中数字出现的次数Ⅱ
题目:剑指Offer56-Ⅱ.数组中数字出现的次数Ⅱ输入一个数组nums,其中只有一个数出现一次,其余数均出现3次;找到那个出现一次的数;1 <= nums.length <= 10000;(说明n ^ 2也可以)1 <= nums[i] < 2^31思路:1,2常规思路,3,4好办法1.哈希表:时间O(n):扫两次nums,空间O(n):几乎每个数都出现3次,因此哈希表只需要存n/3的数即可;class Solution {public: int..原创 2021-03-05 17:21:50 · 117 阅读 · 0 评论 -
剑指Offer56-Ⅰ.数组中数字出现次数
题目:剑指Offer56-Ⅰ.数组中数字出现次数一个数组仅有两个出现一次的数字,其它数字均出现两次;数组长度 >= 2(意思是说一定存在这样的两个目标数);思路:1.分组异或:时间O(n):遍历两次,空间O(1)第一次遍历:将所有数异或得到ab,ab就是那两个目标数的亦或结果,由于这俩数不同,因此ab一定不为0。找到ab的二进制任意为1的位mask(之所以该位为1,就是因为这俩目标数的该位不同),为了方便直接找二进制为1的最低位;第二次遍历:借助这点把数组分成两组,主要目的就是为了..原创 2021-03-05 15:03:15 · 101 阅读 · 0 评论 -
剑指Offer55-Ⅱ.平衡二叉树
题目:剑指Offer55-Ⅱ.平衡二叉树判断一棵输入的二叉树是不是平衡二叉树;思路:判断条件:二叉树的任意节点(不为空的话)的左右子树的高度差 <= 1;空节点也是平衡二叉树;既然也是求高度,那就类似于剑指Offer55-Ⅰ.二叉树的深度,返回值为当前子树的高度,差别在于:如果当前节点的左右子树高度差 > 1,以何种方式标识当前节点已经不平衡了;1.后序遍历:后序遍历就是从树的最下层往上处理//写法1:通过全局变量res标识,由于判断条件只有abs(lheight - rhei.原创 2021-03-05 10:53:51 · 60 阅读 · 1 评论 -
剑指Offer55-Ⅰ.二叉树的深度
题目:剑指Offer55-Ⅰ.二叉树的深度输入一个二叉树,求二叉树的深度(即节点的最大深度最下层叶子节点的深度根节点的高度)思路:求高度:后序遍历 或 层序遍历;求深度:前序遍历1.递归后序遍历:时间O(n),一般情况O(h),h为二叉树的深度,最坏情况,当退化为单链表时,递归深度为n层,空间 O(n)class Solution {public: int res; int dfs(TreeNode* root) { if (!root) return..原创 2021-03-05 10:20:03 · 103 阅读 · 1 评论 -
剑指Offer53-Ⅱ.0~n-1中缺失的数字
剑指Offer53-Ⅱ.0~n-1中缺失的数字题目:一个长度为n-1的排序数组,数字都是[ 0,n - 1 ];每个数字仅出现一次,找出那个唯一缺失的数字;注:通常习惯与数组长度为n,总之题目表达的意思是,长为n的数组,值得范围均在[ 0,n ],即n个坑想放n+1个数,则一定有且仅有一个数不存在;下面均以数组长度为n解释;思路:1.遍历一次,找到第一个值和下标不同的位置:时间O(n),空间O(1)长为n的数组下标范围:[0,n - 1 ],若数字都放在正确的位置,则缺失的就是n;否则一.原创 2021-03-04 17:28:54 · 79 阅读 · 1 评论 -
剑指Offer54.二叉搜索树的第k大节点
剑指Offer54.二叉搜索树的第k大节点题目:输入一个二叉搜索树,返回它的第k大节点值;1 <= k <= 二叉搜索树的节点数(即不用担心树为空,也不用担心不存在第k大的情况);思路:1.逆序中序遍历:时间O(n):当二叉搜索树退化为只有右孩子的单链表时,无论k为几,递归深度都为n层(因为右中左的遍历顺序需要先走到右下角才回退,即使找到第k大节点,依然要逐层回退到根节点),空间O(n):同理,最坏情况下需要n层系统栈;对二叉搜索树中序遍历得到的是从小到大的,本题要第k大,因此要‘.原创 2021-03-04 11:22:10 · 95 阅读 · 1 评论 -
剑指Offer52.两个链表的第一个公共节点
剑指Offer52.两个链表的第一个公共节点题目:找两个链表的第一个交点;思路:1.双指针浪漫相遇:时间O(m+n):m和n分别是两链表的长度,空间O(1)pa和pb走过一样的路,在交点相遇;若两链表本身不相交,那么在各自走完m+n步后,会同时走到对方的链表尾,同时为nullptr,因此不用担心无限循环;class Solution {public: ListNode *getIntersectionNode(ListNode *headA, ListNode *he..原创 2021-03-03 22:17:47 · 66 阅读 · 1 评论 -
剑指Offer50.第一个只出现一次字符
剑指Offer50.第一个只出现一次字符题目:输入一个字符串s,返回第一个出现次数为1的字符,若没有这样的字符,就返回一个空格;字符仅有26个小写字母;思路:1.哈希表 + 两次遍历:O(n),O(1)class Solution {public: char firstUniqChar(string s) { int v[26] = {0}; for (auto c : s) {//第一次遍历s,统计每个字符出现的次数 ..原创 2021-03-03 22:00:26 · 125 阅读 · 1 评论 -
剑指Offer48.最长不含重复字符的子字符串
剑指Offer48.最长不含重复字符的子字符串题目:输入一个字符串s,返回其中最长的一段不含重复字符的子串长度;思路:1.双指针 + 滑动窗口:O(n),O(128):字符最多有128个[ i,j ]表示一个不含重复元素的窗口;尽可能不断后移 j ,一旦窗口内出现重复字符,就把窗口的左边界 i 移到重复字符的右边,即把左边界跳过这个重复字符;class Solution {public: int lengthOfLongestSubstring(string s) {..原创 2021-03-03 21:34:39 · 64 阅读 · 1 评论 -
剑指Offer47.礼物的最大价值
剑指Offer47.礼物的最大价值题目:一个m*n的矩阵,每个格子上都放着一个礼物,且价值均 > 0;从左上角走到右下角的所有路径中,返回价值的最大;思路:1.暴力dfs递归:时间O(2 ^ (m*n)):指数时间复杂度超时,因为(除了第0行,第0列)其它每个格子需要递归2次,空间O(max(m,n)):对于一个格子,只能向右或者下,因为是dfs,所以这两个格子的递归用的是同一块系统栈;class Solution {public: int res; vo..原创 2021-03-03 19:03:57 · 109 阅读 · 1 评论 -
剑指Offer46.把数字翻译成字符串
剑指Offer46.把数字翻译成字符串题目:给一个int num,0 ~ 25分别可以翻译成a ~ z,输出num有多少种翻译方法;思路:1.dp:时间O(log10 n):遍历num的每位数,O(log10 n):额外需要一个dp数组和stringclass Solution {public: int translateNum(int num) { if (num >= 0 && num < 10) return 1; ..原创 2021-03-03 16:58:22 · 84 阅读 · 1 评论 -
剑指Offer45.把数排成最小的数
剑指Offer45.把数排成最小的数题目:把一个vector,使其每个元素值接起来得到的值最小;考虑大数,需要用string保存结果;思路:1.指定一个排序规则:时间O(nlogn),最坏O(n^2),空间平均O(n),最优O(logn)//写法1:class Solution {public: string minNumber(vector<int>& nums) { string res; if (nums.em..原创 2021-03-02 21:32:36 · 88 阅读 · 7 评论 -
剑指Offer43.1~n整数中1出现的次数
剑指Offer43.1~n整数中1出现的次数题目:输入一个int n,输出整数1~n的10进制表示中1出现的次数;思路:1.逐位统计10进制下个位,十位,百位,。。。,最高位出现1的个数:时间O((log10 n) ^ 2):一个数字n共有log10 n位,每层循环内求l和r的操作也需要log10 n,因此共为(log10 n) ^ 2,空间为(log10 n),额外需要一个数组class Solution {public: int countDigitOne(int ..原创 2021-03-02 14:50:16 · 84 阅读 · 0 评论 -
剑指Offer41.数据流中的中位数
剑指Offer41.数据流中的中位数题目:随着数据流的不断addNum,随时求截止到目前为止数据流的中位数findMedian;数据流相当于一个int数组;思路:中位数:排序数组的中间位置的数;1.一个大顶堆,一个小顶堆:大顶堆放排序数组的前一半较小的值,小顶堆放排序数组较大的后一半较大的值;如果数组长度为奇,则class MedianFinder {private: priority_queue<int> big;//大顶堆,放的是数据流中最小的那一半 .原创 2021-03-02 09:29:45 · 80 阅读 · 0 评论 -
剑指Offer39.数组中出现次数超过一半的数字
剑指Offer39.数组种出现次数超过一半的数字题目:找出一个数组中出现次数超过一半的数字;思路:1.(最优解)摩尔投票:O(n),O(1)目标数个数超过一半,哪怕剩下所有数联合起来对付我也是我赢,更何况其它数也可能内讧;class Solution {public: int majorityElement(vector<int>& nums) { int cnt = 0, val;//当前目标数val,以及一个计数器cnt(cnt并..原创 2021-03-01 10:33:51 · 168 阅读 · 0 评论 -
剑指Offer38.字符串的排列
剑指Offer38.字符串的排列题目:对于一个可能有重复字符的字符串s,得到它的全排列;全排列需要不重不漏;思路:1.库函数next_permutation:该库函数不管s有没有重复元素,都可以用;class Solution {public: vector<string> permutation(string s) { vector<string> res; sort(s.begin(),s.end()); ..原创 2021-02-27 14:07:46 · 81 阅读 · 0 评论 -
剑指Offer36.二叉搜索树与双向链表
剑指Offer36.二叉搜索树与双向链表题目:将一个二叉搜索树按结点值从小到大的顺序转换成循环双向链表;不增添结点,只修改结点的left,right指针;思路:结点的left充当pre,right充当next;1.分治:O(n),O(n):当二叉搜索树退化成链表时,递归深度为n层思想是:将二叉搜索树root看成三部分,root,root的左子树,root的右子树;通过递归得到root的左子树的最小值节点和最大值结点,将root与其最大值结点双向连接起来;右侧同理,通过递归得..原创 2021-02-24 21:04:47 · 64 阅读 · 0 评论 -
剑指Offer35.复杂链表的复制
剑指Offer35.复杂链表的复制题目:在单链表中的结点中增添一个Node* random,指向nullptr或链表中的某个节点;复制这个链表,并返回其头结点;class Node {public: int val; Node* next; Node* random; Node(int _val) : val(_val), next(nullptr), random(nullptr) {}};思路:1.哈希表:对于普通单链表,由于只有next指针,因.原创 2021-02-23 23:51:46 · 58 阅读 · 0 评论 -
剑指Offer32.从上到下打印二叉树
题目1:剑指Offer32-Ⅰ.从上到下打印二叉树最直接的层序遍历,每层都从左到右遍历,最终得到一个一维数组;思路:1.层序遍历:O(n):遍历n个结点,O(n):额外需要一个队列,最坏情况下当二叉树为平衡二叉树时,队列中最多的时候会存放n/2个结点class Solution {public: vector<int> levelOrder(TreeNode* root) { if (!root) return {}; vector<.原创 2021-02-21 18:18:49 · 162 阅读 · 0 评论 -
剑指Offer31.栈的压入,弹出序列
剑指Offer31.栈的压入,弹出序列题目:给定两个序列,一个入栈序列pushed,一个出栈序列poped,且poped是pushed的排列,判断他们是否合法?序列中的元素值不相等;思路:1.一对pushed和poped序列,只会对应一种实际出入栈操作:例如pushed = [ 1,2,3,4,5 ],poped = [ 4,5,3,2,1 ];先依次入栈1,2,3,4,此时必须pop4,如果此时不弹出,继续入栈的话,4的上面就会盖上其它数,由于先进后出的特点,无论如何poped序列的..原创 2021-02-21 15:29:26 · 169 阅读 · 0 评论 -
剑指Offer30.包含min函数的栈
剑指Offer30.包含min函数的栈题目:设计一个栈,除了正常的push,pop,top操作,还需要提供min,这些操作的时间复杂度必须都是O(1);思路:通常的stack可以提供O(1)的push,pop,top操作,但由于栈先入后出的特性,栈中的元素顺序是不能改变的,其min操作必须遍历栈元素寻找最小值花费O(n);要想O(1)实现min,必须空间换时间;若只用一个变量记录最小值,有几个问题:① 若把最小值min弹出之后,就不知道次小元素值了,加上栈中可能有重复元素,如果用两个..原创 2021-02-21 10:51:45 · 77 阅读 · 0 评论 -
剑指Offer29.顺时针打印矩阵
剑指Offer29.顺时针打印矩阵题目:将一个矩阵的值顺时针打印到一个数组中;第一个方向是????;思路:1.缩减边界法:O(mn):m和n分别是矩阵的长和宽,需要遍历完矩阵的每一个位置即m*n,O(1):只用到了几个常数变量;上下左右四个边界决定一个矩阵大小;按????????????????的顺序,每遍历完一个方向,缩减响应的边界;每个方向都能作为最后一个结束遍历的方向,因此每个方向结束都要判断是否结束;class Solution {public: vector原创 2021-02-20 20:32:12 · 87 阅读 · 0 评论 -
剑指Offer28.对称的二叉树
剑指Offer28.对称的二叉树题目:判断一个二叉树是否对称?思路:1.递归:O(n):二叉树共n个结点,每次调用递归函数isSame都可以完成两个结点的比较,因此最多调用n/2次递归函数(即比较到最后一对结点),最坏情况下O(n):当二叉树退化成两条链表,此时二叉树的深度为n/2,可以使在满足递归条件前提下深度达到最深(若再少一个就会提前return false),这时系统使用O(n)的栈空间,下面为具体解释:思路:将处于对称位置上的结点两两比较,直至比较到最下层;class Solu.原创 2021-02-20 19:44:22 · 82 阅读 · 0 评论 -
剑指Offer27.二叉树的镜像
剑指Offer27.二叉树的镜像题目:给定一个二叉树,返回它的镜像二叉树;思路:将一颗二叉树镜像,相当于交换它的所有节点的左右孩子;1.递归:O(n),O(n)其实代码中的return没什么用,返回的只是当前节点,如果删掉这一句也能完成镜像操作,只是没法返回最终的头节点(其实就是本来的头节点);递归操作时,并不需要返回值做什么事,因此不同去接下一层的返回值;每层递归的目的就是当该节点不为空时,去交换它的左右孩子即可;需注意遍历顺序:swap操作放在前面或后面均可,但放在中间..原创 2021-02-20 17:26:59 · 55 阅读 · 0 评论 -
剑指Offer26.树的子结构
剑指Offer26.树的子结构题目:给定两棵二叉树A和B,判断B是不是A的子结构;空树不是任何树的子结构;思路:1.递归:O(mn):m是A树的节点个数,n是B树的节点个数,遍历A的所有节点O(m),尝试将A的每个节点都作为根去作匹配工作O(n),空间应该是O(m):当树 A和树 B 都退化为链表时,递归调用深度最大。当m≤n 时,遍历树 A 与递归判断的总递归深度为 m ;当 m>n 时,最差情况为遍历至树 A 叶子节点,此时总递归深度为 m:通过递归调用isSubStr..原创 2021-02-20 16:07:12 · 59 阅读 · 0 评论