翻转单词顺序VS左旋转字符串

已经有很多书籍和博客讲过这两个问题了,也有很多的解法,但是有的解法不够好,或者写的不太清楚,因此我再重新把这两个问题解释下,并用Java代码实现。

之所以将这两个问题放在一起去讨论,一方面是因为这两个问题都需要去反转字符串,另一方面是在反转完字符串后,各自的处理方法不太一样,是两个比较常见的面试笔试题目。

翻转单词顺序(曾经的微软面试题目):

问题描述:给定一个英文句子,将这个句子中每个单词作为整体进行反转,但是单词内字符顺序不变。

例如:输入字符串“I am a student.”,输出"student. a am I"。

问题分析:这个题目是一个比较经典的字符串处理题目,很多公司面试时都会考类似的题目。其实这个问题比较简单,编程前需要先分析清楚,再去写程序。两步就可以完成:

              第一步:可以先反转句子中所有的字符。样例中"I am a student." 经过第一步后变成".tneduts a ma I",可以定义一个方法或函数,专门用来反转字符串。

              第二步:再反转每个单词中字符的顺序。".tneduts a ma I" 经过第二步变成“student. a am I”,这一步中可以把空格作为单词之间的分隔符,但是要特别注意最后一个单词的处理,

                         因为最后一个单词没有空格结尾,可以将最后一个单词特别处理。

              下面使用Java代码实现,方法reverse()专门用来反转字符串,方法fanzhuan()实现了第二步的功能。 

左旋转字符串:

问题描述:给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部。要求时间复杂度为 O(n),空间复杂度为 O(1)。

例如:输入字符串“abcdef”,把前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。

问题分析:使用暴力法可以实现要求的功能,但是暴力法效率比较低,可以满足空间复杂度O(1),但是不满足题目中要求的时间复杂度O(n),因此需要寻找新的解法。

             这里提供了一种方法,叫做三步反转法。具体解释如下:

             将一个字符串分成X和Y两个部分,在每部分字符串上定义反转操作,如X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么可以得到这个结论:(X^T Y^T)^T=YX,这样就解决了字符串的反转问题。

             例如,字符串 abcdef ,若要让abc反转到def的后面,只要三步即可:

                      第一步:首先将原字符串分为两个部分,即X:abc,Y:def;

                      第二步:将X反转,X->X^T,即得:abc->cba;将Y反转,Y->Y^T,即得:def->fed。

                      第三步:反转上述步骤得到的结果字符串X^TY^T,即反转字符串cbafed的两部分(cba和fed)给予反转,cbafed得到defabc,形式化表示为(X^TY^T)^T=YX,这就实现了整个反转。

下面的Java代码中,方法zuofanzhuan()实现了这个操作,当然也需要反转每个每个部分的方法reverse()。

注意:Java语言中字符串包已经提供了很多方法可以直接实现反转操作,程序员直接调用即可,但是本文所讲的是更通用的方法,在任何编程语言中都可以使用的方法,并且讲出了问题的实质,提供了一种处理字符串的思想,

        这也是面试和笔试考官希望看到的答案,因此,这里的方法需要牢牢掌握,方便以后的字符串编程。

下面是具体的Java代码实现,读者可以很容易的改写成其他语言实现:


import java.util.*;
 class Test {
	public static String reverse(String str){            //将一个字符串进行反转
		StringBuilder strb=new StringBuilder(str);       //将其转换为可变字符串
		int low=0,high=strb.length()-1;
		while(low<high){                                //将左边位和右边位依次进行交换
			char ch=strb.charAt(low);
			strb.setCharAt(low,strb.charAt(high));
            strb.setCharAt(high,ch);	
            low++;  high--;
		}
			return strb.toString();                    //将可变字符串变成不可变字符串,并返回
	}
	
	public static String fanzhuan(String str){         //翻转每个单词的顺序
		  str=Test.reverse(str);                       //先整体反转
		  String strfinal=new String("");
		  String str1=new String("");
		  for(int i=0;i<str.length();i++)              //再反转每个单词的顺序
			  if(str.charAt(i)==' ')
			      { 
				  strfinal=strfinal+Test.reverse(str1)+str.charAt(i);
				  str1="";
			      }
			  else {
				   str1+=str.charAt(i);
		           if(i==str.length()-1)               //对最后一个单词进行处理,因为最后一个单词没有空格了
		        	   strfinal=strfinal+Test.reverse(str1);
			       }
		  return strfinal;
	}
	
	public static String zuoxuanzhuan(String str,int k){
		int n=str.length();
		if(n==0 || k<=0|| k>n )                    //如果字符串长度为0,或者k 不在字符串长度的范围内,则返回原来的字符串
			return str;         
		String str1=new String("");               //存储第一部分,前k个字符
		String str2=new String("");               //存储第二部分,后面n-k个字符
		for(int i=0;i<k;i++)
			str1+=str.charAt(i);
		for(int i=k;i<n;i++)
			str2+=str.charAt(i);
		return reverse(reverse(str1)+reverse(str2));    //采用三步反转法
	}
	}
 
public class Main {
	public static void main(String[] args) {
	  String str=new String("I am a student.");
	  System.out.println("翻转句子前为:"+str);
	  System.out.println("翻转句子后为:"+Test.fanzhuan(str));
	  int k=3;
	  str="abcdef";
	  System.out.println("左旋转字符串前为:"+str);
	  System.out.println("左旋转字符个数为:"+k);
	  System.out.println("左旋转字符串后为:"+Test.zuoxuanzhuan(str,k));
	  
	}

}

输出结果为:

翻转句子前为:I am a student.
翻转句子后为:student. a am I
左旋转字符串前为:abcdef
左旋转字符个数为:3
左旋转字符串后为:defabc


你可能感兴趣的:(java,算法,反转字符串,翻转字符串)