剑指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 ...
随机推荐
- 使用cxf调用webservice
1.引入maven包 <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt ...
- 虚拟机中的Linux安装VMware Tools的方法
先检查虚拟机是否能上网 一:安装VMware Tools的之前必装的工具套件方法如下: Centos安装VMware Tools: [root@piaoyun-vm vmware-tools-dist ...
- linux禁止ping
1.临时禁止PING操作的命令为:#echo 1>/proc/sys/net/ipv4/icmp_echo_ignore_all 2.永久禁止PING配置方法 /etc/sysctl.conf ...
- linux入门总结
linux的核心概念知识: linux软件是开源免费的,而linux是由Unix演变而成,Unix是由MINIX演变而成. 2000年以后,linux系统日趋成熟,涌现大量基于linux服务平 ...
- 【Error】2003 - Can't connect to MySQL server on 'localhost' (10038)
此错误主要是连接MySQL地址的地址搞错了. 可以看下 MySQL 的配置文件 /etc/mysql/my.cnf, 其中绑定的本地地址如下: bind-address=127.0.0.1 将其注释掉 ...
- 转:基于Flume的美团日志收集系统(一)架构和设计
美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...
- 009-对象—— 构造方法__construct析构方法__destruct使用方法 PHP重写与重载
<?php /**构造方法__construct析构方法__destruct使用方法 PHP重写与重载 */ //构造方法:当实例化对象时,自动运行的方法 /*class channel{ fu ...
- C++实现设计模式之 —策略与简单工程结合
策略模式封装算法 // cash.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #inc ...
- java中遍历类中的属性、调用getter&setter方法
public static void testReflect(Object model) throws NoSuchMethodException, IllegalAccessException, I ...
- Java并发编程之重入锁
重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁阻塞,该特性的实现需要解决以下两个问题. 1.线程再次获取锁 ...