算法与数据结构面试题

1:将二叉查找树转化为排序的双向链表

       要求不创建任何新的己节点,仅仅是改变指针的方向

          10
           / \
         6 14
         / \ / \
      4 8 12 16
    
 转换成双向链表
4=6=8=10=12=14=16

下面的是二叉树的节点

   struct BSTreeNode
{
  int m_nValue; // value of node
  BSTreeNode *m_pLeft; // left child of node
  BSTreeNode *m_pRight; // right child of node
};

其实这个问题可以这样子想,我们可以以上面的那个例子为例,转换之后的双向链表为4,6,8,10,12,14,16,我们可以发现在10左边的元素都是原来二叉树中对应的左子树上的节点,

而10右边的元素都是原二叉树中对应的右子树上的节点,而上述节点的顺序正好是中序遍历二叉树时我们所需要走过的节点的顺序,同时在数据结构的课程上我们学过一种叫做线索二叉树的东西,这种二叉树说白了就是将左右子树为空的节点重新利用起来,指向其在某种遍历中的前驱节点或者是后继节点,那么这样的话,对于这个问题,我们完全可以采用中序遍历时建立线索二叉树的过程,来完成双向链表的建立,但是这里与建立中序 遍历线索二叉树不同的是,这里完全破坏了树的结构,因为在中序遍历中当节点的左子节点存在时我们是不做任何改变的,但是对于双向链表,我们会将其变成左子树的最右子节点的指针

struct node
{
   int  value;
   node* p_Left;
   node* p_Right;
};
typedef  node* pnode;
pnode Covert(pnode  root)
{
     pnode prv=NULL;
     CovertNode(root,&prv);
     pnode Head=prv;
     while(Head->P_Left!=NULL)
        Head=Head->P_Left;
     return  Head;
}
void   CovertNode(pnode& root,pnode* pre)
{
    if(root!=NULL)
    {
       CovertNode(root->P_Left,pre);
       if(*pre!=NULL)
       {
           root->P-Left=*pre;
           *pre->P_Right=root;
        }
       *pre=root;
       CovertNode(root->P_Right,pre);
    }
}

2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。

2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。
这个问题是 剑指上的原题,在看剑指上的答案之前,我是这样想的,确实需要一个辅助栈这是肯定没问题的,关键在于往辅助栈中压入什么元素?我一开始想的是当压入的元素比当前辅助栈的栈顶元素小的时候我们什么也不做,只是把这个元素压入原来的栈就行了,只有在当辅助栈的栈顶元素小于要压入的元素的时候才真的将其也压入辅助栈,这样的话,就会出现辅助栈的长度可能小于真正的栈的长度,这个时候可能出现问题阿,因为可能在有限步之后由于栈顶元素的弹出使得辅助栈为空,而原本的栈却不为空,这样子肯定是错误的,所以我们需要保持两个栈的长度必须相同,那么当当前元素大于辅助栈的栈顶元素的时候我们只需要把辅助栈的栈顶元素再压入一次就行了,这样的话两个栈的长度相同,同时当 原数据栈的栈顶元素弹出的时候辅助栈的栈顶元素也弹出,两者不一定相等,但这个时候新的辅助栈的栈顶元素一定是 原数据栈中的当前最小元素

void  push(int value)
{
    m_data.push(value);
    if(m_mindata.size()==0||value<=m_minsize.top())
         m_mindata.push(value);
    else
         m_mindata.push(m_minsize.top());
}
void  pop()
{
    assert(m_data.size()>0);
    m_data.pop();
    m_min.pop();
}
int   min()
{
   assert(m_data.size()>0);
   return  m_mindata().top();
}

3.求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18

这个问题我们可以利用动态规划的思想,假设f(i)保存的是以i为下标结尾的子数组的最大和,那么我们需要求的是max[f(i)],,而f(i)之间存在着下面的递推关系

当f(i-1)<0的时候,f(i)=data[i],否则会越加越小,当f(i-1)>=0的时候,f(i)=data(i)+f(i-1),这个时候最起码可以保证f(i)比data(i)大。

int   FincThemaxsum(int *a ,int length)
{
      if(a==NULL||lengthM=0)
         exit(1);
      int  currentmaxsum=-1;
      int   maxsum=-INT_MAX;
      for(int i=0;i<length;i++)
       {
          if(currentmaxsum<=0)
             currentmaxsum=a[i];
          else
             currentmaxsum+=a[i];
          if(currentmaxsum>maxsum)
             maxsum=currentmaxsum;
       }
       return  maxsum;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值