剑指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 ...
随机推荐
- poj 2229 Sumsets 完全背包求方案总数
Sumsets Description Farmer John commanded his cows to search for different sets of numbers that sum ...
- replace()函数用法
replace()函数表示将用一个字符串替换字符串中的所出现的特定内容. 语法为:replace(字段1,字段2,字段3),意思为字段3将会替换字段1里与字段2相同的内容 列如: table1 st ...
- AJAX的例子
var XMLHttpReq; //根据不同的浏览器创建不同的XMLHttpRequest对象function createXMLHttpRequest() { if (window.XMLHttp ...
- C3 文件IO:APUE 笔记
C3:文件IO 1 引言 本章描述的函数被成为不带缓冲的IO,涉及5个函数:open.read.write.lseek.close. 文件控制:dup.sync.fsync.fdatasync.fcn ...
- c语言的tcp和udp客户端和服务器
都是最简单的用来记忆. this is my 的git地址:https://github.com/yanjinyun/cLanguageTcpUdp tcp最简单的服务器: int main(int ...
- 搞懂分布式技术5:Zookeeper的配置与集群管理实战
搞懂分布式技术5:Zookeeper的配置与集群管理实战 4.1 配置文件 ZooKeeper安装好之后,在安装目录的conf文件夹下可以找到一个名为“zoo_sample.cfg”的文件,是ZooK ...
- vue结合element-ui 的select 全选问题
下拉列表多选 问题 通过操作 所有来进行全选 全不选问题 element-ui 中 select 记录下自己最近使用element-ui 中的 select多选问题 在element中默认是指单纯多选 ...
- 【2018多校第一场】hdu6308-Time Zone(日期)
Problem Description Chiaki often participates in international competitive programming contests. The ...
- C++设计模式之-工厂模式的总结
工厂模式分为3种,即简单工厂模式.工厂方法模式.抽象工厂模式,其实大同小异,总结下来就是: 简单工厂模式:一个工厂,多个产品.产品需要有一个虚基类.通过传入参数,生成具体产品对象,并利用基类指针指向此 ...
- APUE学习笔记——5.5~5.7数据流的打开与读写
1.open #include <stdio.h> FILE *fopen(const char *restrict pathname,const char *restrict type) ...