字符串2:左旋转字符串

来源:互联网 发布:新闻的数据库设计 编辑:程序博客网 时间:2024/05/21 11:04

题目:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

本题的方法很多,有针对这道题目的解决方法,也有比较通用的思路。

方法1:使用String类库。针对这道题目的特点来解决问题,首先k=k%(s.length());要求将字符串前面的k个字符切割放到字符串的尾巴上面,根据字面意思就可以使用str.subString(k)取出截取后剩余的部分,用str.subString(0,k)取出要截取的部分,然后将他们拼接即可。str.subString(k).append(str.subString(0,k))即为要求的左旋字符串。

public class Solution {    public String LeftRotateString(String str,int n) {        if(str.length() == 0){            return str;        }        StringBuffer buffer = new StringBuffer(str);        StringBuffer buffer1 = new StringBuffer(str);        StringBuffer buffer2 = new StringBuffer();        buffer.delete(0,n);        buffer1.delete(n,str.length());        buffer2.append(buffer.toString()).append(buffer1.toString());        return buffer2.toString();    }}
这是使用Java类库已经封装好的String类和StringbBuffer的类库来实现的,相当于使用Collections.sort()来进行排序,虽然很方便直接,时间复杂度为O(n),空间复杂度为O(n),但是String本质上也是使用char字符数组来解决的,因此,没有从根本上解决问题。

一个常识:subString(int begin)是将[begin开始的后面全部字符串进行截取;subString(intbegin,int end)是截取[begin,end)部分的字符串,即只是截取到end的前面一个字符。

方法2:使用String类库。根据本题的特点,可以发掘一个规律,将str 前面的k个字符放到尾巴上面,只要先将两个str拼接,str=str+str;然后从str中k位置开始截取n个长度即可,例如对于str=abcdef,长度len=6;如果k=3,只要先得到str=abcdefabcdef,然后从k=3开始,截取len=6个字符即为defabc.

class Solution {public:    string LeftRotateString(string str, int n) {        int len = str.length();        if(len == 0) return "";        n = n % len;        str += str;        return str.substr(n, len);    }};

方法3:使用可扩展的思路,两次反转字符串。对于abcdef,要求将abc放到后面,可以看做是str1=abc,str2=def这两个字符串要进行反转,即两个单词要进行反转,对于“将句子中的单词进行反转”这个问题,有成熟的方法可以使用,就是进行2次反转来实现,首先将整个句子中的全部字符进行反转,然后对于反转后的句子,对于里面的每个单词进行遍历,使用beginIndex,endIndex进行遍历,当遍历到空格“ ”时就认为是一个单词,将这个单词进行反转,当整个句子中的所有单词都反转之后就得到结果了,即句子中单词之间反转,单词内部顺序,例如”I am a student.”à”student. a am i”;于是关键是创建一个方法将字符数组中从beginIndex开始到endIndex部分的字符进行反转,对于一个字符串进行反转,本身不能完成,需要将其分解成为字符数组再来对数组进行操作,分解成为字符数组之后,可以创建新一个新的数组,将原数组反向遍历放到这个数组中即可;但是最简单高效的方法是,这设置两个指针p1,p2从头尾开始遍历,将p1,p2两个字符进行交换即可,于是时间复杂度是O(n/2),空间复杂度是O(1).

本题中可以将字符串前面k个字符和后面的部分看做是一个句子中的两个单词,要将这两个单词反向,只需要先对整个数组进行反向,然后再对[0,k)和[k,end)这两个子数组进行反向即可。注意这里[0,k)和[k,end)是错误的,由于前一次反转已经导致了整个数组反向,一次此时应该进行反转的子数组的范围是[0,array.length-k)和[array.length-k,end)。

//左旋字符串,使用不依赖String类库的方法来实现,利用反转单词的方法来解决public class Solution {    public String LeftRotateString(String str,int n) {        //特殊输入        if(str==null||str.length()<0) return null;        //空输入;对于空字符串由于length是0可能出错,所以最好特殊处理        if(str.length()==0) return "";        //处理n,避免越界        n=n%(str.length());                //将字符串转变为字符数组        char[] array=str.toCharArray();                //第一次反转,将整个数组进行反转        this.reverse(array,0,array.length);                //将[0,k)部分数组进行翻转        this.reverse(array,0,array.length-n);                //将[k,array.length)部分数组进行翻转        this.reverse(array,array.length-n,array.length);           //或者return new String(array);        return String.valueOf(array);    }        //这个方法专门用来将数组中begin~end部分的数组元素进行翻转    public void reverse(char[] array,int begin,int end){     //已知输入的begin,end一定在array范围内,不会越界        int pStart=begin;        int pEnd=end-1;        while(pStart<pEnd){            //交换前后对称位置的元素            char temp=array[pEnd];            array[pEnd--]=array[pStart];            array[pStart++]=temp;        }    }}



1 0
原创粉丝点击