剑指offer第四章
剑指offer第四章
1.二叉树的镜像
二叉树的镜像:输入一个二叉树,输出它的镜像
分析:求树的镜像过程其实就是在遍历树的同时,交换非叶结点的左右子结点。
求镜像的过程:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,交换它的两个子结点,当交换完所有非叶子结点的左右子结点之后,就得到了树的镜像。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot)
{
if(pRoot==NULL)//二叉树为空
return;
if(pRoot->left==NULL&&pRoot->right==NULL)//二叉树只有一个结点
return; //交换左右结点
TreeNode *pTemp=pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=pTemp; if(pRoot->left) //递归求左子树的镜像
Mirror(pRoot->left);
if(pRoot->right)//递归求右子树的镜像
Mirror(pRoot->right);
}
};
2.顺时针打印矩阵
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int>res;
res.clear();
int rows=matrix.size();//行数
int columns=matrix[].size();//列数
//计算打印的圈数
int circle=((rows<columns?rows:columns)-)/+;//圈数
for(int i=;i<circle;i++){
//从左向右打印
for(int j=i;j<columns-i;j++)
res.push_back(matrix[i][j]);
//从上往下的每一列数据
for(int k=i+;k<rows-i;k++)
res.push_back(matrix[k][columns--i]);
//判断是否会重复打印(从右向左的每行数据)
for(int m=columns-i-;(m>=i)&&(rows-i-!=i);m--)
res.push_back(matrix[rows-i-][m]);
//判断是否会重复打印(从下往上的每一列数据)
for(int n=rows-i-;(n>i)&&(columns-i-!=i);n--)
res.push_back(matrix[n][i]);}
return res;
}
};
3.包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
/*
* 1.dataStack为存储数据的栈,minStack为存储最小值的栈;
* 2.push的时候将value值与minStack中的top值比较,小则minStack push value,大则push top值
*/
class Solution {
public:
stack<int> dataStack, minStack;//定义两个栈,一个数据栈,一个最小值的辅助栈
void push(int value)
{
dataStack.push(value);//将数据进行压入数据栈
if (minStack.empty()) //如果辅助栈尾空,将数据压入辅助栈
{
minStack.push(value);
}
else//如果数据小于min,数据压入辅助栈,否则最小值压入辅助栈
{
int min = minStack.top();
value<=min?minStack.push(value):minStack.push(min);
} }
void pop() //出栈
{
dataStack.pop();//数据栈出栈
minStack.pop();//辅助栈出栈
}
int top() //栈顶
{
return dataStack.top();
}
int min() //取最小
{
return minStack.top();
}
};
4、栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV)
{
if(pushV.empty() || popV.empty() || pushV.size()!=popV.size())//如果压入序列或者弹出序列为空、或者压入序列和弹出序列大小不等
return false;
stack<int> s;
int j=;
for(int i=;i<pushV.size();++i)
{
s.push(pushV[i]);
while(!s.empty()&&s.top()==popV[j])
{
s.pop();
++j;
}
}
if(s.empty())
return true;
return false;
}
};
5.从上往下打印二叉树从上往下打印出二叉树的每个节点,同层节点从左至右打印。
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode *root)
{
queue<TreeNode*> q;
q.push(root);
vector<int> r;
while(!q.empty())
{
root = q.front();
q.pop();
if(!root)
continue;
r.push_back(root -> val);
q.push(root -> left);
q.push(root -> right);
}
return r;
}
};
6.二叉搜索树的后序遍历序列输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
vector<int> leftTree,rightTree;
int root; // 根结点
if(sequence.empty())
return false;
int index = ; // 标记左右子树界限
int len = sequence.size();
root = sequence[len-];
int i=;
for(;i<len-;++i)
{
if(sequence[i]>root)
break; // 找到第一个大于根结点的位置,则左边为左子树,右边为右子树
}
for(int j=i;j<len-;++j) // 循环时去除root,因此为len-1
{
if(sequence[j]<root)
return false; // 有一个小于root,则返回false
}
if(i!=)
{
// 即有左子树
for(int m=;m<i;++m)
{
leftTree.push_back(sequence[m]);
}
}
if(i!=len-)
{
for(int j=i;j<len-;++j)
{
rightTree.push_back(sequence[j]);
}
}
bool left = true,right = true; // 看左右子树是否是二叉搜索树
if(leftTree.size()>) VerifySquenceOfBST(leftTree);
if(rightTree.size()>) VerifySquenceOfBST(rightTree);
return (left&&right);
}
};
7.二叉树中和为某一值的路径: 注:路径是从根结点出发到叶结点。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber)
{
vector<vector<int> > res;
if (root == NULL)
return res;
stack<TreeNode *> s;
s.push(root);
int sum = ; //当前和
vector<int> curPath; //当前路径
TreeNode *cur = root; //当前节点
TreeNode *last = NULL; //保存上一个节点
while (!s.empty())
{
if (cur == NULL)
{
TreeNode *temp = s.top();
if (temp->right != NULL && temp->right != last)
{
cur = temp->right; //转向未遍历过的右子树
}
else
{
last = temp; //保存上一个已遍历的节点
s.pop();
curPath.pop_back(); //从当前路径删除
sum -= temp->val;
}
}
else
{
s.push(cur);
sum += cur->val;
curPath.push_back(cur->val);
if (cur->left == NULL && cur->right == NULL && sum == expectNumber)
{
res.push_back(curPath);
}
cur = cur->left; //先序遍历,左子树先于右子树
}
}
return res; }
};
8.复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。
(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
void CloneNodes(RandomListNode* pHead)
{
RandomListNode* pNode=pHead;
while(pNode!=NULL){
RandomListNode* pCloned=new RandomListNode();
pCloned->label=pNode->label;
pCloned->next=pNode->next;
pCloned->random=NULL; pNode->next=pCloned;
pNode=pCloned->next;
}
} void ConnectSiblingNodes(RandomListNode* pHead)
{
RandomListNode* pNode=pHead;
while(pNode!=NULL){
RandomListNode* pCloned=pNode->next;
if(pNode->random!=NULL)
{
pCloned->random=pNode->random->next;
}
pNode=pCloned->next;
}
} RandomListNode* ReconnectNodes(RandomListNode* pHead)
{
RandomListNode* pNode=pHead;
RandomListNode* pClonedHead=NULL;
RandomListNode* pClonedNode=NULL; if(pNode!=NULL)
{
pClonedHead=pClonedNode=pNode->next;
pNode->next=pClonedNode->next;
pNode=pNode->next;
} while(pNode!=NULL)
{
pClonedNode->next=pNode->next;
pClonedNode=pClonedNode->next;
pNode->next=pClonedNode->next;
pNode=pNode->next;
}
return pClonedHead;
}
RandomListNode* Clone(RandomListNode* pHead)
{
CloneNodes(pHead);
ConnectSiblingNodes(pHead);
return ReconnectNodes(pHead);
}
};
9.二叉搜索树与双向链表
输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表(要求不能创建新的结点,只能调整树中结点指针的指向)
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void ConvertNode(TreeNode* pNode,TreeNode** pLastNodeInList)
{
if(pNode==NULL)
return;
TreeNode *pCurrent=pNode;
if(pCurrent->left!=NULL)
ConvertNode(pCurrent->left,pLastNodeInList);
pCurrent->left=*pLastNodeInList;
if(*pLastNodeInList!=NULL)
(*pLastNodeInList)->right=pCurrent;
*pLastNodeInList=pCurrent;
if(pCurrent->right!=NULL)
ConvertNode(pCurrent->right,pLastNodeInList);
}
TreeNode* Convert(TreeNode* pRootOfTree)
{
TreeNode *pLastNodeInList=NULL;
ConvertNode(pRootOfTree,&pLastNodeInList);
TreeNode *pHeadOfList=pLastNodeInList;
while(pHeadOfList!=NULL&&pHeadOfList->left!=NULL)
pHeadOfList=pHeadOfList->left;
return pHeadOfList;
}
};
10.字符串的排列
输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
class Solution {
public:
set<string> res;
void fun(string str, int pos)
{
if (pos == str.length())
{
res.insert(str);
return;
}
for (int i = pos; i < str.length(); ++i)
{
swap(str[i], str[pos]);
fun(str, pos + );
swap(str[i], str[pos]);
}
}
vector<string> Permutation(string str) {
res.clear();
vector<string> st;
if (str.length() == )
return st;
fun(str, );
set<string>::iterator it;
for (it = res.begin(); it != res.end(); ++it)
st.push_back(*it);
return st;
}
};
剑指offer第四章的更多相关文章
- 剑指offer第七章&第八章
剑指offer第七章&第八章 1.把字符串转换成整数 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一个合法的数值则返回0 输入描述: 输入一个字符串 ...
- 剑指offer第六章
剑指offer第六章 1.数字在排序数组中出现的次数 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在数组中出现了4次,所以输出4 分析:思路1 ...
- 剑指offer第五章
剑指offer第五章 1.数组中出现次数超过一半的数 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组 ...
- 剑指offer第三章
剑指offer第三章 1.数值的整数次方 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. class Solution { public ...
- JS 剑指Offer(四) 从尾到头打印链表
题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 首先定义一下链表中的节点,关于链表这个数据结构在另外一篇文章中会详细讲 function ListNode(val) { t ...
- 《剑指Offer》第二章(一)题3-8
为春招实习做准备,记录一下<剑指Offer>里面的面试题 第二章 面试题3:数组之中的重复数字. 这个题吧,虽然不难,但是不知道为什么就是看了很久,可能很久没有做算法题了.最后面一句话说的 ...
- 《剑指Offer》第二章(一)题 9 -12
第二章 面试题9:用两个栈实现队列 题目:如面试题,给你两个栈, 实现队列的先进先出,即在队列头删除一个元素以及在队列的尾部添加一个元素 思路:这个题的分析感觉很巧妙,从一个具体的例子入手,找出其中的 ...
- 算法学习之剑指offer(四)
题目1 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) /** public class TreeNode { int val = 0; Tree ...
- 剑指offer—第三章高质量代码(o(1)时间删除链表节点)
题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点,链表节点与函数的定义如下:struct ListNode{int m_nValue;ListNode* m_pValue ...
随机推荐
- photoshop cc下载与安装
地址:https://jingyan.baidu.com/article/c275f6bacdd927e33d756729.html
- Lubuntu系统中java,tomcat的环境搭建(virtualbox中)
一.安装Lubuntu系统 这一步没什么说的,到官网下载镜像,在virtualbox中安装即可安装时就已经可以选择安装源,当然,选中国的设置环装网络,可将该虚拟机设立为网络上的独立IP,和物理机间可以 ...
- 手机端页面自适应解决方案—rem布局(进阶版,附源码示例)
转自:https://segmentfault.com/a/1190000007350680 一年前笔者写了一篇 <手机端页面自适应解决方案—rem布局>,意外受到很多朋友的关注和喜欢.但 ...
- 毕业设计总结(1)-canvas画图
去年6月底完成的毕业设计,到现在也才开始给它做个总结,里面有很多可以学习和借鉴的东西. 我的毕业设计的题目是“一种路径规划算法的改进与设计”,具体的要求可参见下面的表格: 题目 一种路径规划算法的改进 ...
- java网络编程之图片上传
输入输出流核心代码 所有的文件传输都是靠流,其中文件复制最具代表性.输入流和输出流,从输入流中读取数据写入到输出流中. InputStream in = 输入源; OutputStream os = ...
- App压力测试MonkeyRunner整理
压力测试结果:CRASH:崩溃,应用程序在使用过程中,非正常退出ANR:Application Not Responding 命令很多,不用死记,用到复制.粘贴就行,达到目的最重要. 简单通俗易懂点讲 ...
- Struts2异常处理配置
<package name="lee" extends="struts-default"> <!--定义全局结构映射 --> <g ...
- How to create Oracle ASM devices using device-mapper multipath devices in Red Hat Enterprise Linux 6
How to create Oracle ASM devices using device-mapper multipath devices in Red Hat Enterprise Linux 6 ...
- UML_04_时序图
一.前言 时序图建模工具,推荐一个工具 https://www.zenuml.com/ 时序图是一种强调消息时序的交互图,他由对象(Object).消息(Message).生命线(Lifeline) ...
- APUE学习笔记——10.11~10.13 信号集、信号屏蔽字、未决信号
如有转载,请注明出处:Windeal专栏 首先简述下几个概念的关系: 我们通过信号集建立信号屏蔽字,使得信号发生阻塞,被阻塞的信号即未决信号. 信号集: 信号集:其实就是一系列的信号.用sigset_ ...