B题是这样子的:

  将一个n元一维向量向左旋转(即循环移位)i个位置。例如,当n=8且i=3时,向量abcdefgh旋转为defghabc。简单的代码使用一个n元的中间向量在n步内完成该工作。你能否仅使用数十个额外字节的存储空间,在正比于n的时间内完成向量的旋转?

  以下题目的解答部分参考自一博文及该书参考答案。

  分析: 

  “abcdefgh”严格来说并不是一个字符串,因为'\0'是不会移动的。为了叙述方便,可以把它认为是字符串,只是不对'\0'进行操作罢了。

  如果不考虑时间要求为O(n),那么可以每次整体左移一位,一共移动i次。只使用O(1)的空间的条件下,一共要进行元素交换O(n*i)次;

  如果不考虑空间要求为O(1),那么可以把前i个存入临时数组,剩下的左移i位,再把临时数组里的内容放入后i个位置中。

  很可惜,由于两个限制条件,以上两种思路都不满足要求。

  1. 法一:"杂技"代码

  为了满足O(1)空间的限制,延续第一个思路,如果每次直接把原向量的一个元素移动到目标向量中它的应该出现新位置上就行了。先把array[0]保存起来,然后把array[i]移动到array[0]上,array[2i]移到array[i]上,直至返回取原先的array[0]。但这需要解决的问题是,如何保证所有元素都被移动过了?数学上的结论是,依次以array[0],...,array[gcd(i,n)-1]为首元进行循环即可,其中gcd(a,b)是a与b的最大公约数。

  1. void cyclicShift(char * in, int len, int shift)
  2. {
  3. assert(len >= );
  4. assert(shift >= );
  5. if (shift == || shift == len)
  6. {
  7. return;
  8. }
  9. if (shift > len)
  10. {
  11. shift = shift % len;
  12. }
  13.  
  14. int k, j;
  15. char temp;
  16. int times = gcd(len, shift);
  17. for (int i = ; i < times; i++)
  18. {
  19. j = i;
  20. temp = in[i];
  21. while (true)
  22. {
  23. k = (j + shift) % len;
  24. if (k == i) break;
  25. in[j] = in[k];
  26. j = k;
  27. }
  28. in[j] = temp;
  29. }
  30. }
  31.  
  32. int gcd(int a, int b)
  33. {
  34. assert(a > && b > );
  35.  
  36. // Method1
  37. // int r;
  38. //while (b > 0)
  39. //{
  40. // r = a%b;
  41. // a = b;
  42. // b = r;
  43. //}
  44.  
  45. // Method2
  46. while (a != b)
  47. {
  48. if (a > b)
  49. a -= b;
  50. else
  51. b -= a;
  52. }
  53.  
  54. return a;
  55. }

  正如“杂技”一词所暗示的一样,这个算法就像在玩杂耍球,你要让它们中的每一个都在合适的位置上,这些球,除了手中有一个,其它几个都在空中。如果不熟悉,很容易手忙脚乱,把球掉的满地都是。

  2. 法二:求逆(推荐)

  把原向量分为两部分a和b,分别对a、b求逆得到arbr,再对整体求逆便获得了ba!即(arbr)r = ba。代码如下:

  1. void cyclicShift3(char * in, int len, int shift)
  2. {
  3. assert(len >= );
  4. assert(shift >= );
  5. if (shift == || shift == len)
  6. {
  7. return;
  8. }
  9. if (shift > len)
  10. {
  11. shift = shift % len;
  12. }
  13.  
  14. reverse(in, , shift - );
  15. reverse(in, shift, len - );
  16. reverse(in, , len - );
  17. }
  18.  
  19. void reverse(char * in, int first, int last)
  20. {
  21. assert(first >= );
  22. assert(last >= );
  23. assert(first <= last);
  24.  
  25. char temp;
  26. while (first < last)
  27. {
  28. temp = in[first];
  29. in[first] = in[last];
  30. in[last] = temp;
  31. first++;
  32. last--;
  33. }
  34. }

  这种方法无疑既高效,也难以在编写时出错。有人曾主张把这个求逆的左旋方法当做一种常识。

  来看看这种思想的应用吧:

  扩展:(google面试题)用线性时间和常数附加空间将一篇文章的所有单词倒序。

  举个例子:This is a paragraph for test

  处理后: test for paragraph a is This

  如果使用求逆的方式,先把全文整体求逆,再根据空格对每个单词内部求逆,是不是很简单?另外淘宝今年的实习生笔试有道题是类似的,处理的对象规模比这个扩展中的“一篇文章”小不少,当然解法是基本一样的,只不过分隔符不是空格而已,这里就不重述了。

“《编程珠玑》(第2版)第2章”:B题(向量旋转)的更多相关文章

  1. 《编程珠玑(第2版)》【PDF】下载

    <编程珠玑(第2版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382225 内容简介 书的内容围绕程序设计人员面对的一系列实 ...

  2. java编程思想第四版第十一章习题

    第一题 package net.mindview.holding.test1; import java.util.ArrayList; import java.util.List; /** * 沙鼠 ...

  3. java编程思想第四版第六章总结

    1. 代码重构 为什么f要代码重构 第一次代码不一定是完美的, 总会发现更优雅的写法. 代码重构需要考虑的问题 类库的修改不会破坏客户端程序员的代码. 源程序方便扩展和优化 2. 包 创建一个独一无二 ...

  4. Java编程思想第四版*第七章*个人练习

    欢迎加群:239063848 成团的笔记:该组仅用于技术共享和交流,问题和答案公布 潘基聊天.禁止广告.禁止招聘-- 练习1:(2)创建一个简单的类.第二个类中,将一个引用定义为第一个类的对象.运用惰 ...

  5. java编程思想第四版第五章习题

    创建一个类, 它包含一个未初始化的String引用.验证该引用被Java初始化成了null package net.mindview.initialization; public class Test ...

  6. java编程思想第四版第六章习题

    (略) (略) 创建两个包:debug和debugoff,他们都包含一个相同的类,该类有一个debug()方法,第一个版本显示发送给控制台的String参数,而第二版本什么也不做,使用静态import ...

  7. java编程思想 第四版 第六章 个人练习

    欢迎加群:239063848 进群须知:本群仅用于技术分享与交流.问题公布与解答 禁止闲聊.非诚勿扰 练习1:(1)在某个包中创建一个类,在这个类所处的包的外部创建该类的一个实例. import mi ...

  8. java编程思想第四版第9章

    练习3: public class MainTest { public static void main(String args[]){ Bcycle b=new Bcycle(); b.print( ...

  9. Java编程思想第四版 *第五章 个人练习

    练习3:(1)创建一个带默认构造器(即无參构造器)的类.在构造器中打印一条消息.为这个类创建一个对象.P116 public class Test{ public Test(){ System.out ...

  10. java编程思想第四版第十三章字符串 总结

    1. String和StringBulider的使用 通过书中介绍, 我们得知如下结论: 当使用+连接符将字符串进行拼接的时候, 编译器会进行自动优化为使用StringBuilder连接字符串. 当在 ...

随机推荐

  1. python 函数运算先于单目运算

    >>> def f(): >>> -f() - 初一看,-f()比较陌生的样子,细想,这是合理的

  2. 28自定义View 模仿联系人字母侧栏

    自定义View LetterView.java package com.qf.sxy.customview02; import android.content.Context; import andr ...

  3. Linux 高性能服务器编程——IP协议详解

    1 IP服务特点 IP协议是TCP/IP协议族的动力,它为上层协议提供无状态.无连接.不可靠的服务. 无状态:IP通信双方不同步传输数据的状态信息,因此IP数据包的发送.传输和接收都是无序的.     ...

  4. 返回present的根

    //返回四大tab页面 + (void)gobackToTabarController { UINavigationController* selectedTabNavController = (UI ...

  5. 基于OpenCV 的美颜相机推送直播流

    程序流程: 1.图像采集 先从opencv(2.4.10版本)采集回来摄像头的图像,是一帧一帧的 每一帧图像是一个矩阵,opencv中的mat 数据结构. 2.人脸的美化 人脸美化,我们用的皮肤检测, ...

  6. 【Unity Shaders】Alpha Test和Alpha Blending

    写在前面 关于alpha的问题一直是个比较容易摸不清头脑的事情,尤其是涉及到半透明问题的时候,总是不知道为什么A就遮挡了B,而B明明在A前面.这篇文章就总结一下我现在的认识~ Alpha Test和A ...

  7. c语言求最大公约数

    求差判定法. 如果两个数相差不大,可以用大数减去小数,所得的差与小数的最大公约数就是原来两个数的最大公约数.例如:求78和60的最大公约数.78-60=18,18和60的最大公约数是6,所以78和60 ...

  8. Hadoop:hadoop fs、hadoop dfs与hdfs dfs命令的区别

    http://blog.csdn.net/pipisorry/article/details/51340838 'Hadoop DFS'和'Hadoop FS'的区别 While exploring ...

  9. CMake搜索Boost1.57失败及解决

    CMake更新到3.1.0,Boost更新到1.57,结果CMake搜索Boost失败: Unable to find the Boost header files.  Please set BOOS ...

  10. Android必知必会--GreenDao缓存

    Github版 CSDN版 本篇文章不是介绍GreenDao的配置和基础使用,记录一下GreenDao缓存的问题,帮助遇到同样问题的朋友找到原因和方法,下面是示例: 场景重现 //第一次查询 List ...