【算法】把字符串转换成整数,树中两个结点的最低公共祖先

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 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》这本书到此结束了。

猜你喜欢

转载自blog.csdn.net/SHU15121856/article/details/83348918