![](https://img-blog.csdnimg.cn/20201014180756757.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
剑指offer
文章平均质量分 54
okiwilldoit
这个作者很懒,什么都没留下…
展开
-
LRU算法实现
最近最少使用算法,主要思路:双链表:双链表存储数据,插入和删除元素都很方便,复杂度都是O(1)。头节点是最近使用的元素,尾节点是最近最少使用空间满了的话,就淘汰尾节点,新增元素时,放在头节点。。为什么不用数组,因为插入和删除需要平移元素,复杂度是O(n)。哈希map:用于查找数据,key是数据的key,value是数据的指针(即数据在双链表中的位置)最大容量:如果超过容量,就把尾节点淘汰,新数据添加到头节点。原创 2023-11-30 10:38:12 · 414 阅读 · 0 评论 -
链表中的节点每k个一组翻转
描述将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样你不能更改节点中的值,只能更改节点本身。示例1输入:返回值:示例2输入:{},1返回值:{}原创 2023-11-29 14:21:34 · 94 阅读 · 0 评论 -
股票交易类算法
求一组数中最大差问题(只能是后面的数减前面的数)暴力n2,显然不行可以转化一下思路,求出两两相邻数的差,求一系列差值的最大连续子序列和,问题就转化为Maximum Subarray问题注意两点:收益不能为负,所以如果求出来的值小于0,输出0如果给出的数组只有一个数,也输出0public int maxProfit(int[] price原创 2014-01-23 12:27:31 · 804 阅读 · 1 评论 -
判断链表是否有环以及寻找环入口
思路:采用“快慢指针”查检查链表是否含有环。让一个指针一次走一步,另一个一次走两步,如果链表中含有环,快的指针会再次和慢的指针相遇。这里需要注意的一点是算法中循环的条件,这是一个很容易被忽略的细节。1)因为fast指针比slow指针走得快,所以只要判断fast指针是否为空就好。由于fast指针一次走两步(走得太快了,就容易跌倒!),fast.next可能已经为空(当fast为尾原创 2014-01-11 14:58:30 · 487 阅读 · 0 评论 -
和为S的两个数字
题目描述输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。思路:设置两个头尾指针i,j,计算出头尾两个数的和tmp。(1)如果tmp == sum,那么要找的就是这两个数;(2)如果tmp < sum,那么说明tmp还小,需要大数,头指针右移;(3)如果tmp > sum,那么说明tmp比较大,需要小数,尾指针左移;这里最终答案可能不止一个,所以需要记录符合条件的积,选择一个最小的积。所以对于情况(1),原创 2020-09-06 14:54:08 · 102 阅读 · 0 评论 -
面试题:删除链表中的重复结点&删除链表倒数第k个节点
题目描述在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5思路:找到重复节点(所有重复节点)的前驱和后继节点,用前驱指向后继。有个问题:如果头结点也是重复节点呢?为了避免单独处理头结点,创建一个虚拟节点,作为链表头结点的前驱。代码如下:ListNode* deleteDuplication(ListNode* pHead){原创 2020-09-06 12:55:24 · 200 阅读 · 0 评论 -
打印零与奇偶数
题目:https://leetcode-cn.com/problems/print-zero-even-odd/submissions/用三个互斥锁控制打印0,奇数,偶数的顺序。每把锁控制一种打印。打印0后,如果是偶数,则释放奇数锁,即开始打印奇数。反之,释放偶数锁。打印奇数后,释放0锁;打印偶数后,释放0锁。class ZeroEvenOdd {private: int n...原创 2019-10-12 11:48:17 · 516 阅读 · 0 评论 -
交替打印FooBar
题目:https://leetcode-cn.com/problems/print-foobar-alternately/submissions/打印保持顺序,与按序打印类似。1.用两个信号量解决。由于c++中没有原生信号量,所以用mutex和条件变量实现一个。class Semaphore{public: Semaphore(int value = 1) :count(val...原创 2019-10-12 10:58:11 · 583 阅读 · 2 评论 -
面试题19:二叉树的镜像&对称二叉树
1. 输出一个二叉树的镜像递归交换左右子树的节点。 代码:void MirrorBinaryTree(TreeNode* root){ if(root == NULL || (!root->left && !root->right) { return root; } TreeNode* tmp = root->left; root->left原创 2017-11-06 10:13:37 · 742 阅读 · 1 评论 -
面试题14:调整数组顺序使奇数位于偶数前面、链表按奇偶拆分
题目:输入一个数组,实现一个函数调整该数组中的数字顺序,使得奇数在前,偶数在后。思路:快速排序的分区思想,设置首尾两指针,找到前半部分的偶数和后半部分的奇数,交换即可。算法复杂度为O(n)。代码如下:void ReorderOddEven(vector<int> &data){ int size = data.size(); int p = 0, q = size-1; w原创 2017-11-06 09:52:39 · 931 阅读 · 0 评论 -
面试题25 :二叉树中和为某一值的路径
一. Leetcode-129:Sum Root to Leaf Numbers首先看下一道比较简单的题目,输入一个二叉树,输出所有路径代表的十进制数之和。一般二叉树类的题目,肯定要用到递归函数。 本题中递归函数的参数有三个:root,total_sum(引用传递,即最终结果), sum(单条路径的和)递归函数的跳出条件为遍历到叶子节点,返回前要把sum加到total_sum上。int sumNu原创 2017-11-13 11:17:10 · 304 阅读 · 0 评论 -
大文件排序问题
题目:有一个大文件,里面记录了若干数字,把这些数字进行排序。文件大小远大于内存大小。 思路:内存极少的情况下,利用分治策略,利用外存保存中间结果,再用多路归并来排序。(1)按可用内存的大小,把外存上含有n个记录的文件分成若干个长度为L的子文件,把这些子文件依次读入内存,并利用有效的内部排序方法对它们进行排序,再将排序后得到的有序子文件重新写入外存;(2)对这些有序子文件逐趟归并,使其逐渐...原创 2018-06-08 18:01:00 · 17480 阅读 · 2 评论 -
面试题24:二叉搜索树的后序遍历序列
题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。思路:1. 首先找到根节点,即最后一个元素2. 从左向右遍历,找到左子树序列的终止位置,即第一个比root大的数的位置,该位置也是右子树序列的起始位置3. 从右子树序列的起点开始遍历,如果找到右子树序列中有比root小的,直接返回false4. 分别原创 2017-11-11 16:06:26 · 213 阅读 · 0 评论 -
面试题26:复杂链表的复制
题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)链表节点的数据结构:struct RandomListNode { int label; struct RandomListNode *next, *r...原创 2017-11-30 10:21:54 · 244 阅读 · 0 评论 -
面试题28:字符串排列
题目:输入一个字符串,输出该字符串中所有字符的排列组合。 如abc,输出:abc acb bac bca cab cba经典的排列组合问题,思路: 肯定用递归的思想,先固定一个字符,然后再将剩下的字符继续排列组合。 递归函数的参数有三个:原来的字符str,一种组合result,组合集合(输出的结果)result_set 递归函数结束条件是str.siz原创 2017-11-30 16:52:24 · 245 阅读 · 0 评论 -
面试题42:翻转单词顺序(句子反转)
题目:给定一个句子(只包含字母和空格), 将句子中的单词位置反转,单词用空格分割, 单词之间只有一个空格,前后没有空格。 比如: (1) “hello xiao mi”-> “mi xiao hello”思路: 第一步:翻转句子中所有的字符。比如翻转“hello xiao mi”,变成“im oaix olleh” 第二步:再翻转每个单词的顺序,就变成了“mi xiao hello”这种思路的关原创 2017-12-06 16:50:15 · 2837 阅读 · 0 评论 -
面试题23:二叉树的遍历算法
一. 构造二叉树构造二叉树,先得要构建一个树的节点,定义一个TreeNode:public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } 插入节点,建立新树:TreeNode root = new T...原创 2018-05-23 10:30:37 · 4673 阅读 · 1 评论 -
按序打印
题目:https://leetcode-cn.com/problems/print-in-order/submissions/最经典的多线程问题。这里提供两种解决方案。1. 原子计数器加while循环class Foo {private: std::atomic<int> counter_;public: Foo() { counte...原创 2019-10-11 17:26:55 · 269 阅读 · 0 评论 -
面试题16:单链表逆置
思路如下图所示:代码:Node reverse(Node head){ if(null == head || null == head.next ){//如果链表为空或只有一个元素 return head; } Node p = head.next; head.next = null;//原来的头节点成了表尾 Node temp = null; whi原创 2014-01-16 23:04:22 · 572 阅读 · 0 评论 -
面试题6:根据前序和中序序列构建二叉树(Leetcode-106)
题目:输入二叉树的前序遍历和中序遍历序列,重构其二叉树,假设输入的数字都是不重复的。 例如前序序列是 {1,2,4,7,3,5,6,8},中序序列是{4,7,2,1,5,3,8,6}。 分析如下图所示: 算法步骤: 1. 前序序列的第一个元素即根节点。 2. 根据找到的根节点在中序序列中找到根节点,找出左右子树的范围 3. 函数输入参数有三个:前序序列的start位置,中序序列的star原创 2017-10-26 16:53:58 · 7201 阅读 · 2 评论 -
面试题8:旋转数组的最小值(Leetcode-153,154)
题目:把一个数组最开始的若干元素搬到数组的末尾,称为数组的旋转。 输入一个递增数组的一个旋转,输出其最小值。假设这个递增数组中没有重复元素 例如数组{3,4,5,1,2}是{1,2,3,4,5}的一个旋转,最小值是1。一. O(N)解法最直观的解法就是遍历数组,找到一对相邻的数,前数比后数大,则后数就是最小值。 如果未找到这样一对相邻的数,那么这个数组就未旋转,最小值即为第一个数。int fi原创 2017-11-02 16:02:05 · 1041 阅读 · 0 评论 -
面试题21:Min Stack(Leetcode-115)
用两个vector数组存储,一个存储原始数据序列,一个存储最小值序列。class MinStack {public: /** initialize your data structure here. */ MinStack() { data.clear(); min.push_back(INT_MAX); } void push(int x原创 2017-01-23 15:24:03 · 205 阅读 · 0 评论 -
面试题15:链表中倒数第k个节点(Leetcode-19:Remove Nth Node From End of List)
设置两个指针p,q;p,q相差n-1步。p,q同时前进,当q.next == null时,此时p所指向的节点就是要被删除的节点。遍历的过程中用pre记录p的前驱。找到要被的删除的节点p后要讨论:1.如果p是头节点,则直接返回p.next2.如果p是尾节点,则pre.next = null3.否则,pre.next = pre.next.nextpublic ListNode原创 2014-02-21 16:50:13 · 620 阅读 · 1 评论 -
面试题50:树的最低公共祖先
一.二叉搜索树上查找最低公共祖先输入的是两个值和二叉搜索树的根节点,输出最低公共祖先的值。 剑指offer上的题目:给出递归和非递归的解法:/*非递归*/int findLowestCommonAncestor(node root, int value1, int value2) { node curNode = root; while(1) { if(curN原创 2017-10-27 14:27:12 · 383 阅读 · 0 评论 -
面试题2:实现单例模式
单例模式的三个特点:1,该类只有一个实例2,该类自行创建该实例(在该类内部创建自身的实例对象)3,向整个系统公开这个实例接口根据以上特点,实现单例模式的方法是:(1)私有构造函数(private)(2)私有静态成员变量(private,static)(3)公有静态函数(public,static getInstance())两种形式:饿汉式单例类,懒汉式单例类懒汉...原创 2014-01-18 19:38:58 · 635 阅读 · 0 评论 -
面试题3:二维数组查找某数
题目描述:在一个二维数组中,查找某个数。这个二位数组的每一行和每一列都是递增的。 解决:查找都右上角的数(该数)开始查询。 如果查找的数==该数,则直接返回true; 如果查找的数 < 该数,则说明要查找的数在该数的左边,那么列数-1; 如果查找的数 > 该数,则说明要查找的数在该数的下边,那么行数+1. 直至查找到这个数。代原创 2016-12-08 17:55:52 · 275 阅读 · 0 评论 -
面试题27:二叉排序树转换成有序双向链表
题目描述:将二叉排序树转换成一个排序的双向链表,要求:不能创建任何新的节点,只能通过调整指针的指向来实现; 二叉排序树的一个很重要的特性就是:二叉树中序遍历的结果是一个递增的序列。由这个特性可以知道该题需要通过中序遍历的思想来解决。如下图所示,我们通过中序递归遍历过程中的一个状态来解析转换的过程,当中序遍历root指向10时,要满足转换成双向有序链表的请求,结点10左指针必须指向它中序遍历的前一个原创 2017-10-12 17:51:19 · 1452 阅读 · 0 评论 -
面试题18:判断树的子结构
题目:输入两个二叉树A和B,判断B是否是A的子结构。如下图所是,B树是A树的子结构: 一般二叉树的判断问题都用递归方法来解决。 递归方法首先要确定方法的参数,以及递归结构。 二叉树的结构为:struct BTNode{ int val; BTNode* left; BTNode* right;}判断步骤: 1. 首先判断两树的根节点的值是否相等,如果相等,则进一步判原创 2017-10-24 14:23:31 · 303 阅读 · 0 评论 -
面试题31:连续子数组的最大和(Leetcode-53:Maximum Subarray)
经典DP问题,用max变量存储先前得到的子数组的和注意四点:1. 每次循环 sum += A[i]2. 如果sum>max ,则将max置为sum3. 如果sum因为如果sum4.max的初始值必须是int型的最小值,也就是Integer.MIN_VALUE,因为需要和sum比较 public int maxSubArray(int[] A) { int l原创 2014-01-19 12:07:02 · 517 阅读 · 0 评论 -
面试题17:合并两个有序链表(Leetcode-21:Merge Two Sorted Lists)
思路与合并两个有序数组是一样的,重新建立一个node l3,同时遍历l1和l2,比较小的数就插入到l3的表尾,然后小的数指针后移。不同的是,在遍历之前,得要先建立l3的头结点,也就是比较l1和l2的头结点数值大小,小的数作为l3的头结点。public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode原创 2014-01-19 15:34:51 · 609 阅读 · 0 评论 -
面试题22:栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)思路:每个出栈的元素都是栈的栈顶元素,判断栈顶元素与出栈序列是否相等,如果相等,那么就弹出,继续遍原创 2017-11-10 17:39:15 · 166 阅读 · 0 评论 -
面试题20:顺时针打印矩阵(Leetcode-54和57)
题目:输入一个矩阵,从外向里顺时针打印出每一个数字,例如输入以下矩阵: 输出:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10。分析:可以把这个问题分解为各个小圈,每圈按照顺时针来访问。 对于5*5的矩阵而言,最后一圈只有一个数字,其坐标是(2,2),我们发现5>2*2; 对于6*6的矩阵而言,最后一圈有4个数字,其左上角坐标还是(2,2),我们发现6>2*2依原创 2017-11-08 10:40:39 · 2525 阅读 · 0 评论 -
面试题13:O(1)时间内删除链表节点
函数参数有两个:链表的头节点,需要删除的节点,两个都是ListNode*类型。一. 常规思路,复杂度为O(n)从头到尾遍历,找到该节点的前驱节点,用常规思路去设置指针。 即pre->next = deleted->next;delete deleted; 之所以要遍历,是因为是要找到被删除节点的前驱节点。二. 高效解法:O(1)方法可以用被删除节点的后继节点,去覆盖被删除节点,然后再删除后继节点原创 2017-10-30 16:49:53 · 249 阅读 · 0 评论 -
面试题7:栈和队列的互相实现(Leetcode-232和225)
一. 用两个栈实现队列,实现四个函数:push,pop,peek,empty思路: 用两个栈实现队列; 一个栈s1用于入队,直接把新元素进s1,就完成了push函数。 另一个栈s2用于出队。如果s2已空,则把s1中的所有元素出栈,并push进s2,最后s2出栈,即完成队列的pop函数。 peek函数是取出队列的对首元素。代码如下:class Queue {public: stack原创 2017-10-30 14:14:47 · 339 阅读 · 0 评论 -
面试题39:二叉树的深度&平衡二叉树的判断
一. 二叉树的深度题目:输入一个二叉树,从根节点到叶子节点的一条最长路径,这条路径的最长长度就是二叉树的深度。public int Depth(TreeNode root) { if(root == null)return 0; int left = 1+Depth(root.left); int right = 1+Depth(root.right)原创 2017-10-27 14:59:21 · 192 阅读 · 0 评论 -
面试题4:替换空格
题目:实现一个函数,把字符串中的所有空格替换成”%20”,例如输入“We are happy”,输出“We%20are%20happy”。思路1:O(n2)复杂度从前往后遍历,每遇到一空格,就将后面的所有字符右移2位,然后在空出来的地方填充%20三个字符。这样的话,每遇到一个空格,都要将后面的字符右移,因此每个字符都可能会移动n次,所以复杂度为O(n2)。思路2:O(n)复杂度如果我们从后面开始遍历原创 2017-10-30 11:10:07 · 186 阅读 · 0 评论 -
面试题30:寻找最大(小)的k个数
题目描述:输入n个整数,输出其中最大的k个。举例:输入序列1、2、3、4、5、6、7、8,输出最大的4个数字为5、6、7、8。可能存在的条件限制:要求 时间 和 空间消耗最小、海量数据、待排序的数据可能是浮点数等方法一:对所有元素进行排序,之后取出前K个元素,不提倡使用思路:使用最快排序算法,选择快排 或 堆排时间复杂度:O(n*logn) + O(原创 2014-08-29 11:09:09 · 770 阅读 · 0 评论 -
面试题49:String to Integer (atoi)(Leetcode-8)
问题:将字符串转换成数字分析:感觉题目不难,但是细节很多,容易想不到1.数字前面有空格 如s=“ 123456”2.数字前出现了不必要或多于的字符导致数字认证错误,输出0 如s=“ b1234” ,s=“ ++1233” , s=“ +-1121”3.数字中出现了不必要的字符,返回字符前的数字 如s=“ 12a12” , s=“ 123 123”4.数字原创 2014-09-18 14:15:45 · 470 阅读 · 0 评论 -
面试题37:两个链表的第一个公共节点
寻找两个单链表的第一个公共节点,如下图所示,节点6是两个链表的第一个公共节点。 1. 暴力法两个for循环,找到公共节点,复杂度为O(mn),不推荐。2. 借助栈从上图可以看出,公共节点必然在链表的后半部分出现,我们可以从尾节点开始找,直到找到这个节点的前驱节点不相同,那么这个节点就是第一个公共节点。但是单链表只能从前往后遍历,想要从尾部开始遍历,自然而然会想到栈。先用两个栈,分别遍历这两个链表,原创 2017-10-24 16:01:14 · 267 阅读 · 0 评论