替换空格(Java)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013132035/article/details/80518640

题目:

请实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.”,则输出“We%20are%20happy.”。

第一思路:

(1):是在原来的字符串上做替换(一定要保证内存够用)还是在新创建的字符串并在新的字符串上做替换。因为“ ”替换成“%20”字符串的长度会增加;

(2):最直观的做法是O(n^2)的解法;从头到尾扫描字符串,每一次碰到空格的时候做替换。由于是把一个字符替换成3个字符,我们必须要把后面的所有字符都后移两个字节,否则就有两个字符被覆盖了。故假设字符串的长度是n,对每个空格字符,需要移动后面O(n)个字符,因此对含有O(n)个空格的字符串而言总的时间效率是O(n^2)。

最优解思路:

上面的做法会使时间复杂度达到O(n^2),于是需要提升上面的解题思路使其时间复杂度达到O(n^2);先遍历一遍字符串统计出字符串中空格的总长度,因每次替换一个空格长度+2;故所需的总长度为oldLenth + blankCount * 2;上次我们的时间复杂度达到n的平方,是因为每次替换一个空格,我们的后面的字符串都要移动造成的,故这次我们从后往前移动,使字符在第一次就到达自己的位置上,故这样做的话时间复杂度为O(n);

代码:

public static String replaceBlank(StringBuffer sb){
	int blankCount = 0;
	//先统计出空格的数量
	for (int i = 0; i < sb.length(); i++) {
		if(sb.charAt(i)== ' '){
			++blankCount;
		}
	}
	int oldLength = sb.length(); //得到原来字符串的长度
	int newLength = oldLength + blankCount * 2; //将空格替换为"%20"后的字符长度
	int oldIndex = oldLength - 1; //原来字符串的索引
	int newIndex = newLength - 1; //新字符串的索引
	sb.setLength(newLength);
	//一次遍历,替换其中的空格为"%20"
	while(oldIndex >= 0 && newIndex > oldIndex){
		if(sb.charAt(oldIndex)== ' '){
			sb.setCharAt(newIndex--, '0');
			sb.setCharAt(newIndex--, '2');
			sb.setCharAt(newIndex--, '%');
		}else{
			sb.setCharAt(newIndex--, sb.charAt(oldIndex));
		}
		--oldIndex;
	}
	return sb.toString();
}

第二种解法:

利用Java自己的函数replace(param, param, param)函数帮助我们替换字符串。我们只需要找到空格的位置即可

public static String replaceBlank(StringBuffer sb){
	for (int i = 0; i < sb.length(); i++) {
		char ch1 = sb.charAt(i);
		if(ch1 == ' '){
			sb.replace(i, i+1, "%20");
		}
	}
	return sb.toString();
}

replace函数的源码:其中count是计算str的长度

/**
     * Replaces the characters in a substring of this sequence
     * with characters in the specified <code>String</code>. The substring
     * begins at the specified <code>start</code> and extends to the character
     * at index <code>end - 1</code> or to the end of the
     * sequence if no such character exists. First the
     * characters in the substring are removed and then the specified
     * <code>String</code> is inserted at <code>start</code>. (This
     * sequence will be lengthened to accommodate the
     * specified String if necessary.)
     *
     * @param      start    The beginning index, inclusive.
     * @param      end      The ending index, exclusive.
     * @param      str   String that will replace previous contents.
     * @return     This object.
     * @throws     StringIndexOutOfBoundsException  if <code>start</code>
     *             is negative, greater than <code>length()</code>, or
     *             greater than <code>end</code>.
     */
    public AbstractStringBuilder replace(int start, int end, String str) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (start > count)
            throw new StringIndexOutOfBoundsException("start > length()");
        if (start > end)
            throw new StringIndexOutOfBoundsException("start > end");

        if (end > count)
            end = count;
        int len = str.length();
        int newCount = count + len - (end - start);
        ensureCapacityInternal(newCount);

        System.arraycopy(value, end, value, start + len, count - end);
        str.getChars(value, start);
        count = newCount;
        return this;
    }

第三种解法:利用Java已经封装好的函数

public static String replaceBlank2(String str){
	String str1 = str.replaceAll(" ", "%20");
	return str1;
}

replaceAll函数实现

public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

测试:

public static void main(String[] args) {
	StringBuffer sb = new StringBuffer();
	sb.append("We are happy.");
	String str = replaceBlank1(sb);
	System.out.println(str);
}

总结:

这道编程题考察对字符串的编程能力;

考察分析时间效率的能力,知道时间复杂度的计算;

对内存的考察;

课后小思:

有两个排序的数组A1和A2,内存在A1的尾部有足够多的空间去容纳A2。实现一个函数是A2插入A1是有序的,且时间复杂度最小。最后解的思路还是从尾部开始比较A1和A2,并把较大的数字复制到A1的合适位置,即第一次都到达自己的最终位置。故这类题目合并两个数组,如果从前往后复制每个数字需要重复移动数字多次,那么我们可以考虑从后往前复制,这样时间复杂度就会大大降低。

阅读更多

没有更多推荐了,返回首页