温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

递归与分治算法练习

发布时间:2020-08-10 19:22:36 来源:ITPUB博客 阅读:119 作者:ckxllf 栏目:编程语言

  最近刚学习算法设计与分析的课程,所用教材是清华大学出版社王晓东编著的《算法设计与分析》。一道关于递归与分治算法的练习题如下:

  刚拿到题目觉得这题目似乎和递归分治没有什么关系,但是O(1)的空间复杂度,以及O(n)的时间复杂度度就限制了解决方法,也就是分治和递归。(使用python语言只需几行,用切片即可完成,这里附上极其弱智的代码)

  def exchange(a,k):

  a=a[k:]+a[0:k]#列表切片

  return a

  ls=[1,2,3,4,5,6,7]

  print(exchange(ls,4))

  现在我们来思考这个递归分治算法。

  开始前先说明一下变量含义:

  start:左边子数组开始位置下标

  sep:分割位置下标(左边子数组结束位置下标)

  end:右边子数组结束位置下标

  首先,是最简单的情况,相信大家一定能想到,如果两个子数组长度相等,直接遍历子数组的长度,写上三行交换代码就可以解决了。(在这就不给出图例了,简单脑补一下即可)

  接下来,就是剩余两种情况:分别是左边子数组长度>右边子数组长度以及左边子数组长度<右边子数组长度。我的基本想法就是长度小的一边可以直接交换到位,长度长的一边分成两部分,一部分就是长度短的子数组长度,另一部分就是剩余部分长度。即:

  

递归与分治算法练习

  长数组用和短数组相同长度的元素和短数组元素一一交换,长数组剩余元素不动。第一次交换完成后短数组已经直接到位,接下来处理剩余元素长度即可,从而问题规模缩小,使用分治递归可以解决。

  下面图例都是以这个数组为例{1,2,3,4,5,6,7}(红色字体表示已经到位的元素)

  图一(start=0,sep=4,end=6):

  判断是左边大于右边;长度为2的两对交换。1,2和6,7互换位置;6,7到位。start前进2位(start=2),sep不变,end也不变。

  判断是左边大于右边;1,2和6,7互换位置;6,7,1,2到位。start再前进2位(start=4),sep不变,end也不变。

  判断是左边小于右边;5和3互换位置;6,7,1,2,3到位。start前进1位(start=5),sep增1(sep=5),end不变。

  判断是左边等于右边;5和4直接交换位置,所有元素全部到位。

  图二(start=0,sep=1,end=6):

  判断是左边小于右边;长度为2的两对交换。1,2和3,4互换位置;3,4到位。start前进2位(start=2),sep前进1位(sep=3),end也不变。

  判断是左边小于右边;1,2和5,6互换位置;3,4,5,6到位。start再前进2位(start=4),sep前进2位(sep=5),end也不变。

  判断是左边大于右边;5和3互换位置;6,7,1,2,3到位。start前进1位(start=5),sep增1(sep=5),end不变。

  判断是左边等于右边;2和1直接交换位置,所有元素全部到位。

  接下来是代码呈现:

  public static void exchange(int a[],int start,int sep,int end)

  { 郑州妇科医院 http://www.zyfuke.com/

  int t;

  // 左边子数组长度 = 右边子数组长度

  if(end-sep==sep-start+1)

  {

  for (int i = start; i <=sep; i++)

  {

  t=a[i];

  a[i]=a[i+sep-start+1];

  a[i+sep-start+1]=t;

  }

  }

  // 左边子数组长度 > 右边子数组长度

  if(end-sep

  {

  for(int i=end;i>=sep+1;i--)

  {

  t=a[i];

  a[i]=a[i-(sep-start+1)];

  a[i-(sep-start+1)]=t;

  }

  // start=start+end-sep;

  exchange(a, start+end-sep, sep, end);

  //递归调用exchange方法

  // exchange(a, start, sep, end);

  }

  // 左边子数组长度 < 右边子数组长度

  if(end-sep>sep-start+1)

  {

  for(int i=start;i<=sep;i++)

  {

  t=a[i];

  a[i]=a[i+sep-start+1];

  a[i+sep-start+1]=t;

  }

  // start=sep+1;

  // sep=sep+sep-start+1;

  exchange(a, sep+1, sep+sep-start+1, end);

  //递归调用exchange方法

  exchange(a, start, sep, end);

  }

  }

  左边子数组长度 >右边子数组长度:

  左右两边交换,中间不动,交换后左边部分完成,右边递归,*start前进短的子数组的长度个单位,*短的子数组长度=end-sep,所以有start=start+end-sep;sep不变,end也不变。

  左边子数组长度 <右边子数组长度:

  左边中间交换,右边不动,交换后左边部分完成,右边递归,start前进短的子数组的长度个单位,短的子数组长度=sep-start+1,所以有start=start+sep-start+1=sep+1。sep也前进短子数组长度个单位,sep=sep+sep-start+1;end不变。

  测试:

  int a[]= {10,2,8,3,5,4,7,1};

  ...

  exchange(a, 0,4,a.length-1);

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI