zoukankan      html  css  js  c++  java
  • 翻转单词顺序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代码实现,读者可以很容易的改写成其他语言实现:

     1 import java.util.*;
     2  class Test {
     3     public static String reverse(String str){            //将一个字符串进行反转
     4         StringBuilder strb=new StringBuilder(str);       //将其转换为可变字符串
     5         int low=0,high=strb.length()-1;
     6         while(low<high){                                //将左边位和右边位依次进行交换
     7             char ch=strb.charAt(low);
     8             strb.setCharAt(low,strb.charAt(high));
     9             strb.setCharAt(high,ch);    
    10             low++;  high--;
    11         }
    12             return strb.toString();                    //将可变字符串变成不可变字符串,并返回
    13     }
    14     
    15     public static String fanzhuan(String str){         //翻转每个单词的顺序
    16           str=Test.reverse(str);                       //先整体反转
    17           String strfinal=new String("");
    18           String str1=new String("");
    19           for(int i=0;i<str.length();i++)              //再反转每个单词的顺序
    20               if(str.charAt(i)==' ')
    21                   { 
    22                   strfinal=strfinal+Test.reverse(str1)+str.charAt(i);
    23                   str1="";
    24                   }
    25               else {
    26                    str1+=str.charAt(i);
    27                    if(i==str.length()-1)               //对最后一个单词进行处理,因为最后一个单词没有空格了
    28                        strfinal=strfinal+Test.reverse(str1);
    29                    }
    30           return strfinal;
    31     }
    32     
    33     public static String zuoxuanzhuan(String str,int k){
    34         int n=str.length();
    35         if(n==0 || k<=0|| k>n )                    //如果字符串长度为0,或者k 不在字符串长度的范围内,则返回原来的字符串
    36             return str;         
    37         String str1=new String("");               //存储第一部分,前k个字符
    38         String str2=new String("");               //存储第二部分,后面n-k个字符
    39         for(int i=0;i<k;i++)
    40             str1+=str.charAt(i);
    41         for(int i=k;i<n;i++)
    42             str2+=str.charAt(i);
    43         return reverse(reverse(str1)+reverse(str2));    //采用三步反转法
    44     }
    45     }
    46  
    47 public class Main {
    48     public static void main(String[] args) {
    49       String str=new String("I am a student.");
    50       System.out.println("翻转句子前为:"+str);
    51       System.out.println("翻转句子后为:"+Test.fanzhuan(str));
    52       int k=3;
    53       str="abcdef";
    54       System.out.println("左旋转字符串前为:"+str);
    55       System.out.println("左旋转字符个数为:"+k);
    56       System.out.println("左旋转字符串后为:"+Test.zuoxuanzhuan(str,k));
    57       
    58     }
    59 
    60 }
    View Code

    输出结果为:

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

  • 相关阅读:
    高速排序(递归与分治的思想)
    silverlight wcf mvvm
    黑龙江绿色食品青年电商销售大赛开幕,绿色巨人最终发力做电商了
    ecnu 1244
    可穿戴KEY带来的身份认证的革命
    深入理解7816(3)-----关于T=0 【转】
    深入理解7816(1)---- 关于F/D和etu【转】
    深入理解7816(2)---关于ATR【转】
    [Android 编译(一)] Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程
    Ubuntu16.04下搭建开发环境及编译tiny4412 Android系统【转】
  • 原文地址:https://www.cnblogs.com/guozhenqiang/p/5426787.html
Copyright © 2011-2022 走看看