`
jackyhongvip
  • 浏览: 159671 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

旋转字符串

 
阅读更多

一:问题描述:

编程珠玑第二章的第二个问题是字符串(或者理解为向量)旋转问题,具体描述如下:

rotate a one-dimensional vector of n elements left by i positions. eg: with n = 8; i = 3, the vector abcdefgh is rotated to defghabc.

这个问题在编程之美中也出现了,问题描述:

设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为ON),且只允许使用两个附加变量。

下面的内容主要参考了编程之美中的几个算法,编程珠玑中的思想,以及网上牛人的总结,当然这些之间都是有很大关联的。

二:问题分析与解答:

1、

看到这个问题后我的第一印象是采用循环移位:

把字符用二进制表示,即0101的字符串,然后进行循环移位,这个是可行的,自己还去找了下循环移位如何实现,下面是c语言循环移位的一种实现:

假设串的长度是N,要循环移位k位,那么:

循环右移:(a>>k) | (a<<(N-k))  //即a先右移k位,然后再左移N-k位,然后进行或|运算就实现了循环右移。

循环左移:(a<<k) | (a>>(N-k))  //即a先左移k位,然后再右移N-k位,然后进行或运算就实现了循环左移

当然,如果对于数组的话,这个方法是不太方便的,对于字符串倒是可以。

2、另外一种比较直接的想法就是直接进行交换

比如要将前i个数移到后面的位置即从abcdefgh  --->   defghabc。那么就可以认为是进行三次移动,类似插入排序。

具体步骤是先将a备份,然后让bcdefgh向左移动一个位置,如此循环下去,很容易知道这个思想的时间复杂度是O(i*n)

具体实现如下:

void  rotate(int *array, int len, int pos)

{

int temp ;

while(pos—)

{

temp = array[0];

for(k=1; k<n; k++)

{

array[k-1] = array[k];

}

array[n-1] = temp;

}

}

显然这样的方法是可行的,但复杂度不满足要求。

3、下面的这种方法很是巧妙,而且很高效

利用的思想是(x^r y^r)^r = yx (其中x^r表示对x进行逆序操作)

例如:字符串是abcdefgh,i=3

那么可以看作x=abc;y=defgh

则x^r = cba;  y^r = hgfed(类似线性代数的转置吧)

则(x^r y^r) = cbahgfed

因此(x^r y^r)^r = defghabc = yx

因此需要是三次反转就可以实现字符串的旋转了,用伪代码表示为:

reverse(0, i-1);

reverse(i, n-1);

reverse(0,n-1);

其中reverse(x, y)表示反转从x到y的字符串。因此对应上面的例子就是
reverse(0,2);

reverse(3, 7);

reverse(0,7);

而反转就是一个小的循环,下面是reverse的一个简化实现:

image

可以从上图知道,这个算法的时间复杂度是线性的,满足要求。

4、下面还有几个神奇的算法思想值得学习和分享

a:假设i<n-i,最容易想到的是,前i个字符串最终一定要放在最后面i个位置。把这前后两个i位的字符串进行交换,则接下来的问题变成对前面长度为n-i的字符串进行同样的操作。如果i>n-i,则交换后变成对后面n-i个字符串进行操作。

这个思想在Gries and Mills的报告中称为Successive swap

伪代码如下:

if(i == 0 || i == n)

return;

k = p = i;

j = n –p;

while(k != j)

{

if(k > j)

swap(p-k, p, j);

k –= j;

else

swap(p-k, p+j-k; k);

j –= k;

}

swap(p-k, p, k);

其中swap(a, b, m)表示交换x[a…a+m-1] 和 x[b…b+m-1]

下面是一个简单的实现:

image

b、编程珠玑中的所谓juggling code,在课后习题中利用了gcd(最大公约数)

juggling code是看明白了,但为什么利用gcd确实不太明白啊,而且STL中也是利用的gcd,后面还得研究研究。

juggling的思想如下:先将x[0]保存起来,然后进行下面的操作:x[i]--->x[0]; x[2i]--->x[i]; x[3i]--->x[2i]…最后将x[0]的备份放到x[ki]的位置。如果这个过程没有移动所有的元素,那么继续保存x[1]重复上面的操作,当然是将x[i+1]--->x[1]; x[2i+1]--->x[i+1]…

这种思想是比较容易理解的,但后面利用了gcd的思想,没有深入的理解。

c、STL中的rotate

在C++中STL中实现了rotate操作,说实话原理我还真没看明白--!是利用了上面的b思想,而且利用的gcd,这应该是有一定的数学因素吧。

改天再研究研究~~~

参考文献:

1、编程珠玑

2、http://blog.csdn.net/v_JULY_v/archive/2011/04/14/6322882.aspx   程序员编程艺术(算法卷):第一章、左旋转字符串   这篇文章基本上是总结了所有的思路,赞LZ。同时这个博客收集了大量的经典问题而且讨论的很深入,值得自己研究学习啊

3、http://philoscience.iteye.com/blog/1010964    这篇文章参考了Gries and Mills的一篇总结报告,<swap section>(其实也是编程珠玑上提到的)但说时候这篇文章我一直没找到,注册了个帐号想从LZ这里下,但要注册三天才可以下载 –!

4、编程之美数组循环移位的章节

5、网络上其他牛人的blog,这里不再一一列出

 

 

 

 

另外相关的java实现:

/**
  * 将"abc1234" 循环右移4位  or 将"abc1234"循环左移3位
  *
  * 时间复杂度 O(n2)
  * @param target
  * @param k
  */
 public static void shift(char[] target,int k){
  int length = target.length;
  int m = k % length;
  while(k-- > 0){
   char f = target[length-1];
   for(int i=length-1;i>0;i--){
    target[i]=target[i-1];
   }
   target[0] = f;
  }
  
  System.out.println(String.copyValueOf(target));
 }
 
 /**
  * 将"abc1234" ---> "1234abc"
  * 高效算法:abc -- x  1234 -- y  将x y -- > y x 即可
  * (x^r y^r)^r = yx : x^r cba y^r 4321  -- (cba4321) ^ r ---> 1234abc 哈哈
  * @param target
  * @param k
  */
 public static void advanceShift(char[] target,int k){
  char[] x = Arrays.copyOfRange(target, 0, 3);
  char[] y = Arrays.copyOfRange(target, 3, target.length);
  x = reverce(x);
  y = reverce(y);
  target = reverce((String.copyValueOf(x)+String.copyValueOf(y)).toCharArray());
  System.out.println(String.copyValueOf(target));
 }
 
 private static char[] reverce(char[] target){
  StringBuffer sb = new StringBuffer();
  for(int i=target.length-1;i>=0;i--){
   sb.append(target[i]);
  }
  return sb.toString().toCharArray();
 }
 

分享到:
评论

相关推荐

    旋转字符串1

    旋转字符串问题是一个经典的字符串处理问题,它出现在许多编程竞赛和面试中,比如LeetCode平台上的题目。本问题的核心是判断给定的两个字符串A和B是否可以通过对A进行一定次数的旋转操作变成相同。 首先,我们需要...

    C语言左旋转字符串与翻转字符串中单词顺序的方法

    定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。 如把字符串 abcdef 左旋转 2 位得到字符串 cdefab。请实现字符串左旋转的函数。 要求时间对长度为 n 的字符串操作的复杂度为 O(n),辅助...

    java实现左旋转字符串

    Java 实现左旋转字符串 Java 实现左旋转字符串是 Java 编程语言中的一种常见操作,主要用于实现字符串的循环左移操作。下面将详细介绍 Java 实现左旋转字符串的知识点。 什么是左旋转字符串 左旋转字符串是指将一...

    java基础面试题左旋转字符串

    java基础面试题左旋转字符串提取方式是百度网盘分享地址

    c++-剑指offer题解之左旋转字符串

    c++ c++_剑指offer题解之左旋转字符串

    python-剑指offer第43题左旋转字符串

    python python_剑指offer第43题左旋转字符串

    python教程利用python3代码实现旋转字符串源码分享

    python教程利用python3代码实现旋转字符串源码分享,下载即可运行,欢迎下载学习

    java之左旋转字符串介绍

    Java之左旋转字符串介绍 左旋转字符串是指将字符串的前面若干个字符移动到字符串的尾部。例如,把字符串abcdef左旋转2位得到字符串cdefab。本文将介绍左旋转字符串的概念、实现方法和优缺点分析。 左旋转字符串的...

    左旋转字符串1

    首先,我们需要明确旋转字符串的基本思路。假设我们有一个字符串`s`,其长度为`len`,我们要将其左旋转`k`次。对于一次左旋转,我们可以先将字符串的第一个字符存储起来,然后将剩余的字符依次向前移动一位,最后将...

    3.如何旋转显示字符串?(Visual C++编程 源代码)

    3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转...

    华为编程题及字符串编程

    例如,可能需要实现一个高效的算法来判断两个字符串是否互为旋转字符串(一个字符串可以通过将另一字符串的某个部分移动到开头形成)或者找出字符串中最长的回文子串等。 接下来,关于字符串操作的常见方法。在...

    Arduino串口接收字符串

    Arduino 串口接收字符串 本文将详细介绍 Arduino 串口接收字符串的实现方法,包括基本概念、代码实现和应用实例。 一、Arduino 串口通信 Arduino 的串口通信是通过 Serial 类来实现的。 Serial 类提供了一系列的...

    数据结构-字符串.pptx

    字符串是计算机科学中的一种基本数据结构,用于存储和操作文本信息。在编程语言中,字符串通常是由一个或多个字符组成的序列。字符串的处理涉及到多种算法和技术,这些在解决实际问题时至关重要,特别是在文本处理、...

    第五次作业-字符串压缩数据.zip

    4. **Burrows-Wheeler Transform (BWT)**:这是一种预处理步骤,通过旋转字符串并根据字符顺序形成新的字符串,然后使用其他压缩方法(如Huffman或Run-Length Encoding)进一步压缩。 5. **Dictionary-based ...

    TIA博途WINCC的触摸屏VB脚本入门(Len函数获取字符串长度以及Right和Left函数).docx

    例如,你可以创建三个变量:strInput(存储输入字符串)、lenth(存储字符串长度)、leftLenth(存储从字符串左边取的子串长度)和rightLenth(存储从字符串右边取的子串长度)。 接着,打开根画面,从工具箱中拖放...

    基于字符串移位包含的问题详解

    循环移位,也称为旋转字符串,指的是将字符串的首字符移动到末尾,其余字符依次向前移动一位,形成一个新的字符串。 在提供的代码中,有两个不同的解决方案,分别是穷举法(IfRotateContain1)和空间换取时间法...

    VB编程资源大全(源码 字符串)

    1,strs.zip 实现字节数组, 同c中的字符数组一样好用(6KB) 2,modules.zip 字符串处理的12个例子(13KB) 3,strings.zip 字符串处理函数(4KB) 4,stringfuncs.zip 字符串处理函数(9KB) 5,search&...

    Java 名字旋转

    这个程序可能是用来实现一种特殊的效果,比如反转字符顺序、按照特定规则旋转字符串中的字符等。下面我们将深入探讨Java中如何实现名字旋转,并提供相关的编程知识点。 1. **字符串基础**:在Java中,字符串是不可...

Global site tag (gtag.js) - Google Analytics