《剑指offer系列》每日分享 day-4

文章目录

  • 一. 翻转单链表
    • 1.三指针的方法
    • 2. 头插的方法(推荐)
  • 二. 俩个单调递增的单链表合并为一个不递减的单链表
    • 1. 正常做法
    • 2.递归的方式实现
  • 三.二叉树 判断b是否是a的子树(空树不是任意一棵树的子树)
  • 四. 小激励来了

一. 翻转单链表

1.三指针的方法

在我们采用三指针进行单链表的翻转时,我们要考虑到三种情况:
(1) 当传过来的这个链表是一个空或者只有一个的时候,就不需要再进行翻转,直接返回就行
(2) 就是图示的正常情况,当三个指针指向的都有值。
(3)当最后一个指针指向空时,跳出循环要进行特殊处理,然后将头结点的指针进行处理。

图示:
《剑指offer系列》每日分享 day-4_第1张图片
代码以及注释如下:

ListNode ReverseList(ListNode head)
{
	if(head==NULL|| head.next=NULL)//如果是空,或者只有一个节点。就没有必要再进行反转
	{
		return head;
	}
	//以下就是两个及以上节点
	ListNode left=head;
	ListNode mid=left.next;
	ListNode right=mid.next;//指向第三个节点是可能是空的
	while(right)
	{
		mid.next=left;//改变两个节点的指向方向
		//剩下的基石将三个指针向后移动
		left=mid;
		mid=right;
		right = right.next;
	}
	//第三个节点是空,就剩下两个节点了
	mid.next=left;
	//原来的头结点指针并没有改变,所以要特殊处理一下,让他作为新链表的尾巴,指向空。
	head.next=null;
	
	head=mid;
	return head;
}

2. 头插的方法(推荐)

三指针的方法位面有点繁琐,这时候将原来链表的每一个节点都头插到一个新的链表当中,就显得很简单。

代码如下;

ListNode ReverseList(ListNode head)
{
	if(head==NULL||head.next==NULL)
	{
		return head;
	}
	ListNode new_head=NULL;
	while(head)
	{
		//先将原来链表头结点拿下来
		ListNode p=head;
		//原来的链表指针后移
		head=head.next;
		//插入到一个新链表的头部
		p.next=new_head;
		new_head=p;
	}
	return new_head;
}

二. 俩个单调递增的单链表合并为一个不递减的单链表

1. 正常做法

(1) 两个链表,挑选出值较小的节点。
(2) 将这个节点原来的指针进行后移,指向下一个节点
(3)将节点插入到新的节点当中。
特判:当是新节点的首次进行插入时?
(4)当一个链表到结尾之后,只需要将另一个链表接到新链表的后面即可。那么,如何判断是哪一个链表先结束的呢?

代码以及相应的注释如下,便于大家理解:

ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
	//如果其中一个是空,就直接返回另外一个就行
	if(pHead1==NULL) return pHead2;
	if(pHead2==NULL) return pHead1;
	
	//先声明新链表的两个节点的头尾指针
	ListNode* head=NULL;//便于返回
	ListNode* end=NULL;//便于尾插
	//当两个链表都不是空时
	while(pHead1 && pHead2)
	{
		//1.调出要删除的节点,就是较小值
		ListNode* p=pHead1->val > pHead2->val ? pHead2 : pHead1;
		//2. 删除目标节点
		if(p==pHead1)
			pHead1=pHead1->next;
		else
			pHead2=pHead2->next;
		//3. 将节点插入到新的链表当中
		
		if(head==NULL)//如果是首次进行插入
		{
			head=p;
			end=p;
		}
		else
		{
			//如果不是首次插入,就直接进行尾插就行
			end->next=p;
			end=end->next;
		}
	}
	//跳出循环,就说明其中一个是空或者两个都是空
	if(pHead1==NULl)
		end->next=pHead2;
	else
		end->next=pHead1;
	
	return head;
}

2.递归的方式实现

ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
	if(pHead1==NULL) return pHead2;
	if(pHead2==NULL) return pHead1;
	
	ListNode* head=nullptr;
	//寻找合适节点,也就是较小值,在本次调用时,连接在新链表的后面
	if(pHead1->val > pHead2->val)
	{
		head=pHead2;
		pHead2=pHead2.next;
	}
	else
	{
		head=pHead1;
		pHead1=pHead1.next;
	}
	//递归实现下一个节点的连接
	head->next = Merge(pHead1 , pHead2);
	return head;
}

三.二叉树 判断b是否是a的子树(空树不是任意一棵树的子树)

首先,我们需要知道的就是,一棵二叉树本身就是递归实现的,那么自然而然我们在判断是否是子树时,就需要从根节点开始,递归调用函数判断他的左子树,递归调用函数判断右子树是否是子树。

代码以及注释如下:

bool IsSame(TreeNode* root1,TreeNode* root2)//比较左右子树是否相等
{
	if(root2==NULL)
	{
		return true;
	}
	if(root1==NULL)
	{
		return false;
	}
	if(root1->val!=root2->val)
		return false;
	//递归判断子树是否相等
	return IsSame(root1->left,root2->left)&&IsSame(root1->right,root2->val);
}

bool HasSubtree(TreeNode* root1,TreeNode* root2)
{
	if(root1==NULL || root2==NULL) return false;
	//设置一个flag
	bool result=false;
	//先找起始位置
	if(root1->val== root2->val)
	{
		result=IsSame(root1,root2);
	}
	//过来有两种情况,要么是两个起始位置的值就不相等,要么是子树并不匹配
	//在满足相等条件的时候再进行下一步的继续判断
	if(result!=true)
	{
		result=HasSubtree(root1->left,root2);
	}
	if(result!=true)
	{
		result=HasSubtree(root1->right,root2);
	}
}

注:对于递归调用,大家可能存在不太理解的问题,可以自己画函数递归图,进行进一步的理解。如果还不是很理解,可以留言,本人必将尽力解答。

四. 小激励来了

在我们的日常生活和学习中,总会对于某件事情有“三分钟热度“,在坚持的某一个瞬间就会对于现在所做的事情产生怀疑,是否有坚持的必要。其实,
我们就是想的太多,而做的事情却很少。
当自己有了明确的目标而全身心地投入其中时,脑子中就不会有那么多乱七八糟的想法了。所以,
继续前进吧!hxd.

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