版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/83348918
本书最后的两道题,作者拿了两个面试案例来呈现,主要是要弄清面试官的意图、考虑周全,有些算法虽然容易,不要轻易下手。在此之上最好写出具有鲁棒性的和好的扩展性的代码,遵循编码规范。
面试题67:把字符串转换成整数
请你写一个函数StrToInt,实现把字符串转换成整数这个功能。当然,不能使用atoi或者其他类似的库函数。
#include<bits/stdc++.h>
using namespace std;
enum Status {kValid = 0, kInvalid};//枚举值表示状态:未出错,出错
int g_nStatus = kValid;//全局变量记录是否出错,默认是未出错
//minus指示是否为负,digit是未经检查的纯数字串
//转换成long long类型的数字,这样能在一定程度上检测是否int溢出
//如果直接用int,完全不能检测int自己的溢出...
long long StrToIntCore(const char* digit, bool minus) {
long long num = 0;//用来保存转换后的数字
while(*digit != '\0') {//没到串结束符
if(*digit >= '0' && *digit <= '9') {//在0~9这个合法范围内
int flag = minus ? -1 : 1;//是负的后面就要乘以-1
//高位*10+低位
num = num * 10 + flag * (*digit - '0');//这里直接在每一位上乘了flag
//正数溢出,或者负数溢出
//一个好处是及时判断,快速失败
//另一好处是,本来long long只能在一定程度上检测是否int溢出
//(即如果long long自己溢出了就可能检测不到int溢出了)
//这里及时判断一定可以检测int溢出
//因为long long比int的范围多了不止一位数
if((!minus && num > 0x7FFFFFFF)
|| (minus && num < (signed int)0x80000000)) {
num = 0;//没法转换,就给个0
break;//跳出循环
}
digit++;//这一位转换完了,往后走一位
} else {//如果有字符不在合法范围
num = 0;//没法转换,就给个0
break;//跳出循环
}
}
if(*digit == '\0')//正常结束循环的标识
g_nStatus = kValid;//记录可以成功转换
return num;
}
//字符串转整数
int StrToInt(const char* str) {//这里const指针防止修改字符串的值
g_nStatus = kInvalid;//先设置为出错状态
long long num = 0;//转换来的整数
if(str != nullptr && *str != '\0') {//不是空指针也不是空串
bool minus = false;//指示是否是负数,默认不是
//这里基本就是写个Parser
if(*str == '+')//如果是+号开头
str ++;//跳过加号
else if(*str == '-') {//-号开头
str ++;//跳过减号
minus = true;//记录是负数
}
//至此,正负记录完毕,指针应该指向数字部分最高位
if(*str != '\0')//检查一下不是串结束符
num = StrToIntCore(str, minus);//从该位置开始调用纯数字的转换
}
return (int)num;//long long转成int,溢出检查已经在Core里做了
}
int main() {
cout<<StrToInt("-2147483648")<<endl;//有效的最小负整数,0x80000000
return 0;
}
面试题68:树中两个结点的最低公共祖先
输入两个树结点,求它们的最低公共祖先。
#include<bits/stdc++.h>
#include"../Utilities/Tree.h"
using namespace std;
//递归函数
//获得pRoot到pNode的路径,将这个路径保存在path中,返回是否能到达
bool GetNodePath(const TreeNode* pRoot, const TreeNode* pNode, list<const TreeNode*>& path) {
if(pRoot == pNode)//递归出口:同一结点
return true;
path.push_back(pRoot);//根结点是路径的第一个结点
bool found = false;//先设定成不可达
//前序遍历DFS,这层遍历所有子结点
//更正:后面是用cbegin()而不是begin()
vector<TreeNode*>::const_iterator i = pRoot->m_vChildren.cbegin();
while(!found && i < pRoot->m_vChildren.end()) {//找到了,或者子结点全遍历完了就退出
found = GetNodePath(*i, pNode, path);//递归地去看从子结点能否到那个路径
++i;
}
if(!found)//没找到
path.pop_back();//把这个结点弹出再回到上一层
return found;//回到上一层
}
//得到两条路径path1和path2的最后一个公共结点
const TreeNode* GetLastCommonNode
(
const list<const TreeNode*>& path1,
const list<const TreeNode*>& path2
) {
//两条路径的开始之处,更正:这里应用cbegin()而不是begin()
list<const TreeNode*>::const_iterator iterator1 = path1.cbegin();
list<const TreeNode*>::const_iterator iterator2 = path2.cbegin();
const TreeNode* pLast = nullptr;//记录最后一个公共结点
//两个迭代器都没走到底,更正:这里应用cend()而不是end()
while(iterator1 != path1.cend() && iterator2 != path2.cend()) {
if(*iterator1 == *iterator2)//存的内容是地址,地址一样就是同一个结点
pLast = *iterator1;//这个结点成为目前找到的最后的公共结点
//两个迭代器同步往下走
iterator1++;
iterator2++;
}
return pLast;//最后得到的就是最低(最后一个)公共结点
}
//在pRoot为根的树中找pNode1和pNode2的最低公共祖先并返回
const TreeNode* GetLastCommonParent(const TreeNode* pRoot, const TreeNode* pNode1, const TreeNode* pNode2) {
//输入合法性检查
if(pRoot == nullptr || pNode1 == nullptr || pNode2 == nullptr)
return nullptr;
//到pNode1的路径链表
list<const TreeNode*> path1;
GetNodePath(pRoot, pNode1, path1);
//到pNode2的路径链表
list<const TreeNode*> path2;
GetNodePath(pRoot, pNode2, path2);
//两个链表的最后一个公共结点即是所求
return GetLastCommonNode(path1, path2);
}
// 形状普通的树
// 1
// / \
// 2 3
// / \
// 4 5
// / \ / | \
// 6 7 8 9 10
int main() {
TreeNode* pNode1 = CreateTreeNode(1);
TreeNode* pNode2 = CreateTreeNode(2);
TreeNode* pNode3 = CreateTreeNode(3);
TreeNode* pNode4 = CreateTreeNode(4);
TreeNode* pNode5 = CreateTreeNode(5);
TreeNode* pNode6 = CreateTreeNode(6);
TreeNode* pNode7 = CreateTreeNode(7);
TreeNode* pNode8 = CreateTreeNode(8);
TreeNode* pNode9 = CreateTreeNode(9);
TreeNode* pNode10 = CreateTreeNode(10);
ConnectTreeNodes(pNode1, pNode2);
ConnectTreeNodes(pNode1, pNode3);
ConnectTreeNodes(pNode2, pNode4);
ConnectTreeNodes(pNode2, pNode5);
ConnectTreeNodes(pNode4, pNode6);
ConnectTreeNodes(pNode4, pNode7);
ConnectTreeNodes(pNode5, pNode8);
ConnectTreeNodes(pNode5, pNode9);
ConnectTreeNodes(pNode5, pNode10);
cout<<GetLastCommonParent(pNode1,pNode6,pNode8)->m_nValue<<endl;//2
return 0;
}
《剑指Offer》这本书到此结束了。