面试题4:替换空格之发散思维二

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

  从后向前替换的时候,因为替换后的数组实际长度大于原来的数组实际长度,所以要考虑到数组溢出的问题,首先需要找出字符串valueChars中包含几个oldChars,计算出替换后的字符串实际长度是否存在溢出,如果存在则返回,否则开始从后面开始替换。

  问题就来了,从最后开始替换的时候,首先从最后一个字符开始比较,然后看是否相同,如果全部相同则代表这个词可以替换了。那么这样就和最先匹配原则出现的矛盾,例如'....aaaccc',oldChars='cc'时,newChars='ddd'时采用这种替换的方案,会替换后的字符串变为'....aaacddd',而根据这种最先匹配的原则,应该是'...aaadddc',这样就矛盾了!

  要想解决这个问题,首先要遍历一次valueChars找到最后一个oldChars所在的位置,然后替换掉,重复执行这个步骤,实际的算法复杂度可能是>O(N*N)的,显然是不符合要求的。

  答:不可以,因为这样找出来的oldChars可能不符合最先匹配原则,如果要求符合最先匹配原则,那么需要多次遍历valueChars,实际的算法复杂度实际的算法复杂度可能是>O(N*N)

  问题4.如果让你用比较小的内存开销,在时间复杂度上争取尽可能小,就是在内存和时间上找出平衡你有什么好的方案?

  对于从前向后合并的情况,用原来的方案就很好,时间复杂度O(N*M),空间复杂度O(1)。

  对于从后向前合并,由于以前要求内存O(1)的开销,导致我们在替换的时候需要不断的重复遍历valueChars,找到最后的一个oldChars,其实我们可以在第一次遍历的时候,就创建一个堆栈,记录每个oldChars的位置,然后替换他们。第一次遍历valueChars,是我们统计oldChars个数,防止替换后的串溢出的时候。因此可以写一个函数返回valueChars中所有oldChars的位置的堆栈。

详见代码:

2013年3月24日23:25:35

返回母串中子串位置的堆栈,从母串0的位置开始扫描
        private Stack<int> IndexSubstring(char[] value, int vaLen, char[] subStr, int saLen) 
        {
            if (saLen < 1 || vaLen < saLen)
            {
                return null;
            }
            Stack<int> indexStack = new Stack<int>();
            int index = 0;
            //保证不会出现越界现象
            while (index + saLen <= vaLen)
            {
                bool eq = true;
                for (int k = 0; k < saLen; k++)
                {
                    if (value[index + k] != subStr[k])
                    {
                        eq = false;
                        break;
                    }
                }
                if (eq)
                {
                    indexStack.Push(index);
                    index = index + saLen;
                }
                else
                {
                    index++;
                }
            }
            return indexStack;
        }

  得到子串在母串的所有位置之后就可以进行合并,合并的过程需要设置三个变量lastCopyLoc指针,指向原来的字符串,从后向前扫描时,已经处理的位置,index代表当前oldChars所在的位置,newVAlen新的字符串处理的位置,当堆栈为空时,结束复制。

   问题5.当不限制内存时,可以为原来valueChars开辟新的内存空间时,有没有什么其他的方案?

   答:由于不限制内存,我们完全可以新开辟一块儿足够大的char [],字符串的替换放到char []中进行,然后根据情况返回内存合适小的char[],

开辟了新内存的代码
[ThreadStatic]
        static char[] mTempChars;
        protected static char[] GetTempData()
        {
            if (mTempChars == null)

                mTempChars = new char[1024 * 64];

            return mTempChars;
        }
        private static int GetActualLength(char[] value)
        {
            int alen = 0;
            for (int i = 0; i < value.Length; i++)
            {
                if (value[i] == '\0')
                {
                    break;
                }
                alen++;
            }
            return alen;
        }
        public static void CharsReplace(char[] value, char[] oldchars, char[] newChars) 
        {
            int oAlen = GetActualLength(oldchars);
            if (oAlen < 1)
                return;
            int vAlen = GetActualLength(value);
            int nAlen = GetActualLength(newChars);
            char[] tmpchars = GetTempData();
            int index = 0;
            int copyIndex = 0;
            bool eq = false;
            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++)
                    {
                        tmpchars[copyIndex] = newChars[k];
                        copyIndex++;
                    }
                    index += oAlen;
                }
                else 
                {
                    tmpchars[copyIndex] = value[index];
                    index++;
                    copyIndex++;
                }
            }
            while (index < vAlen) 
            {
                tmpchars[copyIndex] = value[index];
                index++;
                copyIndex++;
            }
            if (value.Length < copyIndex) 
            {
                value = new char[copyIndex];
            }
            for (int i = 0; i < copyIndex;i++ )
            {
                value[i] = tmpchars[i];
            }
            return;
        }
   

  首先这个代码是参照http://www.cnblogs.com/smark/archive/2012/11/05/2754529.html 的代码(我在百度中搜索了半天,都没有找到最初的作者),我发现了里面有一个漏洞,(源代码的变量名和我的代码不一样)是while(index <vAlen){.....},这样会导致for循环中value[index+k]的部分越界,所以做了修改。  

  源代码中使用了[ThreadStatic] 属性,[ThreadStatic]来对每个线程分配一组Char[],因此这个在单例模式的时候,当线程访问时可以访问不同的tempChars的,可以避免数据不一致。

  明天要把所有的代码结合起来组成一个新的类。

                                                  2013年3月25日23:02:44

                                                    菜包子   于宿舍

posted on 2013-03-25 23:04  菜包子  阅读(295)  评论(0编辑  收藏  举报

导航