《剑指offer系列》-day3

文章目录

  • 一. 根据前中序完成二叉树(不包含重复数据)的重建
    • 1. 思路:
    • 2. 下面代码中的递归语句理解:
    • 3. 代码如下(另有相关代码注释帮助理解):
  • 二.二进制计算一个数字里面有几个1
  • 三. 输入一个单链表,输出倒数第K个节点
  • 四. 每日小感慨

一. 根据前中序完成二叉树(不包含重复数据)的重建

1. 思路:

先序遍历第一个就是根节点,所以拿着前序的根节点在中序序列中找到根节点的位置。先找到根节点,进而划分左子树和右子树的前中序序列。划分如下:
(1)如何划分前序(根节点,左子树前序,右子树前序)
(2)如何划分中序(左子树中序,根节点,右子树中序)

中序序列中,根节点前面有几个值,在前序中,根节点后面几个就是左子树的相应的那几个节点。这样,我们就实现了数组的减小,从而获得root左子树的前中序序列,再将这一对再进行一次上述操作,实现数组的进一步减小,进而实现最后的二叉树的重建。如下图所示:
《剑指offer系列》-day3_第1张图片

像这样就可以一直递归下去……
2. 根据思路我们采用的是对于数组逐渐缩小的,分阶段进行划分的。所以我们要有对于下标的细致处理,所以我们需要前序的首尾和中序的首尾下标来进行。

2. 下面代码中的递归语句理解:

《剑指offer系列》-day3_第2张图片
《剑指offer系列》-day3_第3张图片

3. 代码如下(另有相关代码注释帮助理解):

class Solution
{
	public:
	TreeNode* reConstructBinaryTreeHelper(vector<int>&pre,int pre_start,int pre_end,vector<int>&vin,int vin_start,int vin_end)
	{
		if(pre_start>pre_end ||vin_start>vin_end)//递归出口
		{
			return nullptr;
		}
		
		//闭区间
		TreeNode* root=new TreeNode(pre[pre_start]);
		//阶段性处理时,根节点不止是下标为0的,而是每一次前序的首个元素。
		
		for(auto i=vin_start;i<vin.end;i++)
		//遍历中序找到根节点的位置
		{
			if(pre[pre_start]==vin[i])//说明在中序序列中找到了根节点的位置 [vin_start,i-1] i [i+1,vin_end]
			{
				//分别进行左右子树的重建
				root->left=reConstructBinaryTreeHelper(pre,pre_start+1,pre_start + 1 + i-vin_start-1,vin,vin_start,i-1);
				root->right=reConstructBinaryTreeHelper(pre,pre_start+i-vin_start +1,pre_end, vin,i+1,vin_end);
				break;
			}
		}
		//二叉树重建完毕
		return root;
	}
	TreeNode* reConstructBinaryTree(vector<int>pre,vector<int>vin)
	{
		//对于特殊情况的判断
		if(pre.empty()||vin.empty()||pre.size()!=vin.size())
			return NUll;
		return reConstructBinaryTreeHelper(pre,0,pre.size()-1,vin,0,vin.size()-1);
		//首次传的时候前序下标就是0,中序下标就是i+1.
	}
}

二.二进制计算一个数字里面有几个1

记录整数中的1的个数,我们正常是和1按位与。但是我们不是和一个单独的1进行运算,要注意1的二进制形式前面全是0,虽然只是和最后一位按位与,其他全置为0而已。
考虑到命中的效率问题不推荐左移右移,比如0比较松散或者1比较集中。

所以推荐的算法就是和自己小一位的数字进行按位与的操作,
x& x-1 直到结果为0,按位与了几次,就有几个1
下图为演示:
《剑指offer系列》-day3_第4张图片
代码如下:

int Numberof1(int n)
{
	int count=0;
	while(n)
	{
		n&=(n-1);
		count++;
	}
	return count;
}

三. 输入一个单链表,输出倒数第K个节点

由题可得,这是一个单链表,所以我们不能从后往前来数。
大家可能会有很多种想法,我来为大家推荐的是:
前后指针的思想,前面指针先走k步,然后前后指针同时继续跑。直到前指针到尾部,这时后指针就是倒数第k个节点。

ListNode FindKthToTail(ListNode head,int k)
{
	if(head==null||k<0) return null;
	
	ListNode front=head;
	ListNode rear=head;
	while(k>0&& front!=Null)//逻辑与的特点就是只要前面的条件k不符合就会直接跳出
	{
		front=front.next;
		k--;
	}
	while(front!=Null)//只要能进来就说明k的值是合理的。
	{
		front=front.next;
		rear=rear.next;
	}
	return k>0?null:rear;
	//如果k的值不符合条件就说明k的值并不合理,所以返回空。
	
}

四. 每日小感慨

有的时候,我们会心血来潮给自己定很高的目标,这本没有错。但是计划赶不上变化,可能就会完不成目标而对自己的能力产生怀疑而心态爆炸。所以送大家一句话:
***完成有的时候要大于完美。***完成一件事会给予我们心灵上的肯定,进而有下一步的勇气。有的时候,“放自己一马”,并不是对于自身标准的降低,反而是将心中的傲气“泄气”,从而有更好的状态去面对未来。

好了,希望我的每日分享,能给你带来知识,以一种放松的状态充实自己!

你可能感兴趣的:(算法习题,c++)