剑指offer第七章&第八章

1.把字符串转换成整数
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
分析:思路在代码里已经体现
 class Solution {
public:
int StrToInt(string str)
{
if(str.empty())
return ;
int symbol = ;//正负号初始化为1表示正数
if(str[] == '-')
{//处理负号
symbol = -;//表示是负数
str[] = ''; //这里是‘0’ 不是0
}
else if(str[] == '+')
{//处理正号
symbol = ;//表示是正数
str[] = '';
}
int sum = ;
for(int i=;i<str.size();++i)
{
if(str[i] < '' || str[i] > '')
{
sum = ;
break;
}
sum = sum * + str[i] - '';
}
return symbol * sum;//正负号乘以sum,即表示字符串所表示的整数
}
};

2..数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 
例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
分析:注意到数组中的数字都在0——n-1的范围内。如果没有重复数字,那么排序之后数字i将出现在下标为i的位置
从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先比较这个数字(m)是不是等于i。如果是,接着扫描下一个数字。如果不是,再拿m和第m个数字比较。如果相等,就找到了一个重复数字。如果不等,就把第i个数字和第m个数字交换,把m放到属于它的位置。接下来重复比较,直到找到重复数字。
 class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication)
{
if(numbers==NULL||length<=)
return false;
for(int i=;i<length;++i)
{
if(numbers[i]<||numbers[i]>length-)
return false;
}
for(int i=;i<length;++i)
{
while(numbers[i]!=i)
{
if(numbers[i]==numbers[numbers[i]])
{
*duplication=numbers[i];
return true;
}
int temp=numbers[i];
numbers[i]=numbers[temp];
numbers[temp]=temp;
}
}
return false;
}
};

3.构建乘积数组

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
分析:
B[i]的值可以看作下图的矩阵中每行的乘积。 
下三角用连乘可以很容求得,上三角,从下向上也是连乘。 
因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。 

 class Solution {
public:
vector<int> multiply(const vector<int>& A)
{
int n=A.size();
vector<int> B(n);
B[]=;
for(int i=;i<n;++i)
{
B[i]=B[i-]*A[i-];
}
double temp=;
for(int i=n-;i>=;--i)
{
temp*=A[i+];
B[i]*=temp;
}
return B;
}
};

4.表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
分析:在代码里体现
 class Solution {
public:
bool isNumeric(char* string)
{
if(string==NULL)
return false;
if(*string=='+'||*string=='-')//首先判断第一个字符是不是正负号
++string;
if(*string=='\0')//边界判断
return false;
bool numeric=true;
scanDigits(&string);//扫描数位
if(*string!='\0')
{
if(*string=='.')//小数
{
++string;
scanDigits(&string);
if(*string=='e'||*string=='E')//科学记数法
numeric=isExp(&string);
}
//整数
else if(*string=='e'||*string=='E')
numeric=isExp(&string);
else
numeric=false;
}
return numeric&&*string=='\0';
}
void scanDigits(char** string)//扫描字符串中0到9的数位
{
while(**string !='\0'&&**string>=''&&**string<='')
++(*string);
}
bool isExp(char** string)//用来匹配用科学记数法表示数值的结尾部分,结尾部分的第一个字符是‘e’或者‘E’,接下来可能有一个正负号
{
if(**string!='e'&&**string!='E')
return false;
++(*string);
if(**string=='+'||**string=='-')
++(*string);
if(**string=='\0')
return false;
scanDigits(string);
return (**string=='\0') ? true:false;
}
};

5.字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。
例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。
当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述::如果当前字符流没有存在出现一次的字符,返回#字符。
分析:

 class Solution
{
public:
string s;
char hash[]={};
//Insert one char from stringstream
void Insert(char ch)
{
s+=ch;
hash[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
int size=s.size();
for(int i=;i<size;++i)
{
if(hash[s[i]]==)
return s[i];
}
return '#';
}
};

6.链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。

 /*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
//在链表中存在环的前提下找到一快一慢两个指针相遇的结点,一定在环内
ListNode* MeetingNode(ListNode* pHead)
{
if(pHead==NULL)
return NULL;
ListNode* pSlow=pHead->next;
if(pSlow==NULL)
return NULL;
ListNode* pFast=pSlow->next;
while(pFast!=NULL&&pSlow!=NULL)
{
if(pFast==pSlow)
return pFast;
pSlow=pSlow->next;
pFast=pFast->next;
if(pFast!=NULL)
pFast=pFast->next;
}
return NULL;
}
//找到环中任意一个结点之后,就能得出环中结点的数目,并找到环的入口结点
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode=MeetingNode(pHead);
if(meetingNode==NULL)//没有环
return NULL;
//计算环中结点数
int nodesInLoop=;
ListNode* pNode1=meetingNode;
//从相遇的结点开始,一边继续向前移动一边计数,当再次回到这个结点,就统计出了环中节点数
while(pNode1->next!=meetingNode)
{
pNode1=pNode1->next;
++nodesInLoop;
}
//接下来找链表环的入口结点
//分三步:
//第一步:指针p1和p2初始化时都指向链表头结点
//第二步:由于环中有nodesInLoop个结点,指针p1先在链表上向前移动nodesInLoop步
//第三步:指针p1和p2以相同速度移动,直到相遇,相遇结点就是环的入口结点
pNode1=pHead;
for(int i=;i<nodesInLoop;++i)
pNode1=pNode1->next;
ListNode* pNode2=pHead;
while(pNode1!=pNode2)
{
pNode1=pNode1->next;
pNode2=pNode2->next;
}
return pNode1;
}
};

7.删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

 /*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead==nullptr)
return pHead;
ListNode dummy(INT_MIN);//头结点
dummy.next=pHead;
ListNode *prev=&dummy,*cur=pHead;
while(cur!=nullptr){
bool duplicates=false;
while(cur->next!=nullptr&&cur->val==cur->next->val)
{
duplicates=true;
ListNode *tmp=cur;
cur=cur->next;
delete tmp;
}
if(duplicates)
{
//删除重复的最后一个元素
ListNode *tmp=cur;
cur=cur->next;
delete tmp;
continue;
}
prev->next=cur;
prev=prev->next;
cur=cur->next;
}
prev->next=cur;
return dummy.next;
}
};

8.二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
分析二叉树的下一个节点,一共有以下情况: 
1.二叉树为空,则返回空; 
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点; 
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。

 /*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { }
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL)
return NULL;
TreeLinkNode* pNext=NULL;
if(pNode->right!=NULL)
{
TreeLinkNode* pRight=pNode->right;
while(pRight->left!=NULL)
pRight=pRight->left;
pNext=pRight;
}
else if(pNode->next!=NULL)
{
TreeLinkNode* pCurrent=pNode;
TreeLinkNode* pParent=pNode->next;
while(pParent!=NULL&&pCurrent==pParent->right)
{
pCurrent=pParent;
pParent=pParent->next;
}
pNext=pParent;
}
return pNext;
}
};

9.对称二叉树

 /*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/ class Solution {
public:
bool help(TreeNode *root1,TreeNode *root2)
{
if(root1==)
return root2==;
if(root2==)
return false;
return(root1->val==root2->val)&&help(root1->left,root2->right)&&help(root1->right,root2->left);
}
bool isSymmetrical(TreeNode *root)
{
if(root==){
return true;
}
return help(root->left,root->right);
}
};

10.按之字顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

 /*
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> > Print(TreeNode* pRoot)
{
vector<vector<int>> vv;
if(pRoot == NULL)
return vv;
deque<TreeNode *> q;
q.push_back(pRoot);
bool flag = true;//true表示从左向右存储层次遍历,否则是从右向左
int levelCnt = ;//上一层的节点数目
int curLevelCnt = ;//下一层节点数目
vector<int> v;
while(!q.empty())
{
TreeNode *cur;
if(flag)
{
cur = q.front();
q.pop_front();
}
else
{
cur = q.back();
q.pop_back();
}
if(flag)
{
if(cur->left)
{
q.push_back(cur->left);
++curLevelCnt;
}
if(cur->right)
{
q.push_back(cur->right);
++curLevelCnt;
}
}
else
{
if(cur->right)
{
q.push_front(cur->right);
++curLevelCnt;
}
if(cur->left)
{
q.push_front(cur->left);
++curLevelCnt;
}
}
v.push_back(cur->val);
--levelCnt;
if(levelCnt == )
{//这一层完毕
vv.push_back(v);
v.clear();
levelCnt = curLevelCnt;
curLevelCnt = ;
flag = !flag;
}
}
return vv;
}
};

11.把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
 /*
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> > Print(TreeNode* pRoot)
{
vector<vector<int> > result;
queue<TreeNode*> current,next;
if(pRoot==NULL)
return result;
else
current.push(pRoot);
while(!current.empty()){
vector<int> level;//元素在一层
while(!current.empty()){
TreeNode* node=current.front();
current.pop();
level.push_back(node->val);
if(node->left!=NULL)
next.push(node->left);
if(node->right!=NULL)
next.push(node->right);
}
result.push_back(level);
swap(next,current);
}
return result;
}
};

12.二叉搜索树的第k个结点

 /*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
//按照中序遍历的顺序遍历一颗二叉搜索树,遍历序列的数值是递增排序的
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot==NULL||k==)
return NULL;
return KthNodeCore(pRoot,k);
}
TreeNode* KthNodeCore(TreeNode* pRoot, int& k)
{
TreeNode* target=NULL;
if(pRoot->left!=NULL)
target=KthNodeCore(pRoot->left,k);
if(target==NULL)
{
if(k==)
target=pRoot;
k--;
}
if(target==NULL&&pRoot->right!=NULL)
target=KthNodeCore(pRoot->right,k);
return target;
}
};

剑指offer第七章&第八章的更多相关文章

  1. 剑指offer第六章

    剑指offer第六章 1.数字在排序数组中出现的次数 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在数组中出现了4次,所以输出4 分析:思路1 ...

  2. 剑指offer第五章

    剑指offer第五章 1.数组中出现次数超过一半的数 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组 ...

  3. 剑指offer第四章

    剑指offer第四章 1.二叉树的镜像 二叉树的镜像:输入一个二叉树,输出它的镜像 分析:求树的镜像过程其实就是在遍历树的同时,交换非叶结点的左右子结点. 求镜像的过程:先前序遍历这棵树的每个结点,如 ...

  4. 剑指offer第三章

    剑指offer第三章 1.数值的整数次方 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. class Solution { public ...

  5. 《剑指Offer》第二章(一)题3-8

    为春招实习做准备,记录一下<剑指Offer>里面的面试题 第二章 面试题3:数组之中的重复数字. 这个题吧,虽然不难,但是不知道为什么就是看了很久,可能很久没有做算法题了.最后面一句话说的 ...

  6. 《剑指Offer》第二章(一)题 9 -12

    第二章 面试题9:用两个栈实现队列 题目:如面试题,给你两个栈, 实现队列的先进先出,即在队列头删除一个元素以及在队列的尾部添加一个元素 思路:这个题的分析感觉很巧妙,从一个具体的例子入手,找出其中的 ...

  7. 剑指offer—第三章高质量代码(o(1)时间删除链表节点)

    题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点,链表节点与函数的定义如下:struct ListNode{int m_nValue;ListNode* m_pValue ...

  8. 剑指offer—第三章高质量的代码(按顺序打印从1到n位十进制数)

    题目:输入一个数字n,按照顺序打印出1到最大n位十进制数,比如输入3,则打印出1,2,3直到最大的3位数999为止. 本题陷阱:没有考虑到大数的问题. 本题解题思路:将要打印的数字,看成字符串,不足位 ...

  9. 剑指offer—第三章高质量代码(数值的整数次方)

    高质量的代码:容错处理能力,规范性,完整性.尽量展示代码的可扩展型和可维护性. 容错处理能力:特别的输入和处理,异常,资源回收. 规范性:清晰的书写,清晰的布局,合理的命名. 完整性:功能测试,边界测 ...

随机推荐

  1. Eclipse 使用中遇到的一些问题!

    解决办法~ 1.先检查本地svn 版本与Eclipse 中svn插件 的区别 2.发现版本一致,没解决,发现如图 发现   svn接口报错 javaHL(JNI) Not Available!@ 所以 ...

  2. 深入了解JavaScript中的Symbol的使用方法

    这篇文章主要介绍了深入了解JavaScript中的Symbol的使用方法,本文针对ES6版本的JS进行讲解,需要的朋友可以参考下 Symbol 是什么? Symbols 不是图标,也不是指在代码中可以 ...

  3. 在Web API 2 中实现带JSON的Patch请求

    译文:http://www.cnblogs.com/kexxxfeng/p/the-patch-verb-in-web-api-2-with-json.html 原文:https://carly.io ...

  4. Learning R笔记(一)

    基本操作 帮助文档:?函数.演示:demo(函数).参数列表:formals(函数),返回为成对列表pairlist. 用all.equal函数检查浮点数是否相等,容忍度默认为1.5e-8,如果相等返 ...

  5. Java集合详解8:Java的集合类细节精讲

    Java集合详解8:Java集合类细节精讲 今天我们来探索一下Java集合类中的一些技术细节.主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充.可能不全面,还请谅解. 本文参考:http:// ...

  6. 1-15-2-RAID1 企业级RAID磁盘阵列的搭建(RAID1、RAID5、RAID10)

    大纲: 1.创建RAID1 2.创建RAID5 3.创建RAID10 =============================== 1.创建RAID1 RAID1原理:需要两块或以上磁盘,可添加热备 ...

  7. UVA-11367 Full Tank? (dijkstra)

    题目大意:有n个加油站,每个加油站的油价已知,并且已知油箱的大小,问能否从起点走到终点,若能,找出最小油费. 题目分析:记得在做暴力搜索的时候做过这道题,不算难.但是这次是用dijkstra算法做的, ...

  8. day6-面向对象基础篇

    一.面向对象引子及概念 结合编程的一些理论知识和实践,可以总结出目前存在以下编程模式: 1. 面向过程 按照业务逻辑和实现过程步骤来逐步垒代码,代码编写的逻辑即对应于实际实现的步骤过程,核心是过程两个 ...

  9. spring中aop使用

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查.缓存) Spring的基 ...

  10. CMDB Autoclient思路分析

    1.start.py里的script.run():执行run函数--> 2.script.py run方法--> 3.判断模式MODE(Agent/SSHSALT)-->4.执行cl ...