剑指offer--ac代码

1,栈的压入,弹出序列

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if(pushV.size()==0 || popV.size()==0 || pushV.size() != popV.size())
            return false;
        int k=0;
        stack<int> s;
        for(int i=0;i<pushV.size();i++)//遍历一次入栈数组
            while(!s.empty()&&s.top()==popV[k])//入栈顺序错误的话,不再进入循环
                                               //这样最后栈肯定不为空
                                               //条件一是因为,入一个出一个会导致栈为空
            {
                s.pop();
                k++;
            }
        }
           return s.empty();//返回的是bool
        
    }
};

2,从上往下打印二叉树

class Solution {
public:
	vector<int> PrintFromTopToBottom(TreeNode* root) {
		vector<int> v;
		if (root == NULL)
		{
			return v;
		}
		TreeNode* FrontNode;
		queue<TreeNode*> q;
		q.push(root);
		while (!q.empty())  
		{
			FrontNode = q.front();  //出队列一个元素就把这个元素的左右节点都入队列
			q.pop();   
			if (FrontNode == NULL)   //当然NULL也会被入,此时不用入左右节点
				continue;
			v.push_back(FrontNode->val);
			q.push(FrontNode->left);
			q.push(FrontNode->right);
		}
		return v;
	}
};

3,二叉搜索树的后序遍历序列

解题思路:

ST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),

如果去掉最后一个元素的序列为T,那么T满足:

T可以分成两段,前一段(左子树)小于x,

后一段(右子树)大于x,

且这两段(子树)都是合法的后序序列。完美的递归定义 : ) 。

class Solution {
public:
	bool VerifySquenceOfBST(vector<int> sequence) {
		if (sequence.size() == 0)
			return false;
		return judge(sequence,0,sequence.size()-1);
	}
	bool judge(vector<int>& a, int left, int right)
	{
		if (left >= right)                     //关于递归出口,当数组有两个元素时,可以发现
                                               //left会小于right,left会大于right
			return true;
		int i = right-1;
		while (i >= left && a[i] > a[right])i--;//找出来左子树的最后一个值
		for (int j = i; j >= left; j--)         //判断左子树内所有数是否有大于根的,
		{
			if (a[j] > a[right])                //有的话就错了
				return false;
		}
		return judge(a, left, i) && judge(a, i + 1, right - 1);//进行细分
	}
};


4,二叉树中和为某一值的所有路径

class Solution {
public:
	vector<vector<int>> v;
	vector<int> tmp;
	vector<vector<int> > FindPath(TreeNode* root, int expectNumber) {
		if (root == NULL)
			return v;
		_FindPath(root, expectNumber);
		return v;
	}
	void _FindPath(TreeNode* root, int sum)
	{
		tmp.push_back(root->val);
		if ( (sum -= root->val)==0  && root->left==NULL && root->right==NULL)
			//(sum -= root->val)==0  每次进来先减掉当前值,
		{
			v.push_back(tmp);//必须要满足三个条件才能入二维数组
			
		
		}
		if (root->left != NULL)//左为空了,就不用管了
			_FindPath(root->left, sum);
		if (root->right != NULL)
			_FindPath(root->right, sum);//递归返回都这里时,sum并没有改变,带有记忆
		tmp.pop_back();//关键点,处理完一个点,就要弹出这个点,不能影响其他路径
	} 
};

5,二叉搜索树与双向链表

//大体框架是二叉树的中序遍历
//只不过是将原本节点值入vector的部分替换成了左右指针的改变
//精华所在是在处理一个节点时,只能肯定这个节点的pPer指向,而不能确定next指向。
//所以在处理一个节点时,处理这个节点的pPer指向和前一个节点的next指向。
//也不用考虑链表的第一个节点的pPer和最后一个节点的next指向怎样为空,因为本来就是空的。
class Solution {
public:
	TreeNode* Convert(TreeNode* pRootOfTree)
	{
		if (pRootOfTree == NULL)return pRootOfTree;
		stack<TreeNode*>s;
		TreeNode* pCur = pRootOfTree;
		TreeNode* pPer = NULL;
		int flag = 1;
		TreeNode* Ret;
		while (pCur !=NULL || !s.empty())//这里需要两个条件,与层序遍历不同
		{
			while (pCur != NULL)
			{
				s.push(pCur);
				pCur = pCur->left;
			}
			if (flag == 1)//用来找到链表的头结点
			{
				Ret = s.top();
				flag = 0;
			}

			pCur = s.top();
			s.pop();
			pCur->left = pPer;//处理当前节点的pPer指向
			if (pPer != NULL)//第一次时,pPer是空的,所以就没有next指向
				pPer->right = pCur;
			pPer = pCur;//千万要记得将pPer进行更新
			pCur = pCur->right;//左根处理完了,就要去右节点看看。
		}
		return Ret;
	}
};

6,二分查找

int BinarySearch(int * array, int n, int x)
{
	assert(array);
	int left = 0;
	int right = n;//左闭右开[left,right)
	while (left < right)//那么就不存在left==right的情况
	{
		int mid =left+(right-left)/2;//防止整形溢出
		if (array[mid] == x)
			return array[mid];
		else if (array[mid]>x)
		{
			right = mid;//mid位置已经检查过了,所以就可以作为取不到的右端点
		}
		else
		{
			left = mid + 1;
		}
	}

7,两个链表的第一个公共结点

主要的思路是:

                     两个指针分别从各自头结点出发,以相同的步长,

                     如果链表的长度相同,那么刚好在第一个相同节点的位置相遇,并返回

                     如果链表的长度不相等,那么较短的链表肯定先走到NULL,让短链表从长链表开头的位置接着走。

                     较长的链表肯定后走到NULL,让长链表从短链表开头的位置接着走,

                     因为两个指针在第二次到达第一个相同节点之前所走的路径长度是相同的,

扫描二维码关注公众号,回复: 3489219 查看本文章

                     所以肯定会在第一个相同节点处相遇

                     再分析一下为什么路径是相同的:总体来说每个指针都将长短链表都走了一遍 ,所以长度是相等的

                     因为公共部分链表长度是相等的,所以除去公共部分的链表也是相等的。

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(pHead1==NULL || pHead2==NULL)
        {
            return NULL;
        }
        ListNode* p1=pHead1;
        ListNode* p2=pHead2;
        while(p1!=p2)
        {
             p1= (p1 == NULL)?pHead2:p1->next;
             p2= (p2 == NULL)?pHead1:p2->next;
        }
        return p1;
    }
};

8,链表中环的入口结点

关于慢指针肯定走不完一圈的说法,没有证明,自己试了几次,证实的

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead==NULL)
            return NULL;
        //判断有没有环
        ListNode* pFast=pHead;
        ListNode* pSlow=pHead;
        while(pFast!=NULL && pFast->next!=NULL)//这里必须要用&&,两种情况都不能成立
        {
            pFast=pFast->next->next;
            pSlow=pSlow->next;
            if(pFast==pSlow)
                break;
        }
        //判断是那种情况出的循环
        if(pFast==NULL || pFast->next==NULL)//这里的判断不能是(pFast!=pSlow)
                                            //当链表是 1->NULL时,没有环,也会返回1
                                            //并且必须用 || 任意一种情况成立就返回
            return NULL;
        //寻找入口点
        pFast=pHead;
        while(pFast!= pSlow)
        {
            pFast=pFast->next;
            pSlow=pSlow->next;
        }
        return pSlow;
    }
};

 9,删除链表中重复的结点

主要思路就是:三指针法,

class Solution {
public:
	ListNode* deleteDuplication(ListNode* pHead)
	{
		if (pHead == NULL || pHead->next == NULL)//没有或者只有一个就不用删了
			return pHead;
		ListNode* newNode = new ListNode(1);//创建一个节点来防止头结点被删除,最好用栈上空间
		ListNode* pPer = newNode;
		ListNode* pCur = pHead;
		ListNode* pNext = pHead->next;
		ListNode* pDel = NULL;
		while (pNext!=NULL)//不用管第一次,又因为pCur都是pNext赋予的,所以就不用检查了
		{
			if (pCur->val == pNext->val)
			{
				while ( pNext != NULL && pCur->val == pNext->val)//找到相等的,还要继续往后找
				{
					pDel = pCur;
					pCur = pNext;
					pNext = pNext->next;
					free(pDel);
					pDel = NULL;
				}
				free(pCur);//出了循环是因为两个节点的值不相等,但是第一个节点的还是应该删掉
				pCur = NULL;
				pPer->next = pNext;
				pCur = pNext;    
				if (pNext !=NULL)//pNext已经是NULL了,就不能再往后走了
					pNext = pNext->next;
			}
			else//如果两个节点的值是不相等的那么直接往后走就行了
			{
				pPer = pCur;
				pCur = pNext;
				pNext = pNext->next;
			}
		}
		return newNode->next;//注意最后的返回值是自己创建的节点的下一个
	}
};

10,链表中倒数第k个结点

class Solution {
public:
	ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
		if (pListHead == NULL)
			return NULL;
		ListNode* pCur1 = pListHead;
		ListNode* pCur2 = pListHead;
		while (k!=0)//防止链表的节点数小于k
		{
            if (pCur1 == NULL)//还没走K次就遇到NULL了
				return NULL;
			pCur1 = pCur1->next;
			k--;
		}
		while (pCur1!=NULL)//
		{
			pCur1 = pCur1->next;
			pCur2 = pCur2->next;
		}
		return pCur2;
	}
};

11,反转链表

方法一:三指针法

class Solution {
public:
	ListNode* ReverseList(ListNode* pHead) {
		if (pHead==NULL || pHead->next==NULL )
			return pHead;
		ListNode* cur1 = NULL;
		ListNode* cur2 = pHead;
		ListNode* cur3 = NULL;

		while (cur2!=NULL)//最后一个节点处理完后,cur2才被赋为NULL
		{
			cur3 = cur2->next;
			cur2->next = cur1;

			cur1 = cur2;
			cur2 = cur3;
		}
		return cur1;
	}
};

方法二:递归法

//我也不知道为啥,你自己做一遍就知道了,总之特别吊
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead==NULL || pHead->next==NULL)
           return pHead;
        ListNode* pCur=  ReverseList(pHead->next);
        pHead->next->next=pHead;
        pHead->next=NULL;
        return pCur;
    }
};

12,二叉树的下一个节点


给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

1.二叉树为空,则返回空;

2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;

3.节点右根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==NULL)
            return NULL;
        TreeLinkNode* pCur=pNode;
        if(pCur->right!=NULL)
        {
            pCur=pCur->right;
            while(pCur->left!=NULL)
            {
                pCur=pCur->left;
            }
            return pCur;
        }
        //没有右节点,如果当前节点是其父节点的左子树,就返回父节点,不是左节点就向上遍历
        
        while(pCur->next!=NULL)//满足的情况是pCur==根节点
        {
            if(pCur->next->left==pCur)//是否是其父节点的左子树
                return pCur->next;
            pCur=pCur->next;
        }
        return NULL;//说明pCur是该二叉树的最后一个节点,那他的下一个节点是NULL
    }
};

 

猜你喜欢

转载自blog.csdn.net/wm12345645/article/details/82718018