[剑指offer] 第二层

栈的压入与弹栈序列

题目描述:
[剑指offer] 第二层_第1张图片


回顾栈的基本结构:

栈的结构是先进后出,后进先出


入栈序列:[1,2,3,4,5] 出栈序列[4,5,3,2,1],否属于同一个栈出入序列?
提示 :入栈中可能有元素可能会栈
[剑指offer] 第二层_第2张图片


思路:

  • 用一个栈模拟实现入栈,且在入栈时和出栈序列比较是否该元素提前出栈

代码:

    bool IsPopOrder(vector<int> pushV,vector<int> popV)
    {
        if(pushV.size()==0&&popV.size()==0)//特殊情况
        {
            return false;
        }
        int push_index=0,pop_index=0;
        while(push_index<pushV.size())//当入栈序列没有还有元素那么就该出结果了,因为模拟栈和出栈序列如果对不上就说明为假
        {
            st.push(pushV[push_index++]);
            while(!st.empty()&&st.top()==popV[pop_index])//注意,一直相等出栈可能stack空导致越界访问
            {
                st.pop();
                pop_index++;
            }
        }
        return st.empty();//空代表完全符合
    }
    
private:
    stack<int>st;
};


链表的合并

题目描述:

[剑指offer] 第二层_第3张图片


思路:

  • 归并比较大小插入法

新开辟一个链表当作容器,在依次比较较小的值插入链表中

代码:

  ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        
        
         //特殊情况
        if(pHead1==nullptr)
        {
            return pHead2;
        }
        if(pHead2==nullptr)
        {
            return pHead1;
        }

        //开辟一个新的链表当作容器,带头链表(哨兵位置)
        ListNode* ret=new ListNode(0);
        ListNode* NewHead=ret;
        
        while(pHead1&&pHead2)//比较大小需要俩个链表有值才可以
        {
        
            if(pHead1->val<pHead2->val)//链表1小于链表2
               {
                   ret->next=pHead1;
                   pHead1=pHead1->next;
                   ret=ret->next;
               }
            else//链表2小于链表1
            {
                   ret->next=pHead2;
                   pHead2=pHead2->next;
                   ret=ret->next;
            }            
        }
 
        //特殊情况      
        if(pHead1)//当链表2全部节点插入容器时链表1还有元素
        {
            ret->next=pHead1;
        }
        if(pHead2)//反之
        {
            ret->next=pHead2;
       }
       
        return NewHead->next;//返回链表
    }

哨兵位,带头链表的补充说明与解释

这个一个节点不算这个链表中得元素,他的作用就是方便删一个节点的元素,你就可以看作老鹰捉小鸡这个游戏中的老母鸡



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

题目描述:
[剑指offer] 第二层_第4张图片


知识补给:

二叉搜索树
左子树永远大于根节点,右子树永远都大于根节点
如图所示:
[剑指offer] 第二层_第5张图片


后续遍历:
左子树 右子树 根 上述图中的二叉搜索树的后续遍历为:
1->3->2->6->9->7->5


思路:

在知识补给中可以看到二叉搜索树的特点就是左子树比根节点大右子树比根节点大,那么我们只需要找到根在去判断左子树是不是比根节点小,右子树是不是比根节点大

那么现在就有一个问题就是如何找根呢?
[剑指offer] 第二层_第6张图片

依旧是知识补给中,后续遍历是先遍历左子树,在是右子树,然后是根,那么后续遍历最后一个节点就是这棵树的根(如果疑惑前看知识补给或这篇二叉树基础)



代码实现:

主逻辑

    bool VerifySquenceOfBST(vector<int> sequence) 
    {
        
        if(sequence.empty())//特殊处理,小心有诈
        {
            return false;
        }        
        
         return VerifySquenceOfBSTHelp(sequence,0,sequence.size()-1);//递归开始判断
    }

判断部分

    bool VerifySquenceOfBSTHelp(vector<int>& sq,int start,int end)
    {
        if(start>=end)//当你只有一个与元素的时候就说明了没有元素需要在比判断了
        {
            return true;
        }
        
        int root=sq[end];//序列最后一个元素为根
        
        //划分区间
        int i; 
        for(i =start; i<end;i++)//end为根所以少比一次
        {
            if(sq[i]>root)//如果比根大就说明了i这个位置已经是右子树了
            {
                break;
            }
        }
        
        for(int j =i;j<end;j++)//右子树
        {
            if(sq[j]<root)//如果在右子树区间中有一个节点小于根那么就不是一个二叉搜索树树
            {
                return false;   
            }
        }
        
        
        //递归
        return  VerifySquenceOfBSTHelp(sq, , )&&VerifySquenceOfBSTHelp(sq, , )    
    }

区间分析

第一次遍历:
[剑指offer] 第二层_第7张图片

左子树 start

从第一次遍历中可以看出左子树的start还是这个序列的起始位置也就是当前节点的start

左子树end

从第一次遍历中可以发现左子树的end就是在i的前一个位置,那么左子树end 就是 i-1

右子树start

从第一次遍历中可以发现右子树的start 其实就是 i 当下的位置 所以 左子树的start 为 i

右子树end

第一次遍历之后那么当前的根节点对我们来说已经没有用了,所以右子树的end就是当前end-1

return  VerifySquenceOfBSTHelp(sq,start ,i-1 )&&VerifySquenceOfBSTHelp(sq,i ,end-1 );


题目链接

第一题
第二题
第三题



唠唠家常

最近天气有点冷呀,大家注意保暖,今天刚好是2022年1月1日,祝大家新年快乐,新年新气象,改掉上能的坏习惯,保留上年的好习惯

[剑指offer] 第二层_第8张图片

你可能感兴趣的:(剑指offer,链表,数据结构)