算法研究之左旋字符串

今天看了一个大牛在网上写的关于算法的研究,感触颇深,所以写下跟随其脚步研究的过程。

定义:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。 如把字符串abcdef左旋转2位得到字符串cdefab。长度为7的数组,左旋2位即右移4位。

让我们首先来看一个算法:先不考虑字符串的左旋,而是考虑一个字符数组的左旋——设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N), 且只允许使用两个附加变量。

对于这个问题:

解法1:可以每次将数组中的元素右移一位,循环K次。

public class Sweep {
	/*
	 * 将str左旋n位  N:字符数组长度 k:左旋位数
	 */
	public char[] sweepString(char[] str,int N,int k){
		char temp;
		while(k-->0){
			temp=str[N-1];
			for(int i=N-1;i>0;i--){
				str[i]=str[i-1];
			}
			str[0]=temp;
		}
		return str;
	}
	public static void main(String[] args) {
		Sweep sweep=new Sweep();
		char[] test={'a','b','c','d','1','2','3'};
		System.out.println(sweep.sweepString(test, 7, 2));
	}
}
结果为:

abcd123
23abcd1

此算法复杂度为O(kxN)

解法2:

其实我们如果考虑到K如果大于N,即循环左旋,这样我们可以看到右移K位之后的情形,跟右移K’= K % N位之后的情形一样,因此我们可以改进这个算法

加入 K %= N  这样一来,复杂度就变为O(n2)与k无关了。


解法3:

实际上从整体上来看,这个左旋的过程分为两部分:

1、将数组分为两部分,即要左旋的k位和剩下的数组。

2、将这两部分交换下。

变换的步骤实例如下:

逆序排列abcd:abcd1234 → dcba1234; 

逆序排列1234:dcba1234 → dcba4321; 

全部逆序:dcba4321 → 1234abcd。

实现如下:

public class Sweep {
	/*
	 * 将str左旋n位  N:字符数组长度 k:左旋位数
	 */
	public char[] sweepString(char[] str,int N,int k){
		char temp;
		k %= N;
		while(k-->0){
			temp=str[N-1];
			for(int i=N-1;i>0;i--){
				str[i]=str[i-1];
			}
			str[0]=temp;
		}
		return str;
	}
	
	public char[] sweepString2(char[] str,int N,int k){
		reverse(str, 0, N-k-1);
		reverse(str, N-k, N-1);
		reverse(str, 0, N-1);
		return str;
	}
	/*
	 * 逆转输入数组
	 * p:要逆转的数组开始 q:结束
	 */
	private char[] reverse(char[] str,int p,int q){
		char temp;
		for(;p<q;p++,q--){
			temp=str[p];
			str[p]=str[q];
			str[q]=temp;
		}
		return str;
	}
	
	public static void main(String[] args) {
		Sweep sweep=new Sweep();
		char[] test={'a','b','c','d','1','2','3'};
		System.out.println(test);
		System.out.println(sweep.sweepString2(test, 7, 2));
	}
}

输出结果相同。

而这样使用三次翻转的算法,将时间复杂度控制到了线性。

现在我们回到原题上来,对字符串的左旋,现在看来就比较简单了

拿abcdef 这个例子来说:

1、首先分为俩部分,X:abc,Y:def; 

2、X->X^T,abc->cba, Y->Y^T,def->fed。 

3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。

以上。

上一篇:浏览器缓存详解:expires,cache-control,last-modified,etag详细说明


下一篇:Linux环境中堆栈和堆相关内存损坏的基本原理和调试方法介绍