zoukankan      html  css  js  c++  java
  • 面试题4:替换空格之发散思维

      题目:请实现一个函数,吧字符串的每个空格替换成“%20”,例如输入“we are happy”,则输入“we%20are%20happy ”。

      书中给出的代码是用C++实现的,时间复杂度是O(n),我的想法是用C#实现不指定字符串替换,一个字符串valueChars(char数组类型的),把字符串中的oldChars字符串,替换为newChars。注意valueChars,oldChars,newChars 三个的数据类型都是char [] 数组类型的

      开始写算法之前,想的算法的要求为:1,时间复杂度O(n) 2,常量的空间复杂度。实现过程中并不是这样的。

      首先强调一点在C#中和C++中char[]是有一些区别的.

      在C#中代码如下

                char[] str = new char[10];
                for (int i = 0; i < 10; i++) 
                {
                    if (5 <= i&&i <= 6)
                        continue;
                    str[i] = (char)(i+'0');
                }
                Console.WriteLine(str);

      请注意当str赋完值只收str的值,见下面图片

      

    对于C#来说char[] 中的‘\0’并不是相当于C++中的字符串结束符,它可能不起作用,因此对于这点来说需要注意。

      为了使算法具有普适性,valueChars的实际长度(从第一个字符开始,遇到第一个'\0'字符时的长度)和它的占用的内存长度不同,其他的两个字符串也是这样。

      书中对于空格' '替换'%20',是从后面开始替换的,但是对于oldChars和newChars怎么办?最开始时我认为全部是从后开始替换就可以,但是当newChars的实际长度newActualLength(变量名nAlen)小于oldChars的实际长度(变量名oALen)时从后向前替换的问题时,已近替换好的字符串就有了一个需要向前移动的过程(自己脑补,不会画图)。这样显然不符合时间复杂度O(N)的要求,这个时候就需要向前开始移

      有缺陷的发散思维1:为了达到O(N)的时间复杂度(实际上不可能),当 nAlen<=oALen时,替换后字符串的实际长度缩小或者不变的,这个时候就需要向前开始从前面开始替换。当nAlen>oALen时,我们应该从字符串后面开始替换字符串。

      这样对应的算法是:

              1.给定的oldChars和newChars 求出oALen和nAlen。

              2.比较oALen和nAlen

              3.nAlen<=oALen 调用ReplaceFromHead函数,跳转5否则4

              4.调用ReplaceFromEnd函数

              5.结束

      按照这个思路,我就遇到了个各种各样的问题

      问题1.如何认定字符串匹配的问题?

      valueChars='aaabbbccc',oldChars='aa',newChars='d';出现了问题可以认为'aaa...' 和'aaa...'红色的部分是我要找的字符串oldChars,但是这两种情况替换下来结果完全不一样,因此采用最先匹配原则,即认为'aaa...'是应该的替换的字符串。

      答:采用最先匹配原则

      好了现在可以写从前向后匹配算法了,

      问题2.可以实现算法的时间复杂度为O(N)吗?

      答:不可能了,由于涉及到了字符串的匹配所以至少需要O(N*M)的时间复杂度,M是什么脑补,或者看下面的。

      首先需要找到哪里有oldChars,请看代码

    在母串中寻找子串
    在母串中找子串的原则
    
      bool eq=truewhile (index + oAlen <= vAlen)
                {
                    eq = true;
                    for (int k = 0; k < oAlen; k++) 
                    {
                        if (value[index + k] != oldchars[k]) 
                        {
                            eq = false;
                            break;
                        }
                    }
                    if (eq)
                    {
                      //do some thing
                        index = index + oAlen;
                    }
                    else 
                    {
                        index++;
                    }
                }

       知道M是什么了吧?里面的度something就是实现替换oldChars和newChars的替换,while的条件一个是为了减少比较次数,还有就是保证for循环中的value[index+k]不越界,出现异常。

      给出从前向后替换的全部代码,母字符串value,实际长度时vALen

    从前向后替换字符串
      public void ReplaceFromHead(char[] value, int vAlen, char[] oldchars, int oAlen, char[] newChars, int nAlen) 
            {
                int newIndex=0, index = 0;
                bool eq = true;
                while (index + oAlen <= vAlen)
                {
                    eq = true;
                    for (int k = 0; k < oAlen; k++) 
                    {
                        if (value[index + k] != oldchars[k]) 
                        {
                            eq = false;
                            break;
                        }
                    }
                    if (eq)
                    {
                        for (int k = 0; k < nAlen; k++)
                        {
                            value[newIndex] = newChars[k];
                            newIndex++;
                        }
                        index = index + oAlen;
                    }
                    else 
                    {
                        value[newIndex]=value[index];
                        newIndex++; 
                        index++;
                    }
                }
                while (index<vAlen)
                {//把剩余的字符串移动到前面
                    value[newIndex] = value[index];
                    newIndex++;
                    index++;
                }
                while(newIndex<value.Length)
                {
                  value[newIndex] = '\0';
                  newIndex++;
                }
    
            }

      newIndex代表移动后的value的指针,index扫描的是老的value的指针,当index扫描到新的oldChars时就替换,否则就把index指向的字符移到newindex的位置,然后一个while循环index后边的字符复制到index,完成字符串复制;在之后while保证新的value后面都是'\0',不会在输出是出错。

      我们可以按照相同的思路完成从 后向前移动的算法。

      问题3.真的可以这样实现从后向前移动的算法吗?为什么?

      答:睡觉了,明天再说

                                                    2013年3月24日0:36:55

                                                      菜包子 于宿舍

  • 相关阅读:
    Nbear讲解 之核心类CodeGenerator
    计算字符串显示的像素
    C# 加密算法[汇总]
    索引器的本质
    Excel[.xls|.xlsx|.csv] 导入 导出
    Spring.Net Ioc 实例
    反射中 BindingFlags标识
    C# 图片操作 常用方法 总结
    iTextSharp 生成pdf Form 实例
    玩转 Route
  • 原文地址:https://www.cnblogs.com/CaiBaoZi/p/2977956.html
Copyright © 2011-2022 走看看