向量旋转算法
2015-10-15 20:54
483 查看
最近看《编程珠玑》,里面提到了一个常见的向量旋转问题,是指将一个数按照某点前后置换,比如【1,2,3,4,5,6,7,8,9,10】按照4旋转后,就变成了【5,6,7,8,9,10,1,2,3,4】。
之前在leetcode上也看到了这个问题,当时觉得很简单,就是把前i个数存起来,然后将后面的数据向前移动,然后在把存起来的前i个数加在后面。
《编程珠玑》上提到了两种算法,非常高效,时间复杂度为O(n),空间复杂度为O(1)。
代码1:
描述的算法的思路是:将num[0]保存起来,然后num[0] = num[i % size],num[i % size] = num[2*i % size],,,直到进行到这样一点待保存的数正好为num[0],然后将之前保存的临时值赋给它。如果此时,数组中所有的值都已经被遍历了一遍,那么退出循环,否则从num[1]重新开始循环。
这里有三个问题:
1、为什么这个算法是有效的?我不知道;
2、为什么一定会出现num[k * i % size] = 0的情况。因为当k足够大,比如k == size时,一定会等于0。实际上k的最大值是有讲究的。当满足条件时,一定是k*i = i和size的最小公倍数。因为最小公倍数 乘 最大公约数为 = i*size;所以等式两边变成了 k*i*gcd(i,size) = i*size;所以k*gcd = size;
这也就回答了下面问题:
3、要循环几次才会退出循环过程?答案是gcd次。
算法2:
这个算法非常美妙,它将前i个值进行翻转,将后面的n-i个值翻转,然后总体再翻转一次,完成向量旋转了。
该算法时间复杂度为O(2*n),不占用额外空间。
之前在leetcode上也看到了这个问题,当时觉得很简单,就是把前i个数存起来,然后将后面的数据向前移动,然后在把存起来的前i个数加在后面。
《编程珠玑》上提到了两种算法,非常高效,时间复杂度为O(n),空间复杂度为O(1)。
代码1:
int gcd(int a, int b) { int c; while ((c = a%b) != 0) { a = b; b = c; } return b; } void rotate1(int* nums, int size,int rotateLen) { int times = gcd(rotateLen, size); for (int i = 0; i < times; i++) { int val = nums[i]; int cur = i; int next = i + rotateLen; while (next % size != i) { nums[cur] = nums[next % size]; cur = next % size; next += rotateLen; } nums[cur] = val; } }
描述的算法的思路是:将num[0]保存起来,然后num[0] = num[i % size],num[i % size] = num[2*i % size],,,直到进行到这样一点待保存的数正好为num[0],然后将之前保存的临时值赋给它。如果此时,数组中所有的值都已经被遍历了一遍,那么退出循环,否则从num[1]重新开始循环。
这里有三个问题:
1、为什么这个算法是有效的?我不知道;
2、为什么一定会出现num[k * i % size] = 0的情况。因为当k足够大,比如k == size时,一定会等于0。实际上k的最大值是有讲究的。当满足条件时,一定是k*i = i和size的最小公倍数。因为最小公倍数 乘 最大公约数为 = i*size;所以等式两边变成了 k*i*gcd(i,size) = i*size;所以k*gcd = size;
这也就回答了下面问题:
3、要循环几次才会退出循环过程?答案是gcd次。
算法2:
void reverse(int *nums,int start, int end) { while (start < end) { int val = nums[start]; nums[start] = nums[end]; nums[end] = val; start++; end--; } } void rotate2(int* nums, int size,int rotateLen) { if (rotateLen >= size || rotateLen < 0) return; reverse(nums,0, rotateLen - 1); reverse(nums,rotateLen, size - 1); reverse(nums,0, size - 1); }
这个算法非常美妙,它将前i个值进行翻转,将后面的n-i个值翻转,然后总体再翻转一次,完成向量旋转了。
该算法时间复杂度为O(2*n),不占用额外空间。
相关文章推荐
- android 文件上传到服务器
- 浅谈Builder设计模式
- Android-Fragment
- 《剑指Offer》面试题:不使用加减乘除做加法运算
- 多条件查询
- Android服务之信使应用之二
- cloudstack management与agent交互
- usbredir-0.7内容详解(二)
- poj1703 find them,catch them
- fpga闪烁的led灯
- 26.Struts2文件下载并在下载文件之前进行权限检查
- 淘宝异构数据源数据交换工具 DataX
- 移动端Web框架
- hmmer 使用
- lintcode :搜索二维矩阵
- opencv2.4.9 + vs2013 之 blobtrack 调试
- 接口
- xcode APP 打包以及提交apple审核详细流程(新版本更新提交审核)
- EasyUI datagrid checkbox数据设定与取值(转自http://blog.csdn.net/baronyang/article/dnetails/9323463,感谢分享,谢谢)
- #上海ORACLE用户组2014在论坛#时刻