关于《剑指offer》的66道编程题的总结(七----本系列结束)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43949535/article/details/100711423

2019年9月10日20:27:25

(第六十题)矩形覆盖

2019年9月10日22:06:15
题目链接:
https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=13&tqId=11214&tPage=4&rp=4&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/*
请实现两个函数,分别用来序列化和反序列化二叉树

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,
从而使得内存中建立起来的二叉树可以持久保存。
序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,
序列化的结果是一个字符串,
序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
*/

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
	//这个是根据先中序 建树的函数
	TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin)
	{
		int size1 = pre.size();
		int size2 = vin.size();

		if (size1 == 0 || size2 == 0)//递归终止条件
		{
			return nullptr;
		}

		int root_val = pre[0];
		TreeNode* root = new TreeNode(root_val);//先序的第一个值 为root根节点

		//分别定义左右子序列的 先序 中序序列
		vector<int>pre_left, pre_right, vin_left, vin_right;

		//第一步:求出这个树的根节点root_val在中序序列中的位置
		vector<int>::iterator it_root = vin.begin();
		int k = 0;
		for (; it_root != vin.end(); ++it_root)
		{
			if (*it_root == root_val)
			{
				break;
			}
			k++;//k保存的是左子树的中序序列的个数
			//此时的it_root 正是这个树的根root_val在中序序列中的位置
		}
		//第二步:把左子树的中序序列和先序序列给求出来
		for (int i = 0; i < k; ++i)
		{
			pre_left.push_back(pre[i + 1]);//把先序序列中的左子树的部分放到左子树先序序列里面
			vin_left.push_back(vin[i]);//把中序序列中的左子树的部分放到左子树中序序列里面
		}
		//第三步:把右子树的中序序列和先序序列给求出来
		for (int i = k + 1; i < size1; ++i)//别把根节点给插进去了
		{
			pre_right.push_back(pre[i]);//把先序序列中的右子树的部分放到右子树先序序列里面
			vin_right.push_back(vin[i]);//把中序序列中的右子树的部分放到右子树中序序列里面
		}
		//第四步:递归调用 建树
		root->left = reConstructBinaryTree(pre_left, vin_left);//建立左子树
		root->right = reConstructBinaryTree(pre_right, vin_right);//建立右子树

		return root;
	}

	void Serialize_Operator(TreeNode* this_node, string& str)//先序遍历 进行序列化
	{
		if (this_node == nullptr)
		{
			str.push_back('#');
			return;
		}
		str += to_string(this_node->val);
		str.push_back('!');

		Serialize_Operator(this_node->left, str);//序列化左子树
		Serialize_Operator(this_node->right, str);//序列化右子树
	}
	char* Serialize(TreeNode* root) 
	{
		if (root == nullptr)
			return nullptr;
		string str = "";
		
		Serialize_Operator(root, str);//把序列化结果放在str里面
		char* result = new char[str.size() + 1];
		/*int k = 0;
		for (char val : str)
		{
			result[k++] = val;
		}
		result[k] = '\0';*/
		strcpy(result, str.c_str());
		return result;
	}

	TreeNode* Deserialize_Operator(string& str)//进行反序列化
	{
		if (str.empty())
			return nullptr;

		if (str[0] == '#')//若是上来就是 # 没有根节点,完蛋
		{
			str = str.substr(1);
			return nullptr;
		}
		TreeNode* root = new TreeNode(stoi(str));//建立这个子树的根节点
		str = str.substr(str.find_first_of('!') + 1);//把数值 和 !多给跳过去

		root->left = Deserialize_Operator(str);
		root->right = Deserialize_Operator(str);

		return root;
	}
	TreeNode* Deserialize(char* str) 
	{
		if (str == nullptr)
			return nullptr;

		string mystr(str);

		TreeNode* result = Deserialize_Operator(mystr);//进行反序列化
		return result;
	}
};
int main()
{
	Solution solution;
	
	vector<int>pre({ 1,2,4,7,3,5,6,8 });//先序遍历
	vector<int>vin({ 4,7,2,1,5,3,8,6 });//中序遍历


	TreeNode* myTree = solution.reConstructBinaryTree(pre, vin);//完成建树

	//下面进行测试 二叉树根据前序遍历得到的序列化函数
	//先进行预测结果:先序序列如下
	//                              1!2!4!#7!###3!5!##6!8!###
	char* p = solution.Serialize(myTree);
	cout << p << endl;//打印一下
	
	//下面测试 反序列化函数
	//预测结果:建一棵新树成功,我们继续  对这个新树 进行序列化 看其结果怎样
	TreeNode* new_of_myTree = solution.Deserialize(p);

	char* p1 = solution.Serialize(new_of_myTree);//测试反序列化函数
	cout << p1 << endl;//打印一下

	return 0;
}

在这里插入图片描述
测试如下:
在这里插入图片描述
2019年9月10日22:08:50

(第六十一题)矩阵中的路径

2019年9月11日01:20:21
题目链接:
https://www.nowcoder.com/practice/c61c6999eecb4b8f88a98f66b273a3cc?tpId=13&tqId=11218&tPage=4&rp=4&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/*
思路:回溯算法。
1.将 matrix 里的每一个字符作为起点去跟 str 字符串匹配。
2.成功就选择该起点的上下左右再去跟 str 字符串匹配直到 str 字符串全部匹配成功。
3.失败就直接返回。
*/
class Solution {
public:
	static bool hasPath_Operator(const char* matrix, int rows, int cols, int cur_row, int cur_col, const char* str, bool*& isVisited)
	{
		if (*str == '\0') return true;
		if (0 <= cur_row && cur_row < rows 
			&& 0 <= cur_col && cur_col < cols
			&& !isVisited[cur_row * cols + cur_col] 
			&& matrix[cur_row * cols + cur_col] == *str)
		{
			isVisited[cur_row * cols + cur_col] = true;
			if (hasPath_Operator(matrix, rows, cols, cur_row - 1, 
			cur_col, str + 1, isVisited)//上
				|| hasPath_Operator(matrix, rows, cols, cur_row + 1, 
			cur_col, str + 1, isVisited)//下
				|| hasPath_Operator(matrix, rows, cols, cur_row, 
			cur_col - 1, str + 1, isVisited)//左
				|| hasPath_Operator(matrix, rows, cols, cur_row, 
			cur_col + 1, str + 1, isVisited))//右
			{
				return true;
			}
			else
			{
				//此路不通的话,把路径恢复
				isVisited[cur_row * cols + cur_col] = false;
			}
		}
		return false;
	}
	bool hasPath(const char* matrix, int rows, int cols, const char* str)
	{
		if (matrix == nullptr || rows < 1 || cols < 1 || str == nullptr)
			return false;

		bool* isVisited = new bool[rows * cols];
	
		memset(isVisited, 0, rows * cols);
	
		for (int i = 0; i < rows; ++i)//遍历矩阵中每个元素
		{
			for (int j = 0; j < cols; ++j)//从每个元素出发
			{
				if (hasPath_Operator(matrix, rows, cols, i, j, str, isVisited) == true)
				{
					return true;
				}
			}
		}
		delete[]isVisited;
		return false;
	}
};
int main()
{
	Solution solution;
	
	const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS";
	const char* str = "SGGFIECVAASABCEHJIGQEM";

	if (solution.hasPath(matrix, 5, 8, str) == true)
	{
		cout << "存在路径" << endl;
	}
	else cout << "不存在路径" << endl;
	return 0;
}
/**
*备用注释:
*
*
*
*/

在这里插入图片描述
在这里插入图片描述
2019年9月11日01:23:29

(第六十二题)二叉搜索树的后序遍历序列

2019年9月12日11:06:46
题目链接:
https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/*
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。


算法思想:
BST树的后序遍历得到的数列 最后一个元素为根节点root_val
于是该数列就可以划分成两段了:前面小于root_val,后面大于root_val
而且这两端 分贝又成了一个BST树。

左子树一定比右子树小,因此去掉根后,数字分为left,right两部分,right部分的最后一
个数字是右子树的根,它也比左子树所有值大,因此我们可以每次只看有子树是否符合条件
即可。即使到达了左子树,而左子树也可以看出由左  右子树组成的树还像右子树那样处理。
对于左子树回到了原问题,对于右子树,左子树的所有值都比右子树的根小可以暂时把他看出右子树的左子树,只需看看右子树的右子树是否符合要求即可。

*/
class Solution {
public:
	bool VerifySquenceOfBST_Operator(vector<int>& sequence, int low, int high)
	{
		if (low >= high)//相等 这是一个叶子节点
		{
			return true;//大于是 没有右孩子或者左孩子
		}

		int root_val = sequence[high];//把这棵BST树的根节点值拿到
		int k = 0;//计算左子树上节点的个数的

		for (int i=low;i<high;++i)
		{
			if (sequence[i] < root_val)
			{
				k++;
			}
			else break;//没必要向后走了
		}

		//现在我就得到了最后一个是根节点
		//前面左子树的节点数是 【low,low+k-1】共k个节点
		//后面右子树的节点数是 【low+k,high-1】

		//low+k的指向是:右子树的第一个节点
		//如果是在右子树序列中发现有小于root_val的 出错
		for (int i = low + k; i <= high - 1; ++i)
		{
			if (sequence[i] < root_val)
				return false;
		}

		return VerifySquenceOfBST_Operator(sequence, low, low + k - 1) 
			&& VerifySquenceOfBST_Operator(sequence, low + k, high - 1);
	}

	bool VerifySquenceOfBST(vector<int> &sequence) 
	{
		int size = sequence.size();
		if (size == 0)
			return false;

		int low = 0;
		int high = size - 1;

		return VerifySquenceOfBST_Operator(sequence, low, high);
	}
};

(第六十三题)二叉搜索树与双向链表

2019年9月12日12:03:35
题目链接:
https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=11179&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:非递归实现

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
	TreeNode* Convert(TreeNode* pRootOfTree)
	{
		if (pRootOfTree == nullptr)
			return nullptr;
		stack<TreeNode*>mystack;

		TreeNode* head = nullptr;//作为最后返回链表的头指针
		TreeNode* pre = nullptr;
		TreeNode* p = pRootOfTree;

		bool this_is_first = true;
		while (p != nullptr || !mystack.empty())
		{
			while (p != nullptr)//找这个子树上 最左的元素
			{
				mystack.push(p);//或者说是其 中序遍历的第一个节点
				p = p->left;
			}
			
			p = mystack.top();
			mystack.pop();
			if (this_is_first == true)//此时已经找到了中序遍历的第一个节点
			{
				head = p;
				pre = p;
				this_is_first = false;
			}
			else
			{
				pre->right = p;//两个指针相连
				p->left = pre;

				pre = p;//走向下一个节点
			}
			p = p->right;
		}
		//此时BST树 变成了一个双向链表
		return head;
	}
};

2019年9月12日12:04:59

(第六十四题)序列化二叉树

2019年9月12日12:07:52
题目链接:
https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=13&tqId=11214&tPage=4&rp=4&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
	void Serialize_Operator(TreeNode* this_node, string& str)//先序遍历 进行序列化
	{
		if (this_node == nullptr)
		{
			str.push_back('#');
			return;
		}
		str += to_string(this_node->val);
		str.push_back('!');

		Serialize_Operator(this_node->left, str);//序列化左子树
		Serialize_Operator(this_node->right, str);//序列化右子树
	}
	char* Serialize(TreeNode* root) 
	{
		if (root == nullptr)
			return nullptr;
		string str = "";
		
		Serialize_Operator(root, str);//把序列化结果放在str里面
		char* result = new char[str.size() + 1];
		/*int k = 0;
		for (char val : str)
		{
			result[k++] = val;
		}
		result[k] = '\0';*/
		strcpy(result, str.c_str());
		return result;
	}

	TreeNode* Deserialize_Operator(string& str)//进行反序列化
	{
		if (str.empty())
			return nullptr;

		if (str[0] == '#')//若是上来就是 # 没有根节点,完蛋
		{
			str = str.substr(1);
			return nullptr;
		}
		TreeNode* root = new TreeNode(stoi(str));//建立这个子树的根节点
		str = str.substr(str.find_first_of('!') + 1);//把数值 和 !多给跳过去

		root->left = Deserialize_Operator(str);
		root->right = Deserialize_Operator(str);

		return root;
	}
	TreeNode* Deserialize(char* str) 
	{
		if (str == nullptr)
			return nullptr;

		string mystr(str);

		TreeNode* result = Deserialize_Operator(mystr);//进行反序列化
		return result;
	}
};

2019年9月12日12:09:17

(第六十五题)二叉搜索树的第k个节点

2019年9月12日12:51:59
题目链接:
https://www.nowcoder.com/practice/ef068f602dde4d28aab2b210e859150a?tpId=13&tqId=11215&tPage=4&rp=4&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:借助于BST树的中序遍历 非递归实现

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 == nullptr)
			return nullptr;
		stack<TreeNode*>mystack;
		TreeNode* top_node = pRoot;
		int i = 0;
		while (top_node != nullptr || !mystack.empty())
		{
			if (top_node != nullptr)
			{
				mystack.push(top_node);
				top_node = top_node->left;
			}
			else
			{
				top_node = mystack.top();
				i++;
				if (k == i)
					return top_node;
				mystack.pop();
				top_node = top_node->right;
			}
		}
		return nullptr;
	}
};

2019年9月12日12:53:37

(第六十六题)扑克牌顺子

2019年9月12日16:35:34
题目链接:
https://www.nowcoder.com/practice/762836f4d43d43ca9deb273b3de8e1f4?tpId=13&tqId=11198&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/**══════════════════════════════════╗
*作    者:songjinzhou                                                 ║
*CSND地址:https://blog.csdn.net/weixin_43949535                       ║
**GitHub:https://github.com/TsinghuaLucky912/My_own_C-_study_and_blog║
*═══════════════════════════════════╣
*创建时间:2019年9月12日15:55:28                                                            
*功能描述:                                                            
*                                                                      
*                                                                      
*═══════════════════════════════════╣
*结束时间: 2019年9月12日16:33:54                                                            
*═══════════════════════════════════╝
//                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
//            __.'              ~.   .~              `.__
//          .'//              西南\./联大               \\`.
//        .'//                     |                     \\`.
//      .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
//    .'//.-"                 `-.  |  .-'                 "-.\\`.
//  .'//______.============-..   \ | /   ..-============.______\\`.
//.'______________________________\|/______________________________`.
*/
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;


class Solution {
public:
	bool IsContinuous(vector<int> &numbers) 
	{
		int size = numbers.size();
		if (size < 1 || size>5)
			return false;
		
		//里面的数据范围是0  ----   13
		sort(numbers.begin(), numbers.end());//所以要先进行一项排序操作
		int num_of_0 = 0;//统计0出现的次数

		//同时num_of_0这个变量 是第一个不为0的数的下标 或者说:最小值的下标

		int i = 0;
		for (;i<5;++i)
		{
			if (numbers[i] == 0)//计算0出现的次数
				num_of_0++;
			if (i < 4 && numbers[i] != 0 && numbers[i] == numbers[i + 1])
				return false;//一旦出现了 不是0的对子,那么一定不行
		}		
		if (num_of_0 == 5)//这是题目挖的坑 需要跳过
			return false;

		if (numbers[4] - numbers[num_of_0] >= 5)
		{
			return false;//最大值和最小值的差  超过了4,大小王个数也补不上
		}
		else return true;
	}
};
int main()
{
	
	
	return 0;
}
/**
*备用注释:
*
*
*
*/

2019年9月12日16:41:19

(第六十七题)正则表达式匹配

2019年9月12日17:36:30
题目链接:
https://www.nowcoder.com/practice/45327ae22b7b413ea21df13ee7d6429c?tpId=13&tqId=11205&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
题目描述:
在这里插入图片描述
代码如下:

/**══════════════════════════════════╗
*作    者:songjinzhou                                                 ║
*CSND地址:https://blog.csdn.net/weixin_43949535                       ║
**GitHub:https://github.com/TsinghuaLucky912/My_own_C-_study_and_blog║
*═══════════════════════════════════╣
*创建时间:2019年9月12日16:49:26                                                            
*功能描述:                                                            
*                                                                      
*                                                                      
*═══════════════════════════════════╣
*结束时间: 2019年9月12日17:35:11                                                        
*═══════════════════════════════════╝
//                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
//            __.'              ~.   .~              `.__
//          .'//              西南\./联大               \\`.
//        .'//                     |                     \\`.
//      .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
//    .'//.-"                 `-.  |  .-'                 "-.\\`.
//  .'//______.============-..   \ | /   ..-============.______\\`.
//.'______________________________\|/______________________________`.
*/
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;


class Solution {
public:

	bool match(char* str, char* pattern)
	{
		if (*str == '\0' && *pattern == '\0')
			return true;
			//模式串为空 匹配串不空 肯定不行
		if (str != nullptr && pattern == nullptr)
			return false;
		
		if (*(pattern + 1) != '*')//模式串的第二个不为* 共2种情况
		{
			//这是当前两个字符相等的情况
			if (*str == *pattern || (*pattern == '.' && *str != '\0'))
			{
			//这是当前两串的当前字符 真实相等				
				return match(str + 1, pattern + 1);
			}
			else
			{
				//这两个字符不相等 且模式串下一个字符还不是*
				return false;
			}
		}
		else//模式串的第二个为* 共2种情况
		{
			//这是当前两个字符相等的情况
			if (*str == *pattern || (*pattern == '.' && *str != '\0'))
			{
			//这是当前两串的当前字符 真实相等  匹配多次的情况
				return match(str + 1, pattern)//匹配多次的情况
					|| match(str, pattern + 2);//和 . 匹配上了  或者 匹配过了
			}
			else
			{
				//这两个字符不相等 且模式串下一个字符还不是*
				return match(str, pattern + 2);//匹配0次
			}
		}
	}
};
int main()
{
	
	
	return 0;
}
/**
*备用注释:
*
*
*
*/

本题分析:
请实现一个函数用来匹配包括 ‘.’ 和 ‘ * ’ 的正则表达式。模式中的字符 ‘.’ 表示任意一个字符,而 ‘*’ 表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab * ac * a"匹配,但是与"aa.a"和"ab * a"均不匹配

  1. 首先,考虑特殊情况:两个字符串都为空,返回true;当第一个字符串不为空,而第二个字符串为空,返回false(因为这样,就无法匹配成功了。而如果第一个字符串为空了,第二个字符串非空,有可能匹配成功,比如第二个字符串是 “a * a * a * a *”, ‘ * ’ 之前的元素可以出现0次)
  2. 之后就开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern下一个字符可能是 ‘ * ’ ,这里我们分两种情况讨论:pattern下一个字符为 ‘ * ’ 或不为 ‘ * ’ 。
  3. pattern下一个字符不为‘ * ’:直接匹配当前字符。如果匹配成功,继续匹配下一个;如果匹配失败,直接返回false。这里的“匹配成功”有两种情况,第一:两个字符相同,第二:pattern的当前字符为‘.’, 同时str的当前字符不为‘\0’。
  4. pattern下一个字符为 ‘ * ’ :稍微复杂一些,因为 ‘*’ 可以代表0个或多个。当 ‘ * ’ 配0个字符时,str当前字符不变,pattern当前字符后移两位,跳过这个 ‘ * ’ 符号;当 ‘ * ’ 匹配1个或多个时,str当前字符移向下一个,pattern当前字符不变。(这里匹配1个或多个可以看成一种情况,因为:当匹配一个时,由于str移到了下一个字符,而pattern字符不变,就回到了上边的情况;当匹配多于一个字符时,相当于从str的下一个字符继续开始匹配)。
  5. 之所以 在 pattern中下一个字符是 ‘*’,且当前字符匹配时。return match(str+1, pattern)|| match(str, pattern+2); 之所以是match(str, pattern+2),是因为可能出现匹配过了的情况。如下:

例子:“aaa”,“a * a”
pattern的第一个字符匹配到了ptr的第三个字符:
在这里插入图片描述
此时 这么做就是需要:
return match(str+1, pattern)|| match(str, pattern+2);

ptr的当前字符继续匹配与跳过pattern的 ‘ * ’,二者只要有一个匹配成功,即为匹配成功。
在这里插入图片描述
2019年9月12日17:56:24

猜你喜欢

转载自blog.csdn.net/weixin_43949535/article/details/100711423