问题如下描述:
In MATLAB, there is a very useful function called 'reshape', which can reshape a matrix into a new one with different size but keep its original data.
You're given a matrix represented by a two-dimensional array, and two positive integers r and c representing the row number and column number of the wanted reshaped matrix, respectively.
The reshaped matrix need to be filled with all the elements of the original matrix in the same row-traversing order as they were.
If the 'reshape' operation with given parameters is possible and legal, output the new reshaped matrix; Otherwise, output the original matrix.
Example 1:
Input: nums = [[1,2], [3,4]] r = 1, c = 4 Output: [[1,2,3,4]] Explanation:
The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, fill it row by row by using the previous list.
Example 2:
Input: nums = [[1,2], [3,4]] r = 2, c = 4 Output: [[1,2], [3,4]] Explanation:
There is no way to reshape a 2 * 2 matrix to a 2 * 4 matrix. So output the original matrix.
Note:
- The height and width of the given matrix is in range [1, 100].
- The given r and c are all positive.
- 首先要判断数组包含的元素的数目和所要变换的矩阵的行列成绩是否相等,如果不相等, 直接输出原数组,这里还要判断输入数组是不是一个空数组。
- 如果相等的话,就把原数组的所有元素都取出来放到一个数组newlist里。
- 根据所要新建的矩阵的行r,建立一个包含r个元素的数组finalist。
- 然后根据所要新建的矩阵的列c,把newlist的元素按组分片,比如:newlist[0,c],newlist[c,2c],newlist[2c,3c],,,new[(r-1)c,rc],分别赋值给finallist[0],finallist[1],,,finallist[r-1].
- 最后返回finallist,得到最终的结果。
方法一: runtime:32ms
class Solution(object): def matrixReshape(self, nums, r, c): """ :type nums: List[List[int]] :type r: int :type c: int :rtype: List[List[int]] """ nums_r = len(nums) nums_c = len(nums[0]) newlist = [] finallist = range(r) for i in xrange(nums_r): # for j in xrange(nums_c): newlist.append(nums[i][j]) if (nums_r * nums_c != r * c)|(len(nums)==0): return nums else: for i in xrange(r): finallist[i] = newlist[i * c:(i + 1) * c] return finallist
方法二:runtime:32ms
class Solution(object): def matrixReshape(self, nums, r, c): """ :type nums: List[List[int]] :type r: int :type c: int :rtype: List[List[int]] """ nums_r = len(nums) nums_c = len(nums[0]) newlist = [] finallist = range(r) for i in xrange(nums_r): newlist.extend(nums[i])if (nums_r * nums_c != r * c)|(len(nums)==0):return nums else: for i in xrange(r): finallist[i] = newlist[i * c:(i + 1) * c] return finallist
方法三:这是根据官方给出的第二种Java方法改的,不需要额外数组空间来放置所有的元素。
class Solution(object): def matrixReshape(self, nums, r, c): """ :type nums: List[List[int]] :type r: int :type c: int :rtype: List[List[int]] """ nums_r = len(nums) nums_c = len(nums[0]) #newlist = [] rows = 0 cols = 0 finallist = range(r) for i in xrange(r): finallist[i]=range(c) #for i in xrange(len(nums)): # newlist.extend(nums[i]) if ((nums_r== 0)|nums_r * nums_c != r * c): return nums for i in xrange(nums_r): for j in xrange(nums_c): #finallist[i]=[] finallist[rows][cols]=nums[i][j] cols+=1 if cols==c: cols=0 rows+=1 #finallist[i] = newlist[i * c:(i + 1) * c] return finallist
总结:还是那个问题,自己的基础薄弱。就拿这题来说,你必须对Python中列表的基本方法了熟于心 ,最基本的操作必须要知道,然后才能根据自己想的算法按步骤写出代码。写代码,想提高性能,就要从降低时间复杂度和内存占用空间为目标,尽可能的增加效率。同时还要把代码可能遇到的所有情况都要考虑进去,比如这题,我没有考虑给定的原数组为空数组,就少了一个判定条件(当然在本题中,题目明确说不会给出空的数组,而且r和c的值必须为整数,所以不需要考虑空数组情况)。
还有,这题还有没有别的方法?我看LeetCode给出的三个方法,用Java写的,其中有一个方法是不需要把原数组所有的元素提出来放到一个新的数组的,直接在原数组上操作,把元素赋值给要新建的数组。我有机会用Python尝试一下这种方法,看能不能实现。
LeetCode给出的方法,用Java写的:
方法一:
Approach #1 Using queue [Accepted]
Algorithm
The simplest method is to extract all the elements of the given matrix by reading the elements in a row-wise fashion. In this implementation, we use a queue to put the extracted elements. Then, we can take out the elements of the queue formed in a serial order and arrange the elements in the resultant required matrix in a row-by-row order again.
The formation of the resultant matrix won't be possible if the number of elements in the original matrix isn't equal to the number of elements in the resultant matrix.
Java
public class Solution { public int[][] matrixReshape(int[][] nums, int r, int c) { int[][] res = new int[r][c]; if (nums.length == 0 || r * c != nums.length * nums[0].length) return nums; int count = 0; Queue < Integer > queue = new LinkedList < > (); for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums[0].length; j++) { queue.add(nums[i][j]); } } for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { res[i][j] = queue.remove(); } } return res; } }
Complexity Analysis
-
Time complexity : O(m∗n). We traverse over m∗n elements twice. Here, m and n refer to the number of rows and columns of the given matrix respectively.
-
Space complexity : O(m∗n). The queue formed will be of size m∗n.
Approach #2 Without using extra Space [Accepted]
Algorithm
Instead of unnecessarily using the queue as in the brute force approach, we can keep putting the numbers in the resultant matrix directly while iterating over the given matrix in a row-by-row order. While putting the numbers in the resultant array, we fix a particular row and keep on incrementing the column numbers only till we reach the end of the required columns indicated by c. At this moment, we update the row index by incrementing it and reset the column index to start from 0 again. Thus, we can save the space consumed by the queue for storing the data that just needs to be copied into a new array.
Java
public class Solution { public int[][] matrixReshape(int[][] nums, int r, int c) { int[][] res = new int[r][c]; if (nums.length == 0 || r * c != nums.length * nums[0].length) return nums; int rows = 0, cols = 0; for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums[0].length; j++) { res[rows][cols] = nums[i][j]; cols++; if (cols == c) { rows++; cols = 0; } } } return res; } }
Complexity Analysis
-
Time complexity : O(m∗n). We traverse the entire matrix of size m∗n once only. Here, m and n refers to the number of rows and columns in the given matrix.
-
Space complexity : O(m∗n). The resultant matrix of size m∗n is used.
Approach #3 Using division and modulus [Accepted]
Algorithm
In the last approach, we needed to keep a track of when we reached the end of columns for the resultant matrix and needed to update the current row and column number for putting the extracted elements by checking the current indices every time. Instead of doing these limit checks at every step, we can make use of maths to help ease the situation.
The idea behind this approach is as follows. Do you know how a 2-D array is stored in the main memory(which is 1-D in nature)? It is internally represented as a 1-D array only. The element nums[i][j] of nums array is represented in the form of a one dimensional array by using the index in the form: nums[n∗i+j], where m is the number of columns in the given matrix. Looking at the same in the reverse order, while putting the elements in the elements in the resultant matrix, we can make use of a count variable which gets incremented for every element traversed as if we are putting the elements in a 1-D resultant array. But, to convert the count back into 2-D matrix indices with a column count of c, we can obtain the indices as res[count/c][count%c] where count/c is the row number and count%c is the coloumn number. Thus, we can save the extra checking required at each step.
Java
public class Solution { public int[][] matrixReshape(int[][] nums, int r, int c) { int[][] res = new int[r][c]; if (nums.length == 0 || r * c != nums.length * nums[0].length) return nums; int count = 0; for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums[0].length; j++) { res[count / c][count % c] = nums[i][j]; count++; } } return res; } }
Complexity Analysis
-
Time complexity : O(m∗n). We traverse the entire matrix of size m∗n once only. Here, m and n refers to the number of rows and columns in the given matrix.
-
Space complexity : O(m∗n). The resultant matrix of size m∗n is used.