3/9 OJ 字符串,链表,二叉树相关

学会处理临界条件

《一》,字符串

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字 符串为We%20Are%20Happy。

法一,双指针原地修改

class Solution {
public:
    void replaceSpace(char *str,int length) {
        int i=0;
        int count=0;
        while(str[i]!='\0')
        {
            if(str[i]==' ')
            count++;
            i++;
        }
        int newlength=length+2*count;
        char* oldend=str+length;
        char* newend=str+newlength;
        while(oldend>=str)
        {
            
            if(*oldend==' ')
            {
                *(newend--)='0';//这里要注意--
                *(newend--)='2';
                *(newend)='%';
            }
            else
            *newend=*oldend;
            newend--;//两种情况放一起减减的部分
            oldend--;
        }
    }
};

法二,利用C++stl的接口

class Solution {
public:
    string replaceSpace(string s) {
        int i=0;
        while(s[i]!='\0')
        {
            if(s[i]==' ')
            {
                s[i]='0';
                s.insert(i,"%2");
               
            }
             i++;
        }
        return s;
    }
};

法三:以空间换时间

class Solution {
public:
    void replaceSpace(char *str,int length) {
        string s;
        for(int i=0;i<length;i++)
        {
            if(str[i]!=' ')
            s+=str[i];
            else
            s+="%20";
        }

        strcpy(str,s.c_str());
    }
};

《二》.逆置链表

  1. 遍历链表,入栈。再出栈到数组

  1. 遍历链表,尾插到数组,再逆置

//前两种比较简单,我们可以考虑第三种

  1. 递归法

思路:你想输出一个节点的前提是后面的节点曾经以及进入了数组,由此让子问题规模缩小

void printreversehelper(ListNode* head,vector<int> &v)
 {
     if(nullptr==head)
        return ;
     printreversehelper(head->next,v);
     v.push_back(head->val);   
 }
vector<int> printreverse(ListNode* head)
{
    vector<int> v;
    printreversehelper(head,v);
    return v;
}

递归法提供另一种思想

《三》.二叉树重建

描述

给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

解题思路:根据root节点,将中序vector划分成vin_left,vin_right 两部分中序子序列

根据中序子序列长度,将前序vector 划分成pre_left,pre_right对应的前序子序列

root->left 递归生成

root->right 递归生成

1,2,4,7,3,5,6,8

4,7,2,1,5,3,8,6

1,2,4,7,3,5,6,8

4,7,2,1,5,3,8,6

按照前序遍历的方式,先构建左子树,再构建右子树

class Solution {
public:
TreeNode* reConstructBinaryTreeCore(vector<int> pre,int preStart,int preEnd,vector<int>
vin, int vinStart, int vinEnd) {

if(preStart > preEnd || vinStart > vinEnd){
return nullptr;
}//当没有元素时,区间会不合法

TreeNode *root = new TreeNode(pre[preStart]);//前序开始的节点是我本次要构建的子树的根

for(auto i = vinStart; i <= vinEnd; i++){//在中序序列中,找根节点,可以将数组划分为两部分
if(pre[preStart] == vin[i]){
//前序的第一个节点,是root,能将中序划分为两部分
//一棵树,无论前,中,后怎么遍历,元素的个数是不变的
//在实际遍历的时候,前,中,后序遍历,各种遍历方式左右子树的节点都是在一起的
//所以这里重点是要想清楚下标问题
//根据中序,我们能确认左子树的节点个数是:i - vinStart (没有从0开始哦)
//所以,需要从preStart+1,连续i - vinStart个元素,就是左子树的前序序列
root->left = reConstructBinaryTreeCore(pre,preStart+1, i-vinStart+preStart,
vin, vinStart, i-1);
root->right = reConstructBinaryTreeCore(pre, i-vinStart+preStart+1,
preEnd,vin, i+1,vinEnd);
break;
}
}
return root;
}

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if (pre.empty() || vin.empty()){
return nullptr;
}
return reConstructBinaryTreeCore(pre, 0, pre.size()-1, vin, 0, vin.size()-1);
//
}
};

本题小结:

本题通过前序的第一个,在中序中找到根,根可以把中序分成左右子树,中序的左右子树长度可以划分前序的区间,然后前序的第二个可以继续在中序的左边继续找到下一个根,化为子问题,继续分左右子树

如何划分区间:

root->left 参数: pre数组 , prestart+1第二个根,通过prestart找到vin中的根i可以将vin分成左右区间。i-vinstart时左子树节点个数,根据这个划分前序区间右边为prestart+i-vinstart,然后vin被划分为vinstart和i-1

同理可以得到root->right的参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值