学会处理临界条件
《一》,字符串
请实现一个函数,将一个字符串中的每个空格替换成“%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());
}
};
《二》.逆置链表
遍历链表,入栈。再出栈到数组
遍历链表,尾插到数组,再逆置
//前两种比较简单,我们可以考虑第三种
递归法
思路:你想输出一个节点的前提是后面的节点曾经以及进入了数组,由此让子问题规模缩小
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的参数