1. 程式人生 > >【演算法】把字串轉換成整數,樹中兩個結點的最低公共祖先

【演算法】把字串轉換成整數,樹中兩個結點的最低公共祖先

本書最後的兩道題,作者拿了兩個面試案例來呈現,主要是要弄清面試官的意圖、考慮周全,有些演算法雖然容易,不要輕易下手。在此之上最好寫出具有魯棒性的和好的擴充套件性的程式碼,遵循編碼規範。

面試題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》這本書到此結束了。