剑指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 ...
随机推荐
- [BZOJ3244][NOI2013]树的计数
这题大家为什么都写O(NlogN)的算法呢?…… 让本蒟蒻来写一个O(N)的吧…… 首先还是对BFS序和DFS序重编号,记标好的DFS序为d[1..n].令pos[x]为x在d[]中出现的位置,即po ...
- 黑客落网记:FBI如何抓捕Anonymous核心成员
腾讯科技讯 美国新闻网站Daily Dot近日撰文,通过他们掌握的资料和实地采访,还原了Anonymous核心成员被捕的经过. 以下为文章全文: 哈蒙德被捕前夜 2012年3月,一个周六的下午,天气异 ...
- bootstrap 知识点
1.datetimepicker //带分钟选择 $('.form_datetime').datetimepicker({ format: 'yyyy-mm-dd HH:mm:ss', languag ...
- Android-------ListView列表中获取EditText输入的值
最近项目的购物车中用列表中包含了留言功能, 需要获取EditText输入的内容,当购买多件商品时,就有点棘手了. 经过查资料解决了这个功能,并写了一个案例: 效果图: 可以在商品数据用一个字段来管理留 ...
- LabVIEW之生产者/消费者模式--队列操作
LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...
- 第六天 vim编辑的使用和Xmanager远程工具的使用
1.1 vim主要模式介绍,vim命令模式 使用命令 vim [file name] 有三种主要模式:命令模式.编辑模式.命令行模式 在vim中主要使用快捷键进行操作,详见:http://www.cn ...
- android面试准备一之Activity相关
1.Activity生命周期 1.1 Activity的4种状态 running/paused/stopped/killed running:当前Activity正处于运行状态,指的是当前Ac ...
- javascript打开新窗体
open -- 打开(弹出)一个新的窗体 open,中文"打开"的意思 引用网址:http://www.dreamdu.com/javascript/window.open Jav ...
- 使用IScroll5实现滚动
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Mysql 表锁定的问题
下面的几个语句查询到,但如何定位到对应的进程,还需要学习这些表的结构. select * from information_schema.innodb_trx ## 当前运行的所有事务select * ...