1.力扣48旋转图像
旋转图像:顺时针旋转图像90度
step1.先将这个n*n矩阵按照对角线(从左上角到右下角的对角线,而非从右上角到左下角的对角线)进行对称。比如第一行经过对称就变成第一列
沿对角线对称的代码:
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
int temp=nums[i][j];
nums[i][j]=nums[j][i];
nums[j][i]=temp;
}
}
这里之所以 j 从 i 开始,表示的是蓝色线那部分(每一行的对角线元素和对角线元素右边的那部分元素)
step2:再对矩阵的每一行进行反转
比如第一行是1,5,7,4,经过反转就变成了4,7,5,1
经过这两步发现矩阵已经顺时针旋转90度了
代码实现如下:
class Solution
{
public void rotate(int[][] nums)
{
//这道题要求是原地旋转,不能用另一个新的矩阵在装旋转后的矩阵
//求出这个方形矩阵的边长(长和宽相等)
int n=nums.length;
//第一步:先沿对角线进行对称
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
int temp=nums[i][j];
nums[i][j]=nums[j][i];
nums[j][i]=temp;
}
}
//第二步:每一行进行对称
//取出这个matric矩阵的每一行
for(int i=0;i<n;i++)
{
int p=0,q=n-1;
while(p<q)
{
int temp=nums[i][p];
nums[i][p]=nums[i][q];
nums[i][q]=temp;
p++;
q--;
}
}
}
}
2.力扣54 螺旋矩阵
按照顺时针的顺序返回二维数组中的所有元素
class Solution
{
public List<Integer> spiralOrder(int[][] nums)
{
int m=nums[0].length; //矩阵长度
int n=nums.length;//矩阵宽度
//定义四个边界
//注意这里m,n的位置不要写反了,很容易出错
int left=0; //左边界在第几列
int right=m-1; //右边界在第几列
int up=0; //上边界在第几行
int down=n-1;//下边界在第几行
List<Integer> result=new ArrayList();
//把m*n个元素全部添加到result
while(result.size()<m*n)
{
//要求是顺时针旋转,所以依次添加上边界,右边界,下边界,左边界的数
//添加上边界的数
if(up<=down)
{
for(int temp=left;temp<=right;temp++)
{
result.add(nums[up][temp]);
}
//上边界下移
up++;
}
//添加右边界的数
if(left<=right)
{
for(int temp=up;temp<=down;temp++)
{
result.add(nums[temp][right]);
}
//右边界左移
right--;
}
//添加下边界的数
if(up<=down)
{
for(int temp=right;temp>=left;temp--)
{
result.add(nums[down][temp]);
}
//下边界上移
down--;
}
//添加左边界的数
if(left<=right)
{
for(int temp=down;temp>=up;temp--)
{
result.add(nums[temp][left]);
}
//左边界右移
left++;
}
}
return result;
}
}
生成螺旋矩阵
用up,down,left,right来标记上下左右边界
初始时候:up=0,down=n-1,left=0,right=n-1;
按照先从左到右,然后从上到下,然后从右到左,然后从下到上
从左到右完,上边界就要下移,+1
从上到下完,右边界就要左移,-1
从右到左完,下边界就要上移,-1
从下到上完,左边界就要左移,+1
还有一个问题是:nums[i][j] 怎么确定二维数组的两个下标是多少,也就是如何确定现在填数填到哪里了,填的都是边界上的位置
比如你 从左到右,那一定是上边界不动,然后i在移动,然后上边界下移+1
从上到下,一定是右边界不动,然后i在移动,然后右边界左移-1
从右到左,一定是下边界不懂,然后i在移动,然后下边界-1
从下到上,一定是左边界不懂,然后i在移动,然后左边界+1
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums=new int[n][n];
int up=0,down=n-1,left=0,right=n-1;
int count=1;
while(count<=n*n)
{
for(int i=left;i<=right;i++)//左到右
{
nums[up][i]=count;
count++;
}
up++;//上边界往下移
for(int i=up;i<=down;i++)//上到下
{
nums[i][right]=count;
count++;
}
right--;//右边界往左移
for(int i=right;i>=left;i--)//右到左
{
nums[down][i]=count;
count++;
}
down--; //下边界上移
for(int i=down;i>=up;i--)//下到上
{
nums[i][left]=count;
count++;
}
left++;//左边界右移
}
return nums;
}
}
而荣耀的笔试题几乎完全一样
在nxn方阵里填入1,2,.,nxn,要求填成蛇形。元素1从右上角开始,顺时针排列,例如,n=4时
只需要改变一下遍历顺序就可以,遍历顺序由
先从左到右,然后从上到下,然后从右到左,然后从下到上
变成:
然后从上到下,然后从右到左,然后从下到上,再从左到右
只需要将上面的代码顺序调换一下就行
public class test4
{
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int[][] nums=new int[n][n];
int up=0,down=n-1,left=0,right=n-1;
int count=1;
while(count<=n*n) {
for (int i = up; i <= down; i++)//上到下
{
nums[i][right] = count;
count++;
}
right--;//右边界往左移
for (int i = right; i >= left; i--)//右到左
{
nums[down][i] = count;
count++;
}
down--; //下边界上移
for (int i = down; i >= up; i--)//下到上
{
nums[i][left] = count;
count++;
}
left++;//左边界右移
for (int i = left; i <= right; i++)//左到右
{
nums[up][i] = count;
count++;
}
up++;//上边界往下移
}
for(int i=0;i<n;i++)
{
for (int j = 0; j < n; j++) {
System.out.print(nums[i][j]+" ");
}
System.out.println();
}
}
}
4.力扣2022 将一维数组转变成二维数组
class Solution
{
public int[][] construct2DArray(int[] original, int m, int n)
{
if(original.length!=m*n)
{
int[][] result=new int[0][0];
return result;
}
int[][] result=new int[m][n];
int index=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
result[i][j]=original[index];
index++;
//或者这里可以这样写:result[i][j]=original[i*n+j];一行有n个元素
//这里也可以不用两重循环,而是一重循环,遍历original数组
/*for(int i=0;i<original.length;i++)
{
res[i/n][i%n] = original[i];
}
*/
}
return result;
}
}
5.力扣240 搜索二维数组||
从最左下角的数开始:
如果target比这个数小,就去这个数的上面(比这个数小的区域找)
如果target比这个数大 ,就去这个数的右边(比这个数大的区域找)
终止条件就是索引超出边界
class Solution
{
public boolean searchMatrix(int[][] nums, int target)
{
int m=nums.length;
//这里可能需要判断一下m是否等于0,因为下面有nums[0],如果nums数组的长度为0,就不存在nums[0]
int n=nums[0].length;
//从左下角开始出发
int x=m-1;
int y=0;
//横坐标最小为0,纵坐标最大为n-1
while(x>=0&&y<=n-1)
{
//比target小,那就去右边更大的区域找
if(nums[x][y]<target)
{
y++;
}
//比target大,就往上面更小的区域找
else if(nums[x][y]>target)
{
x--;
}
else
{
return true;
}
}
return false;
}
}
或者是从右上角出发(但是不能从左上角和右下角出发)
这道题也可以在每一行中用二分查找
6.返回最多1的是哪一行
这个二维矩阵的特点是每一行左边全0,右边全1
从第一行的最后一个元素出发,一直往左移动,找到第一个不为1的数为止,记录下此时最多1的个数为4,行数为0
然后此时直接横坐标+1,纵坐标不变去下一行
6. 力扣 2482 求差值矩阵
class Solution
{
//给定一个1-0矩阵,求差值矩阵
//每个位置的值等于:行1的个数+列1的个数-行0的个数-列0的个数
//改写成行1的个数-行0的个数+列1的个数-列0的个数
//=行1的个数-(列数-行1的个数)+列1的个数-(行数-列1的个数)
//=2*行1的个数-列数+2*列1的个数-行数
public int[][] onesMinusZeros(int[][] grid)
{
int n=grid.length;//行数
int m=grid[0].length;//列数
//求出每一行1的个数:
int[] nums1=new int[n];
//求出每一列1的个数
int[] nums2=new int[m];
for(int i=0;i<n;i++)
{
int sum=0;
for(int j=0;j<m;j++)
{
if(grid[i][j]==1)
{
sum++;
}
}
nums1[i]=sum;
}
for(int i=0;i<m;i++)
{
int sum=0;
for(int j=0;j<n;j++)
{
if(grid[j][i]==1)
{
sum++;
}
}
nums2[i]=sum;
}
int[][] result=new int[n][m];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
//第i行第j列=行1的个数-行0的个数+列1的个数-列0的个数=2*行1的个数-列数+2*列1的个数-行数
result[i][j]=2*nums1[i]+2*nums2[j]-m-n;
}
}
return result;
}
}
简化代码:
class Solution
{
//给定一个1-0矩阵,求差值矩阵
//每个位置的值等于:行1的个数+列1的个数-行0的个数-列0的个数
//改写成行1的个数-行0的个数+列1的个数-列0的个数
//=行1的个数-(列数-行1的个数)+列1的个数-(行数-列1的个数)
//=2*行1的个数-列数+2*列1的个数-行数
public int[][] onesMinusZeros(int[][] grid)
{
int n=grid.length;//行数
int m=grid[0].length;//列数
//求出每一行1的个数:
int[] nums1=new int[n];
//求出每一列1的个数
int[] nums2=new int[m];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(grid[i][j]==1)
{
nums1[i]++;
nums2[j]++;
}
}
}
int[][] result=new int[n][m];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
//第i行第j列=行1的个数-行0的个数+列1的个数-列0的个数=2*行1的个数-列数+2*列1的个数-行数
result[i][j]=2*nums1[i]+2*nums2[j]-m-n;
}
}
return result;
}
}