程序员编程艺术学习笔记(一)字符串左旋问题
2014-05-03 23:56
721 查看
程序员编程艺术原文出自大神:v_JULY_v 地址:http://blog.csdn.net/v_july_v/article/category/784066
c++实现.敬请膜拜。
由于之前忙于准备面试,但总觉得代码和算法分析实现力严重的不够扎实,了解自己所以心里没底。
最终决定沉下心来,从头把该实现的实现,从基础到升级版做到了然于心,自然心平气和,踏实自信。
原文C++实现,现将自己实现的java版本记录如下,不定期更新,自我监督,自我监督。
一,字符串左旋
题目描述:
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。
思路一、暴力移位法
初看此题,最先想到的笨方法可能就是一位一位移动。
完成一位的移动,再考虑x位的移动。
总体代码如下:
思路二、指针翻转法
咱们先来看个例子,如下:abc defghi,若要让abc移动至最后的过程可以是:abc defghi->def abcghi->def ghiabc
如此,我们可定义俩指针,p1指向ch[0],p2指向ch[m];
一下过程循环m次,交换p1和p2所指元素,然后p1++, p2++;。
第一步,交换abc 和def ,abc defghi->def abcghi
第二步,交换abc 和 ghi,def abcghi->def ghiabc
整个过程,看起来,就是abc 一步一步 向后移动
abc defghi
def abcghi
def ghi abc
//最后的 复杂度是O(m+n)
图解如下:
由上述例子九个元素的序列abcdefghi,您已经看到,m=3时,p2恰好指到了数组最后一个元素,于是,上述思路没有问题。但如果上面例子中i 的后面还有元素列?
即,如果是要左旋十个元素的序列:abcdefghij,ok,下面,就举这个例子,对abcdefghij序列进行左旋转操作:
如果abcdef ghij要变成defghij abc:
abcdef ghij
1. def abc ghij
2. def ghi abc j //接下来,j 步步前移
3. def ghi ab jc
4. def ghi a j bc
5. def ghi j abc
下面,再针对上述过程,画个图清晰说明下,如下所示:
String str="abcdefghijx";时,无法直接走到结尾:
返回结果为:defghiabcjx 需要处理尾巴
ok,咱们来好好彻底总结一下此思路二:(就4点,请仔细阅读):
1、首先让p1=ch[0],p2=ch[m],即让p1,p2相隔m的距离;
2、判断p2+m-1是否越界,如果没有越界转到3,否则转到4(abcdefgh这8个字母的字符串,以4左旋,那么初始时p2指向e,p2+4越界了,但事实上p2至p2+m-1是m个字符,可以再做一个交换)。
3、不断交换*p1与*p2,然后p1++,p2++,循环m次,然后转到2。
4、此时p2+m-1 已经越界,在此只需处理尾巴。过程如下:
4.1 通过n-p2得到p2与尾部之间元素个数r,即我们要前移的元素个数。
4.2 以下过程执行r次:
ch[p2]<->ch[p2-1],ch[p2-1]<->ch[p2-2],....,ch[p1+1]<->ch[p1];p1++;p2++;
所以,之前最初的那个左旋转九个元素abcdefghi的思路在末尾会出现问题的(如果p2后面有元素就不能这么变,例如,如果是处理十个元素,abcdefghij 列?对的,就是这个意思),解决办法有两个:
方法一(即如上述思路总结所述):
def ghi abc jk
当p1指向a,p2指向j时,由于p2+m越界,那么此时p1,p2不要变
这里p1之后(abcjk)就是尾巴,处理尾巴只需将j,k移到abc之前,得到最终序列
方法二:
def ghi abc jk
当p1指向a,p2指向j时,那么交换p1和p2,
此时为:
def ghi jbc ak
p1++,p2++,p1指向b,p2指向k,继续上面步骤得:
def ghi jkc ab
p1++,p2不动,p1指向c,p2指向b,p1和p2之间(cab)也就是尾巴,
那么处理尾巴(cab)需要循环左移一定次数(而后的具体操作步骤已在下述程序的注释中已详细给出)。
五:分块翻转
对于这个问题,咱们换一个角度,可以这么做:
将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。
不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
我想,这下,你应该一目了然了。
其次,在《编程珠玑》上也有这样一个类似的问题,它的解法同本思路一致,如下图所示:
c++实现.敬请膜拜。
由于之前忙于准备面试,但总觉得代码和算法分析实现力严重的不够扎实,了解自己所以心里没底。
最终决定沉下心来,从头把该实现的实现,从基础到升级版做到了然于心,自然心平气和,踏实自信。
原文C++实现,现将自己实现的java版本记录如下,不定期更新,自我监督,自我监督。
一,字符串左旋
题目描述:
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。
思路一、暴力移位法
初看此题,最先想到的笨方法可能就是一位一位移动。
完成一位的移动,再考虑x位的移动。
总体代码如下:
public class StrMove { public static void main(String args[]){ String str="abcdefg"; int x=4; //move1(str,x); System.out.println(move1(str,x)); } //暴力移位法 public static String move1(String str,int x){ char[] array=str.toCharArray(); while(x!=0){ char s=array[0]; if(x<array.length){ for(int i=0;i<array.length-1;i++){ array[i]=array[i+1]; } array[array.length-1]=s; x--; } else{ return "x is bigger than length"; } } String str2=new String(array); return str2; }
思路二、指针翻转法
咱们先来看个例子,如下:abc defghi,若要让abc移动至最后的过程可以是:abc defghi->def abcghi->def ghiabc
如此,我们可定义俩指针,p1指向ch[0],p2指向ch[m];
一下过程循环m次,交换p1和p2所指元素,然后p1++, p2++;。
第一步,交换abc 和def ,abc defghi->def abcghi
第二步,交换abc 和 ghi,def abcghi->def ghiabc
整个过程,看起来,就是abc 一步一步 向后移动
abc defghi
def abcghi
def ghi abc
//最后的 复杂度是O(m+n)
图解如下:
public static void main(String args[]){ String str="abcdefghi"; int x=3;
public static String move2(String str,int x){ char array[]=str.toCharArray(); if(array.length==0||x<0||x>array.length){ return "false"; } for(int p1=0,p2=x;p1<array.length-x;p1++,p2++){ char tmp=array[p1]; array[p1]=array[p2]; array[p2]=tmp; } String str2=new String(array); return str2; }
由上述例子九个元素的序列abcdefghi,您已经看到,m=3时,p2恰好指到了数组最后一个元素,于是,上述思路没有问题。但如果上面例子中i 的后面还有元素列?
即,如果是要左旋十个元素的序列:abcdefghij,ok,下面,就举这个例子,对abcdefghij序列进行左旋转操作:
如果abcdef ghij要变成defghij abc:
abcdef ghij
1. def abc ghij
2. def ghi abc j //接下来,j 步步前移
3. def ghi ab jc
4. def ghi a j bc
5. def ghi j abc
下面,再针对上述过程,画个图清晰说明下,如下所示:
String str="abcdefghijx";时,无法直接走到结尾:
返回结果为:defghiabcjx 需要处理尾巴
public static String move2(String str,int x){ char array[]=str.toCharArray(); if(array.length==0||x<0||x>array.length){ return "false"; } int y=3; int n=array.length; for(int p1=0,p2=y;p1<array.length-y;p1++,p2++){ if(p2+y-1<array.length){ char tmp=array[p1]; array[p1]=array[p2]; array[p2]=tmp; }else{ System.out.println("越界"); } } String str2=new String(array); return str2; }
ok,咱们来好好彻底总结一下此思路二:(就4点,请仔细阅读):
1、首先让p1=ch[0],p2=ch[m],即让p1,p2相隔m的距离;
2、判断p2+m-1是否越界,如果没有越界转到3,否则转到4(abcdefgh这8个字母的字符串,以4左旋,那么初始时p2指向e,p2+4越界了,但事实上p2至p2+m-1是m个字符,可以再做一个交换)。
3、不断交换*p1与*p2,然后p1++,p2++,循环m次,然后转到2。
4、此时p2+m-1 已经越界,在此只需处理尾巴。过程如下:
4.1 通过n-p2得到p2与尾部之间元素个数r,即我们要前移的元素个数。
4.2 以下过程执行r次:
ch[p2]<->ch[p2-1],ch[p2-1]<->ch[p2-2],....,ch[p1+1]<->ch[p1];p1++;p2++;
所以,之前最初的那个左旋转九个元素abcdefghi的思路在末尾会出现问题的(如果p2后面有元素就不能这么变,例如,如果是处理十个元素,abcdefghij 列?对的,就是这个意思),解决办法有两个:
方法一(即如上述思路总结所述):
def ghi abc jk
当p1指向a,p2指向j时,由于p2+m越界,那么此时p1,p2不要变
这里p1之后(abcjk)就是尾巴,处理尾巴只需将j,k移到abc之前,得到最终序列
方法二:
def ghi abc jk
当p1指向a,p2指向j时,那么交换p1和p2,
此时为:
def ghi jbc ak
p1++,p2++,p1指向b,p2指向k,继续上面步骤得:
def ghi jkc ab
p1++,p2不动,p1指向c,p2指向b,p1和p2之间(cab)也就是尾巴,
那么处理尾巴(cab)需要循环左移一定次数(而后的具体操作步骤已在下述程序的注释中已详细给出)。
五:分块翻转
对于这个问题,咱们换一个角度,可以这么做:
将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。
不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
我想,这下,你应该一目了然了。
其次,在《编程珠玑》上也有这样一个类似的问题,它的解法同本思路一致,如下图所示:
public static String move5(String str,int x){ //StringBuffer str2=new StringBuffer(str); String tmp=str.substring(0, x); String tmp2=str.substring(x, str.length()); StringBuffer str1=new StringBuffer(tmp); str1.reverse(); System.out.println(str1); StringBuffer str2=new StringBuffer(tmp2); str2.reverse(); System.out.println(str2); StringBuffer s=new StringBuffer(); s.append(str1); s.append(str2); s.reverse(); String a=new String(s); return a; } public static String move6(String str,int x){ String tmp=str.substring(0, x); String tmp2=str.substring(x, str.length()); tmp=reverse(tmp); tmp2=reverse(tmp2); //System.out.println(tmp); //System.out.println(tmp2); String str2=tmp+tmp2; //System.out.println(str2); String result=reverse(str2); return result; } public static String reverse(String str){ char[] array=str.toCharArray(); char tmp; for(int i=0,j=array.length-1;i<j;i++,j--){ tmp=array[i]; array[i]=array[j]; array[j]=tmp; } String res=new String(array); return res; }
相关文章推荐
- 程序员编程艺术学习笔记(二)字符串是否包含问题
- 【程序员编程艺术】学习记录3:字符串包含问题
- 程序员编程艺术学习笔记(三续)Top K算法问题的实现
- 程序员编程艺术--2、字符串包含问题
- 程序员编程艺术2:字符串是否包含问题
- 程序员编程艺术:第二章、字符串是否包含及匹配/查找/转换/拷贝问题
- 程序员编程艺术:第二章、字符串是否包含问题
- 【程序员编程艺术】第二章:字符串是否包含问题
- 读程序员编程艺术第一章---左旋字符串(二)
- 读程序员编程艺术第二章---字符串包含问题
- 程序员编程技术学习笔记——字符串包含
- 【程序员编程艺术】学习记录1:左旋转字符串之指针翻转法
- 程序员编程艺术学习笔记(三)寻找最小的k个数
- 【笔记】程序员编程艺术 字符串转换成整数
- 程序员编程艺术:第二章、字符串是否包含及匹配/查找/转换/拷贝问题
- 读程序员编程艺术第一章---左旋字符串
- 个人解法 ------- 程序员编程艺术:第二章、字符串是否包含问题
- 读程序员编程艺术第一章---左旋字符串(三)
- 程序员编程技术学习笔记——左旋转字符串
- 程序员编程艺术:第二章、字符串是否包含及匹配/查找/转换/拷贝问题