《剑指Offer》题五十一~题六十
五十一、数组中的逆序对
题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,在数组{7, 5, 6, 4}中,一共存在5个逆序对,分别是(7, 6)、(7, 5)、(7, 4)、(6, 4)和(5, 4)。
提示:本题可以使用归并排序来完成,其时间复杂度为O(nlogn),但需要一个长度为n的辅助数组。
五十二、两个链表的第一个公共节点
题目:输入两个链表,找出它们的第一个公共节点。
提示:假设两个链表的长度分别为m和n,蛮力法的时间复杂度是O(mn),优化的算法的时间复杂度是O(m+n)。
分析:有公共节点的两个链表,从它们的第一个公共节点开始,之后它们所有的节点都是重合的。故如果两个链表有公共节点,那么公共节点出现在两个链表的尾部。故我们可以想到,首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个节点;在第二次遍历的时候,在较长的链表上先走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是它们的第一个公共节点。
解法:
ListNode* find_first_common_node(ListNode *pHead1, ListNode *pHead2)
{
if(pHead1 == nullptr || pHead2 == nullptr) return nullptr; int listLen1 = 0;
int listLen2 = 0;
ListNode *pCur1 = pHead1;
ListNode *pCur2 = pHead2;
while(pCur1 != nullptr) {
pCur1++;
listLen1++;
}
while(pCur2 != nullptr) {
pCur2++;
listLen2++;
}
pCur1 = pHead1;
pCur2 = pHead2;
int step = listLen1 - listLen2;
if(step < 0) {
step *= -1;
for(int i = 0; i < step; ++i)
pCur2 = pCur2->next;
}
if(step > 0) {
for(int i = 0; i < step; ++i)
pCur1 = pCur1->next;
} while(pCur1 != nullptr && pCur2 != nullptr) {
if(pCur1->value != pCur2->value) {
pCur1 = pCur1->next;
pCur2 = pCur2->next;
}
else
return pCur1;
}
return nullptr;
}
小结:还有一种思路,就是如果我们从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。因为尾节点要先比较,所以我们可以用两个辅助栈,分别把两个链表的节点放入两个栈里,这样两个链表的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的节点是否节点。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的节点。
五十三、在排序数组中查找数字
题目一:数字在排序数组中出现的次数。统计一个数字在排序数组中出现的次数。
提示:我们可以用二分查找算法来解决此题。
分析:假如输入的排序数组为{1, 2, 3, 3, 3, 3, 4, 5},而要找3出现的次数。我们先用二分查找算法找到一个3,由于3可能出现多次,因此在找到的3的左右两边顺序扫描,分别找出第一个3和最后一个3,但顺序扫描就失去了二分查找的时间效率,故我们应该仔细想想如何好好利用二分查找算法以找到第一个3和最后一个3。
解法:
int getNumOfK(int *pData, int length, int k)
{
if(pData == nullptr || length <= 0) return -1;
int firstKIndex = getFirstK(pData, length, k, 0, length - 1);
int lastKIndex = getLastK(pData, length, k, 0, length - 1); if(firstKIndex > -1 && lastKIndex > -1)
return lastKIndex - firstKIndex + 1;
} /* 用二分查找算法在排序数组中找第一个K */
int getFirstK(int *pData, int length, int k, int begin, int end)
{
if(begin > end) return -1;
int midIndex = (begin + end) / 2;
int midData = data[midIndex];
if(midData == k) {
if((midIndex > 0 && data[midIndex - 1] != k) || midIndex == 0)
return midIndex;
else
end = midIndex - 1;
}
else if(midData > k)
end = midIndex - 1;
else
begin = midIndex + 1; return getFirstK(pData, length, k, begin, end);
} /* 用二分查找算法在排序数组中找最后一个K */
int getLastK(int *pData, int length, int k, int begin, int end)
{
if(begin > end) return -1;
int midIndex = (begin + end) / 2;
int midData = data[midIndex];
if(midData == k) {
if((midIndex < length - 1 && data[midIndex + 1] != k) || midIndex == length - 1)
return midIndex;
else
end = midIndex + 1;
}
else if(midData < k)
end = midIndex + 1;
else
begin = midIndex - 1; return getLastK(pData, length, k, begin, end);
}
小结:本题需要用二分查找算法在排序数组中找到第一个K和最后一个K。
题目二:0~n-1中缺失的数字。一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
题目三:数组中数值和下标相等的元素。假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实现一个函数,找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1, 1, 3, 5}中,数字3和它的下标相等。
五十四、二叉搜索树的第K大节点
题目:给定一棵二叉搜索树,请找出其中第K大的节点。
提示:二叉搜索树的中序遍历序列是递增的。
分析:如果按照中序遍历的顺序遍历一棵二叉搜索树,则遍历序列的数值是递增排序的。故只需用中序遍历算法遍历一棵二叉搜索树,我们就很容易找出它的第K大节点。
五十五、二叉树的深度
题目一:二叉树的深度。输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
题目二:平衡二叉树。输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左、右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
五十六、数组中数字出现的次数
题目一:数组中只出现一次的两个数字。一个整型数组里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
题目二:数组中唯一只出现一次的数字。在一个数组中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
五十七、和为S的数字
题目一:和为S的两个数字。输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得它们的和正好是S。如果有多对数字的和等于S,则输出任意一对即可。
题目二:和为S的连续正数序列。输入一个正数S,打印出所有和为S的连续正数序列(至少含有两个数)。例如,输入15,由于1+2+3+4+5 = 4+5+6 = 7+8 = 15,所以打印出3个连续序列1~5、4~6和7~8。
五十八、翻转字符串
题目一:翻转单词顺序。输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如,输入字符串"I am a student.",则输出"student. a am I"。
提示:两次翻转字符串即可。第一步翻转句子中所有的字符,第二步翻转每个单词中字符的顺序。
解法:
char* reverse_sentence(char *pStr)
{
if(pStr == nullptr) return nullptr; char *pBegin = pStr;
char *pEnd = pStr;
while(*pEnd != '\0')
pEnd++;
pEnd--;
// 翻转整个句子
reverse(pBegin, pEnd);
// 翻转句子中的每个单词
pBegin = pEnd = pStr;
while(*pBegin != '\0') {
if(*pBegin == ' ') {
pBegin++;
pEnd++;
}
else if(*pEnd == ' ' || *pEnd == '\0') {
pEnd--;
reverse(pBegin, pEnd);
pBegin = ++pEnd;
}
else {
pEnd++;
}
}
return pStr;
} /* 翻转整个句子 */
void reverse(char *pBegin, char *pEnd)
{
while(pBegin < pEnd) {
char temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp; pBegin++;
pEnd--;
}
}
题目二:左旋转字符串。字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
提示:上题的加强版,合理利用上题的思路来解决该题。
五十九、队列的最大值
题目一:滑动窗口的最大值。给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。例如,如果输入数组{2, 3, 4, 2, 6, 2, 5, 1}及滑动窗口的大小3,那么一共存在6个滑动窗口,它们的最大值分别为{4, 4, 6, 6, 6, 5}。
题目二:队列的最大值。请定义一个队列并实现函数max得到队列里的最大值,要求函数max、push_back和pop_front的时间复杂度都是O(1)。
六十、n个骰子的点数
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。
《剑指Offer》题五十一~题六十的更多相关文章
- 《剑指offer》第二十一题(调整数组顺序使奇数位于偶数前面)
// 面试题21:调整数组顺序使奇数位于偶数前面 // 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有 // 奇数位于数组的前半部分,所有偶数位于数组的后半部分. #inclu ...
- 《剑指offer》第十一题(旋转数组的最小数字)
// 面试题:旋转数组的最小数字 // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组 // {3, ...
- 剑指Offer(二十一):栈的压入、弹出序列
剑指Offer(二十一):栈的压入.弹出序列 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/b ...
- 剑指Offer(三十一):整数中1出现的次数(从1到n整数中1出现的次数)
剑指Offer(三十一):整数中1出现的次数(从1到n整数中1出现的次数) 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https:// ...
- 剑指offer第五章
剑指offer第五章 1.数组中出现次数超过一半的数 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组 ...
- [持久更新] 剑指offer题目Python做题记录
第一题 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路:先快速定位到 ...
- 剑指offer第五题
输入一个链表,从尾到头打印链表每个节点的值. 但是 根据往常的经验 如果if里面有return了 就不要写else了 import java.util.ArrayList; import java ...
- 【剑指Offer】俯视50题之21 - 30题
面试题21包括min函数的栈 面试题22栈的压入.弹出序列 面试题23从上往下打印二叉树 面试题24二叉搜索树的后序遍历序列 面试题25二叉树中和为某一值的路径 面试题26复杂链表的复制 ...
- 《剑指offer》第十三题(机器人的运动范围)
// 面试题:机器人的运动范围 // 题目:地上有一个m行n列的方格.一个机器人从坐标(0, 0)的格子开始移动,它 // 每一次可以向左.右.上.下移动一格,但不能进入行坐标和列坐标的数位之和 // ...
随机推荐
- windows10上安装mysql
环境:windwos 10(1511) 64bit.mysql 5.7.14 一.下载mysql 1. 在浏览器里打开mysql的官网http://www.mysql.com/ 2. 进入页面顶部的& ...
- mybatis报错:未找到参数导致绑定异常
问题: 在映射文件中使用parameterMap元素时出现以下异常: org.mybatis.spring.MyBatisSystemException: nested exception is or ...
- tp3.2源码解析——入口文件
如果有人读这篇文章并跟着做的话,希望你能使用支持函数跳转的编辑器,还要善用var_dump和exit,对着源码去调试着看.跟着入口文件读,执行到哪里你看到哪里,对于那些不能一眼看出来的配置,则要记录下 ...
- python -- 简单配置发送邮件功能
本文用第三方类库:yagmail 实现:以QQ邮箱作为发送邮箱为例.最终的实现效果:给指定邮箱,发送指定内容的邮件. 准备工作 1.用于发送邮件的账号信息 比如账号用自己的qq邮箱,但'密码'需要在邮 ...
- KEIL MDK-ARM Version 5.26正式版开发工具下载
Keil MDK最新版本已经出来啦,ARM开发工具MDK-ARM Version 5.26地址:http://www.myir-tech.com/soft.asp?id=1141,需要的可以去下载哦 ...
- rails应用无法读取kafka数据报错Kafka::Error: Failed to find group coordinator
如果确保kafka中有数据,rails应用中却无法读取到,或报如下错误: Kafka::Error: Failed to find group coordinator 一般有两种情况,解决: ...
- 说一说MySQL的锁机制
锁概述 MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则. 最显著的特点是不同的存储引擎支持不同的锁机制,InnoDB支持行锁和表锁,MyISAM支持表锁. 表锁就是把 ...
- for循环简单实例(打印乘法表,打印菱形)
关于for循环的简单应用: 回顾了一下for循环的嵌套: for循环嵌套简单来讲就是一个外圈的for程序里面一个套着一个小的for程序,如果在范围内就来回运行计算,超出了就跳出等待 下面程序为打印九九 ...
- 009---linux进程管理
进程管理 top 查看运行状态:top 查看cpu核心数:top and 1 查看cpu占用率最大:top and P free 查看内存状态:free 以M为单位:free -m 以G为单位:fre ...
- python--复习之路的目录
想要看时点链接看看,常来复习,温故而知新,可以为师矣. 1:基本类型 python--基本类型之字符串 python--基本类型之列表 python--基本类型之元组 python--基本类型之集合 ...