力扣 844. 比较含退格的字符串---二法(栈与双指针)

844. 比较含退格的字符串

给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:S = “ab#c”, T = “ad#c”
输出:true
解释:S 和 T 都会变成 “ac”。
示例 2:

输入:S = “ab##”, T = “c#d#”
输出:true
解释:S 和 T 都会变成 “”。
示例 3:

输入:S = “a##c”, T = “#a#c”
输出:true
解释:S 和 T 都会变成 “c”。
示例 4:

输入:S = “a#c”, T = “b”
输出:false
解释:S 会变成 “c”,但 T 仍然是 “b”。

提示:
1 <= S.length <= 200
1 <= T.length <= 200
S 和 T 只含有小写字母以及字符 '#'。
进阶:
你可以用 O(N) 的时间复杂度和 O(1) 的空间复杂度解决该问题吗?
 

题解:

方法一:栈+重新构建字符串

由于退格键的存在,我们只需要用上这些退格键来重新构建一个真正的字符串即可。最后比较一下重组后的二者是否相同即可。

代码:

char*bj(char*str)//此为“重组”函数
{
    
    
    int n = strlen(str);
    char*temp=(char*)malloc((n+1)*sizeof(char));//用来临时储存“重组”后的字符串,先设置内存大点
    int len = 0;//此为代表“重组”后的字符串数组的下标,开始为0
    for(int i=0;i<n;i++)//for循环来填充
    {
    
    
        if(str[i]!='#')//如果不是退格键,则直接赋给他即可
        {
    
    
            temp[len]=str[i];
            len++;//下标先指向下一个
        }
        else if(len>0)//是退格键的情况,但前提须是“重组”后的字符串数组的下标须大于0
        	//因为进入此条件体内下面我们要对len--,所以len在进来时就必须先是>0的,不然会越界
        {
    
    
            len--;//因为是退格键,所以即相当于“删掉”了前一个,所以要对前一个进行重新赋值,所以下标往前一个
        }
    }
    temp[len]='\0';//因为开始不知道应该申请多大内存,而字符串数组以‘\0’为结尾
    			//所以先申请一个最大的,最后再“去掉”多余的即可
    return temp;
}
bool backspaceCompare(char * S, char * T){
    
    
    return strcmp(bj(S),bj(T))==0;//代入函数验证即可
}

此法效率较低,但逻辑较为简单。

方法二:逻辑性处理—双指针查找

此法效率很高,但是逻辑上比较复杂。

首先要明白的是使用双指针查找的话,起始位置应该是从头开始查找还是从尾部开始查找
通过题目我们可以知道,一个字符只会对其后面出现的退格键才会受到作用,对其前面出现的退格键不会受到影响。也就是说如果我们从头开始查找的话,若是遇到#时需要对其上一个进行操作。而如果我们从尾部开始查找,一旦碰到#我们就先存起来,当没有碰到#时,我们就可以由存起来的#数量来立刻判断此时的字符是不是会被删掉。对于从头查找我们发现要完成这一步骤较为复杂。

附上一张大神的题解的图片以便更好理解接下来的过程:
在这里插入图片描述

在确定从尾部开始查找后,我们可以先对S数组进行查找,若是此时对应的元素是#,则存储一次#,将指针向前移一次;若不是#,看一下存储的#有没有抵消完,若是没有抵消完,则抵消一次,指针再向前移一次;若是抵消完了,说明此时的字符是相当于经过退格键处理后的真实的应该存在的字符,所以此时可以把他拿出来与T数组同样操作拿出来的字符进行比较,看是否相等。

即上述操作我们的目的是从S数组,T数组中拿出来一个经过退格键处理后的真正存在的字符进行比较

下面是一些代码中的细节问题:

----注:代码中如果i,j均为负值的话不用比较S[i]与T[j]是否相等了,为什么?
因为i,j都为负值时代表他们没有选出来经过退格键操作后真实存在的字符,既然是都没选出来,那么也没事~
当然也可能是i,j都遍历完全了自己的数组,那么也没事,遍历完全了自然不用再比较了~

注:开头的while循环的条件为什么是“i>=0||j>=0”?
因为可能一个指针由于所在数组小,搜索的快,所以很快就搜索完了,所以此时他对应的i或j就是负值了,但是另一个比较慢,还在搜索。而这种情况并不一定是代表“真”,也不一定代表“假”,所以需要再进行一轮验证慢的那个是不是搜索不到内容了,如果是这种情况,则为 “真” ;如果不是这种情况,即在一个已经搜索完的情况下另一个还能搜索到内容,则一定二者不同,所以为 “假” 。

!!!!并且要明确------i,j如果不是负值的情况下即代表他们是搜索到了内容,即此时对应的S[i],T[j]不是#.(这是由while循环的条件得出的)

代码:

bool backspaceCompare(char * S, char * T){
    
    
    int i=strlen(S)-1;//S的指针
    int j=strlen(T)-1;//T的指针
    int nums = 0;//S的计数器,存储S的#个数
    int numt = 0;//T的计数器,存储T的#个数
    while(i>=0||j>=0)//进入搜索查找循环
    {
    
    
        while(i>=0)//先查找出S的经过退格处理的真正存在的字符,因为i为S的查找指针,
        	//每一个都要查找,所以i=0也要查找,所以循环为i>=0就要进入循环
        {
    
    
            if(S[i]=='#')
            {
    
    
                nums++;
                i--;
                continue;
            }
            if(nums!=0)
            {
    
    
                i--;
                nums--;
                continue;
            }
            if(nums==0)
            {
    
    
                break;
            }
        }
        while(j>=0)//再找出T的经过退格处理的真正存在的字符,同理j>=0
        {
    
    
            if(T[j]=='#')
            {
    
    
                numt++;
                j--;
                continue;
            }
            if(numt!=0)
            {
    
    
                j--;
                numt--;
                continue;
            }
            if(numt==0)
            {
    
    
                break;
            }
        }
        if(i>=0&&j>=0)//首先满足i,j不越界,即都搜索到了内容时
        {
    
    
            if(S[i]!=T[j])//进行比较
                return 0;
        }
        else//else的条件其实就是当不满足前面的if条件时,所以即i,j有越界的,即有没有搜索到内容的
        {
    
    
            if(i >= 0 || j >= 0)//在else的情况下,所以必定有至少一个没有搜索到内容
            {
    
    //若是都没搜索到,则没啥事,若是一个搜索到了,一个没搜索到,则一定为“假”了
                return false;//因为搜索时本来就把退格键使用了,所以此时显然S与T不相同了
            }
        }
        i--;//移动指针
        j--;
    }
    return 1;
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/112291205