字符串反转,神奇的算法-读《编程珠玑(第二版)》

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

最近在缓慢地读《编程珠玑(第二版)》(英文名Programming Pearls),书很薄(正文才160多页),但正如其封面“近20年来众多大师级程序员一致推崇的作品”所示,这本经典哪能是我一下子就能读完的?书中有很多简洁但有趣的例子分析,更有作者的实际经验及注意点的阐述,值得一点点地读,一遍不够以后再来第二、三遍...

另外,前些天发现51CTO读书频道有《编程珠玑(续)》(英文名 More Programming Pearls)整本书的在线阅读,真是太赞了!

回到正题。第二章“啊哈!算法”中作者给出三个“小题目”,其中第二个是:将一个具有n个元素的一维向量x向左旋转i个位置。例如,将 ABC123DEF456 向左旋转 3 个位置之后得到 123DEF456ABC。要求是花费与n成比例的时间来完成这个操作。

题目虽小,但正如本章标题“啊哈!算法”所示,作者想要强调的是算法的巧妙与强大,其中有本题的3种解决方案。

*.使用临时数组

这大概是大多数人都会想到的一种方案,即将所给向量x的前i个复制到临时数组中,再将剩下的n-i 个元素往左移动i个位置,最后将临时数组中的i个元素复制回x中后面的位置。

代码实现:

 
  1. public void tempArrReverse(char [] arr, int len, int m){
  2. char [] temp = new char[m];
  3. // 将数组前m个元素保存到临时数组
  4. for(int i = 0; i < m; i++){
  5. temp[i] = arr[i];
  6. }
  7. // 将数组后面(len-m)个元素前移
  8. for(int i = m; i < len; i++){
  9. arr[i-m] = arr[i];
  10. }
  11. // 将临时数组所有元素复制到原数组
  12. for(int i = 0; i < m; i++){
  13. arr[len-m+i] = temp[i];
  14. }
  15. }

很明显上面的解法虽然简单移动,但用到了i个额外的空间,比较浪费空间。于是又有一个作者称赞“堪称巧妙的杂技表演”的解法。

*.“巧妙的杂技表演”

先将x[0]移到临时变量t中,再把x[i]移到x[0]腾出来的位置中,x[2i]移到x[i]中,以此类推(每一次移动时将x[]中的下标对其长度n取模),直到又回到从x[0]提取元素,此时应该把临时变量t放入到上一个位置中,并开始下一次迭代,即对x[1]进行类似的操作。

找来书中直观的图如下:

代码实现:

 
  1. public void juggleReverse(char [] arr, int len, int m){
  2. int k = 0;
  3. for(int i = 0; i < m; i++){
  4. k = 1; //每次迭代都从1倍位移开始
  5. char temp = arr[i];
  6. while((k*m+i) % len != i){
  7. arr[(k-1)*m+i] = arr[k*m+i];
  8. k++;
  9. }
  10. arr[(k-1)*m+i] = temp;
  11. }
  12. }


但是,正如作者所提醒的“将这个想法转换为代码,请务必小心!”实际上我的实现中只能是当原向量长度n是位移i的整数倍时才可行,碰巧书中的也是用 i=3n=12 这个例子来演示说明的,而且感觉此处的译文有点儿别扭,理解得不顺畅,得找找原文是怎么说的。

如果你在纸上画一下不是整数倍的情况,会发现其实情况复杂得多,有可能某些元素被放到其正确位置的后面去了,而我又不想用很多if...else语句来判断所出现的情况,因为我认为是我没理解到作者的思路,所以暂时只能这么实现(还要再思考),希望高手看到能指教一下。=)

*.另一种更巧妙的思路-原语的力量

其实题目的意思就是字符串反转(reverse,不知道原文中“旋转”是不是这个词,得查证),书中这一小节“原语的力量”提到“有些编程语言提供了旋转作为对向量的原语运算”。假如已经有将数组指定部分元素进行反转的函数(原语操作),接下来的解法就更有意思了。

原问题可以这样来看:将原数组看成 ab,需要转换成 ba,先单独对子数组a进行反转得到a'ba'表示a反转后的结果),同理单独反转b,得到 a'b',最后将得到的 a'b' 一起进行一次反转可得 (a'b'',而这就是最终结果 ba了,不信你在纸上尝试一下(或者请看下面更有趣的、可操作的例子)。

代码实现:

 
  1. // 原语操作-反转数组
  2. public void reverse(char [] arr, int start, int end){
  3. int mid = (start + end) / 2;
  4. for(int s = start, i = 1; i < mid; s++, i++){
  5. char temp = arr[s];
  6. arr[s] = arr[end-i];
  7. arr[end-i] = temp;
  8. }
  9. }
  10. public void useReverse(char [] arr, int len, int m){
  11. reverse(arr, 0, m);
  12. reverse(arr, m, len);
  13. reverse(arr, 0, len);
  14. }

其实到这里我认为作者已经让我感受到算法巧妙之处了,对于相同问题的不同理解、看法可以激发出这么精彩的解法。但实际上你还会发现这本经典书还很频繁地列举其他大师级人物对某问题的解法与运用之类的历史信息。例如,书中提到 Ken Thompson也是将这段代码用在其编辑器和转置代码的,而且“声称即使在那个时候,那也可编入神话故事了”。难道还不够精彩吗?请看下面。

*.可操作的证明方法-手摇法

如果要将一个具有10个元素(我们只有10个手指啊)的数组向上旋转5个位置,先让两只手的掌心正对你自己,左右放在右手上面(其实两只手是同意平面上的),看下图:

其实如果亲自读这本书的话,会发现更多精彩!这样一本书,难道不值得一点点地读吗?

 

转自:http://haolloyin.blog.51cto.com/1177454/560597

 

 

 

 

旋转字符串编程珠玑第二章;rotate a one-dimensional vector;循环移位数组;编程之美 一:问题描述: 编程珠玑第二章的第二个问题是字符串(或者理解为向量)旋转问题,具体描述如下: 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位,要求时间复杂度为O(N),且只允许使用两个附加 阅读详情

相关推荐

字符串部分反转

题目: 将一个字符串进行反转。 将字符串中指定部分进行反转。 例如,将abcdefg 反转为: abfedcg 题解: 题目不算难,只是对于String的一个简单应用,但是对于该题目,可以实现一题多解: 将主要的功能模块抽离出来,main()只实现对于功能方法的调用即可: public static void main(String[] args) { String str = "abcdefg"; StringDemo stringDemo = new StringDemo(); Str

qq_47888755的博客 982

循环移位(翻转算法

循环移位

yk_ee的博客 2620

编程珠玑》中的最优性能效率最高字符串反转算法

编程珠玑》中的最优性能效率最高字符串反转算法

编程珠玑2》书笔记1---翻转代码

第二章 ”啊哈,算法“ P11 问题B:将一个n元一维向量向左旋转i个位置(循环移位),例如abcdefgh左循环移位3个位置变成defghabc  要求:使用一个n元的中间向量在n步内完成,能否仅适用数十个额外字节的存储空间,在正比于n的时间内完成? "啊哈,灵机一动": 贴个照片,不侵权吧,呵呵,手我加了指甲,分辨手掌正反面 代码: package org.

On the way 724

编程珠玑字符串反转

编程珠玑真是一本让人感觉到眼前一亮的书,虽然书不厚,但是里面的知识很贴近实际应用,也很有启发性,如果能真正的消化里面的内容,对程序的理解肯定会上一个档次。 本文给出的是第二章习题的第五题的大概程序! #include using namespace std; void move(int * arr, int arrsize,int n);//将数组arr的前n个元素左移 void show(

shiwazone的专栏 1022

对二进制数组进行循环左移C语言,旋转字符串编程珠玑第二章;rotate a one-dimensional vector;循环移位数组;编程之美...

一:问题描述:编程珠玑第二章的第二个问题是字符串(或者理解为向量)旋转问题,具体描述如下: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.这个问题在编程之美中也出现了,问题描述:设计...

weixin_30569303的博客 696

循环字符串问题中的翻手算法

最近再看《编程珠玑》,

玄云飘风的博客 638

旋转字符串

一:问题描述: 编程珠玑第二章的第二个问题是字符串(或者理解为向量)旋转问题,具体描述如下: 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. 这个问题在编程之美中也出现了,...

jackyhungvip的博客 140

字符串反转的9种方法

1. 使用Array.Reverse方法 对于字符串反转,我们可以使用.NET类库自带的Array.Reverse方法 public static string ReverseByArray(string original) { char[] c = original.ToCharArray(); Array.Reverse(c); return new string(c); }

迷之月光的专栏 1万+

利用计算机属性将字符串逆序输出,字符串逆序的各种实现算法

很早就准备写一个字符串系列的面试题,本来已经写好了,大概有十几道题,但是写完才发现,文章好长,连我自己都没有耐心下去了,索性就将其拆分成几个系列,一来分开后篇幅变小,看起来比较方便。二来也更有针对性,便于精雕细作。比如这篇,在原来的文章中只占很小的篇幅,但是独立出来才发现,东西也不少。既然是第一篇,就来个最最简单的字符串逆序吧。字符串逆序可以说是最经常考的题目。这是一道入门级的题目,相信80%的...

weixin_42297390的博客 525

字符串逆序算法实现

给定一个字符串S,将字符串S中的字符顺序颠倒过来,即实现字符串的逆序。本文将介绍一种字符串逆序算法的实现。

a_woxinfeiyang_a的专栏 3367

编程珠玑 Chapter2 字符串翻转算法

没办法,久没练过算法,只好用Java写了。 题目很简单: Q: abcdefg, r=3 A: defgabc 代码一:借助StringBuffer的append来做。即一部分一部分来求逆,然后再“拼接”起来求逆。 public class Rotate { /** * Rotate a String by reversing it partly and then

陌上 1209

字符串的替换、反转、查找、分割

以下实例中我们使用 java String 类的 replace 方法来替换字符串中的字符: public class StringReplaceEmp{ public static void main(String args[]){ String str="Hello World"; System.out.println( str.replace( 'H','W...

江江同学的博客啊 399

旋转交换或向量旋转

问题描述 (来源于《编程珠玑》第2的第2章第11页问题B) 请将一个具有n个元素的一维向量向左旋转i个位置。例如,假设n=8,i=3,那么向量abcdefgh旋转之后得到向量defghabc。简单编码使用一个具有n个元素的中间向量分n步即可完成此作业。你可以仅使用几十字节的微小内存,花费与n成比例的时间来旋转该向量吗? 解决思路 方案一: 将向量x中的前i个元素复制到一个临时

松子茶的专栏 2316

笔试——字符串算法题——翻转分段字符串

这个既然有人笔试完就问,那我还是敲一份分享一下吧。         题目大意:字符串的问题,把字符串按点的位置翻转。要求时间复杂度O(n)、空间复杂度O(1)。                             例如:对于字符串 "www.hyzhou.com.cn" 输出 "cn.com.hyzhou.www"         代码简单明了,就不写注释了,是在看不懂,自己调试

御坂的专栏 1336

LeetCode题解(0541)字符串分段反转(Python)

题目:原题链接(简单) 题目标签: 解法 时间复杂度 空间复杂度 执行用时 Ans 1 (Python) O(N)O(N)O(N) O(N)O(N)O(N) 36ms (91.51%) LeetCode的Python执行用时随缘,只要时间复杂度没有明显差异,执行用时一般都在同一个量级,仅作参考意义。 解法一(): def reverseStr(self, s: str, k: int) -> str: ans = "" while k * 2 <= len

长行 609

向量旋转算法集锦

 /*  Name: 向量旋转算法集锦   Copyright: 始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处  Author: goal00001111  Date: 28-12-08 23:28  Description:   向量旋转算法:将具有n个元素的向量a向左旋转r个位置。  例如 :将字符串"abcdefghij"旋转成"defghjabc",其中n=10

goal00001111的专栏 2480

J-Link驱动签名验证失败?手把手教你搞定Windows 11/10下的WHQL驱动安装(附INF文件下载)

本文详细解析了J-Link驱动在Windows 11/10企业环境中签名验证失败的解决方案,重点介绍了WHQL认证驱动的获取与安装流程,并提供了固件升级和新机调试的实用技巧,帮助开发者高效解决驱动兼容性问题。

weixin_33701251的博客 531
上一篇: Flex数据类型
下一篇: java责任链模式
hatom
博客等级 码龄15年 46粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值