题目及测试
package pid059;
import java.util.Arrays;
/* 338. 比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
进阶:
给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。
*/
public class main {
public static void main(String[] args) {
int[] testTable = {2,5};
for (int i=0;i<testTable.length;i++) {
test(testTable[i]);
}
}
private static void test(int ito) {
Solution solution = new Solution();
int[][] rtn;
long begin = System.currentTimeMillis();
System.out.print(ito+" ");
System.out.println();
rtn = solution.generateMatrix(ito);//执行程序
long end = System.currentTimeMillis();
System.out.println("rtn=" );
for (int i = 0; i < rtn.length; i++) {
System.out.println(Arrays.toString(rtn[i]));
}//打印结果几数组
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(成功,0ms,极快)
可以将矩阵看成若干层,首先填入矩阵最外层的元素,其次填入矩阵次外层的元素,直到填入矩阵最内层的元素。
定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1 层,次外层元素都是第 2 层,最内层元素都是第 3 层。
[[1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 1],
[1, 2, 3, 3, 2, 1],
[1, 2, 3, 3, 2, 1],
[1, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 1]]
对于每层,从左上方开始以顺时针的顺序填入所有元素。假设当前层的左上角位于 (top,left),右下角位于 (bottom,right),按照如下顺序填入当前层的元素。
从左到右填入上侧元素,依次为 (top,left) 到 (top,right)。
从上到下填入右侧元素,依次为 (top+1,right) 到 (bottom,right)。
如果 left<right 且 top<bottom,则从右到左填入下侧元素,依次为 (bottom,right−1) 到 (bottom,left+1),以及从下到上填入左侧元素,依次为 (bottom,left) 到 (top+1,left)。
填完当前层的元素之后,将 left 和 top 分别增加 1,将 right 和 bottom 分别减少 1,进入下一层继续填入元素,直到填完所有元素为止。
package pid059;
class Solution {
public int[][] generateMatrix(int n) {
int[][] result=new int[n][n];
if(n==1){
result[0][0]=1;
return result;
}
int begin=1;
for(int i=0;i<n/2;i++){
createCircle(result, i, i, n-1-2*i, begin);
begin = begin+4*(n-1-2*i);
}
if(n%2==1){
result[n/2][n/2]=begin;
}
return result;
}
private void createCircle(int[][] result,int i,int j,int span,int begin){
for(int k=0;k<span;k++){
result[i][j+k]=begin;
begin++;
}
j=j+span;
for(int k=0;k<span;k++){
result[i+k][j]=begin;
begin++;
}
i=i+span;
for(int k=0;k<span;k++){
result[i][j-k]=begin;
begin++;
}
j=j-span;
for(int k=0;k<span;k++){
result[i-k][j]=begin;
begin++;
}
i=i-span;
}
}
解法2(别人的)
模拟矩阵的生成。按照要求,初始位置设为矩阵的左上角,初始方向设为向右。若下一步的位置超出矩阵边界,或者是之前访问过的位置,则顺时针旋转,进入下一个方向。如此反复直至填入 n^2个元素。
记 matrix 为生成的矩阵,其初始元素设为 0。由于填入的元素均为正数,我们可以判断当前位置的元素值,若不为 0,则说明已经访问过此位置。
class Solution {
public int[][] generateMatrix(int n) {
int maxNum = n * n;
int curNum = 1;
int[][] matrix = new int[n][n];
int row = 0, column = 0;
int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上
int directionIndex = 0;
while (curNum <= maxNum) {
matrix[row][column] = curNum;
curNum++;
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] != 0) {
directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向
}
row = row + directions[directionIndex][0];
column = column + directions[directionIndex][1];
}
return matrix;
}
}

1414

被折叠的 条评论
为什么被折叠?



