矩阵原地转置算法
2015-12-19 11:05
281 查看
这个面试题要求现场写程序。
题目描述非常简单:给一个m*n的矩阵,要求实现矩阵的转置,不要额外开辟内存空间。
题目分析:
如果可以开辟额外内存空间,我们可以申请一个n*m的矩阵,然后挨个将矩阵元素放入转置之后的位置。但题目明确指出不能开辟额外内存空间,显然,最简单的实现就是,使用一个一维数组保存原来的矩阵(行优先,即一行一行的保存矩阵,其实在各个编译器中,这是最常见的保存方式),然后在这个一维数组上实现元素位置的变化。变化后,一行一行的读取一维数组时,读出的即是转置后的矩阵的行。下面举个栗子,看这个图,介绍了整个过程:
初始矩阵如下
这个矩阵中,每个数字的下标表示这个数字在一维数组中的保存序号。经过转置后,矩阵应该如下:
同样的,每个数字的下标表示这个数字在一维数组中保存的序号。虽然形象来看,转置后,矩阵应该这个样子,可是仍然按照一维数组保存和表示。大家脑海里应该都有这个影像。
通过这个栗子,我们可以看到,实际上,我们只需要对这个一维数组中的元素进行交换,即可达到目的。可是该怎么变换呢?
我们先来看看这些数字的位置是如何变化的。下面我们先把位置变化列举出来:
0 to 0 5 to 1 10 to 2
1 to 3 6 to 4 11 to 5
2 to 6 7 to 7 12 to 8
3 to 9 8 to 10 13 to 11
4 to 12 9 to 13 14 to 14
猛一看,这不是稍微有点规律吗!直接将0、1、2、3、4的数字分别移动到0、3、6、9、12,将5、6、7、8、9分别移动1、4、7、10、13,将10、11、12、13、14移动到2、5、8、11、14不就可以吗?但是存在一个问题,将1位置的数放入3位置,这样就会覆盖3位置原来的数字,3位置的数字是需要放到9的,而也不能提前将3位置的数放到9位置,因为9位置也有数,那个数需要放到13位置的。下面我们看看这是怎么样一个放置的过程:
1 to 3, 3 to 9, 9 to 13, 13 to 11, 11 to 5, 5 to 1
童鞋们,发现没有经过一个循环,最后又回到了1。这说明,其实变化的过程是个循环!如果按照这个顺序变化,肯定是不可以的了,因为要将1中的数组放到3,必须先将3中数字放入9,......,循环到最后,发现必须先将1中数字放入3才能解决5中数字的放置问题。
看到这个问题想到了什么?对!我们应该反着来,反个顺序移动!先将1中的数字放入临时变量,然后将5中的数字放入1,再将11中数字放入5,......,最后将1放入3位置。这样不就可以完美解决了吗?是的,然后再分别将2、3、4这几个数也按照刚才的流程变化位置。这样这个矩阵就完成了转置!
下面是我自己实现的一个简单实现的代码:
题目描述非常简单:给一个m*n的矩阵,要求实现矩阵的转置,不要额外开辟内存空间。
题目分析:
如果可以开辟额外内存空间,我们可以申请一个n*m的矩阵,然后挨个将矩阵元素放入转置之后的位置。但题目明确指出不能开辟额外内存空间,显然,最简单的实现就是,使用一个一维数组保存原来的矩阵(行优先,即一行一行的保存矩阵,其实在各个编译器中,这是最常见的保存方式),然后在这个一维数组上实现元素位置的变化。变化后,一行一行的读取一维数组时,读出的即是转置后的矩阵的行。下面举个栗子,看这个图,介绍了整个过程:
初始矩阵如下
这个矩阵中,每个数字的下标表示这个数字在一维数组中的保存序号。经过转置后,矩阵应该如下:
同样的,每个数字的下标表示这个数字在一维数组中保存的序号。虽然形象来看,转置后,矩阵应该这个样子,可是仍然按照一维数组保存和表示。大家脑海里应该都有这个影像。
通过这个栗子,我们可以看到,实际上,我们只需要对这个一维数组中的元素进行交换,即可达到目的。可是该怎么变换呢?
我们先来看看这些数字的位置是如何变化的。下面我们先把位置变化列举出来:
0 to 0 5 to 1 10 to 2
1 to 3 6 to 4 11 to 5
2 to 6 7 to 7 12 to 8
3 to 9 8 to 10 13 to 11
4 to 12 9 to 13 14 to 14
猛一看,这不是稍微有点规律吗!直接将0、1、2、3、4的数字分别移动到0、3、6、9、12,将5、6、7、8、9分别移动1、4、7、10、13,将10、11、12、13、14移动到2、5、8、11、14不就可以吗?但是存在一个问题,将1位置的数放入3位置,这样就会覆盖3位置原来的数字,3位置的数字是需要放到9的,而也不能提前将3位置的数放到9位置,因为9位置也有数,那个数需要放到13位置的。下面我们看看这是怎么样一个放置的过程:
1 to 3, 3 to 9, 9 to 13, 13 to 11, 11 to 5, 5 to 1
童鞋们,发现没有经过一个循环,最后又回到了1。这说明,其实变化的过程是个循环!如果按照这个顺序变化,肯定是不可以的了,因为要将1中的数组放到3,必须先将3中数字放入9,......,循环到最后,发现必须先将1中数字放入3才能解决5中数字的放置问题。
看到这个问题想到了什么?对!我们应该反着来,反个顺序移动!先将1中的数字放入临时变量,然后将5中的数字放入1,再将11中数字放入5,......,最后将1放入3位置。这样不就可以完美解决了吗?是的,然后再分别将2、3、4这几个数也按照刚才的流程变化位置。这样这个矩阵就完成了转置!
下面是我自己实现的一个简单实现的代码:
public class App { public void rotateArray(int[] array, int rowNum, int columnNum) { int maxValue = -1; for (int i = 0; i < array.length; i++){ if (maxValue < array[i]){ maxValue = array[i]; } } maxValue += 1; for (int i = 0; i < array.length; i++) { if(array[i] >= maxValue){ continue; } int rowOri = i / columnNum, columnOri = i % rowNum; if (rowOri == columnOri) { array[i] += maxValue; continue; } int startRow = columnOri, startColumn = rowOri; int rowMoveTo = columnOri, columnMoveTo = rowOri; int newColumnNum = rowNum; int moveValue = array[i]; while(rowMoveTo != startColumn || columnMoveTo != startRow){ int offset = rowMoveTo * newColumnNum + columnMoveTo; int tmpValue = array[offset]; array[offset] = moveValue; array[offset] += maxValue; rowOri = offset / columnNum; columnOri = offset % columnNum; rowMoveTo = columnOri; columnMoveTo = rowOri; moveValue = tmpValue; } array[i] = moveValue + maxValue; } } }
相关文章推荐
- SQLServer跨服务器访问数据库(openrowset/opendatasource/openquery)
- Linux_指令杂烩
- juery实现粘贴复制
- [IOS]轻松理解UITableViewCell的重用机制
- Linux vmstat命令实战详解
- android:windowSoftInputMode属性
- 通过阅读Oracle Enterprise Asset Management User Guide,我对Oracle eAM的初步理解
- Ubuntu下压缩、解压缩rar文件
- linux 修改用户密码
- 关于驱动与编译器版本的查询命令
- PHP常用正则表达式汇总
- 获取手机本地的图片或者照相机照像的图片 为头像
- 优化SQLServer数据库加快查询速度
- 日经春秋 20151219
- 天声人語 20151219 手書きの年賀状
- callable,compile,eval,single,exec,递归
- C++类模板的定义
- xTaskCreate()
- java线程并发控制:ReentrantLock Condition使用详解
- 308. Range Sum Query 2D - Mutable