1、顺时针打印二维数组
package org.lanqiao.algo.elementary._04matrix;
/**
* 顺时针打印二维数组
输入
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
输出
1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10
*/
public class Case01_Print2DArr {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4, 100},
{5, 6, 7, 8, 101},
{9, 10, 11, 12, 102},
{13, 14, 15, 16, 103},
{104, 105, 106, 107, 103},
};
print(matrix);
}
static void print(int[][] matrix) {
int leftUpRow = 0, leftUpCol = 0, rightDownRow = matrix.length - 1, rightDownCol = matrix[0].length - 1;
while (leftUpRow <= rightDownRow && leftUpCol <= rightDownCol) {
int r = leftUpRow, c = leftUpCol;
//上面一条边
while (c <= rightDownCol) {
System.out.print(matrix[r][c++] + " ");
}
//恢复
c = rightDownCol;
r++;
//右边的一条边
while (r <= rightDownRow) {
System.out.print(matrix[r++][c] + " ");
}
//恢复
r = rightDownRow;
c--;
//下面一条边
while (c >= leftUpCol) {
System.out.print(matrix[r][c--] + " ");
}
// 恢复
c = leftUpCol;
r--;
while (r > leftUpRow) {
System.out.print(matrix[r--][c] + " ");
}
leftUpRow++;
leftUpCol++;
rightDownRow--;
rightDownCol--;
}
}
}
2、将0所在的行清0
package org.lanqiao.algo.elementary._04matrix;
import org.lanqiao.algo.util.Util;
public class Case02_ClearZeroIn2DArr {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4, 100},
{5, 6, 7, 0, 101},
{9, 0, 11, 12, 102},
{13, 14, 15, 16, 103},
{104, 105, 106, 107, 103},
};
solve(matrix);
Util.printMatrix(matrix);
}
static void solve(int[][] matrix) {
int M = matrix.length;
int N = matrix[0].length;
//记录哪些行出现了0
int[] rowRecord = new int[M];
//记录哪些列出现了0
int[] colRecord = new int[N];
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
if (matrix[i][j] == 0) {
rowRecord[i] = 1;
colRecord[j] = 1;
}
}
}
for (int row = 0; row < M; row++) {
for (int col = 0; col < N; col++) {
//当前的行或者列,被标记了,这个元素就应该变为0
if (rowRecord[row] == 1 || colRecord[col] == 1) {
matrix[row][col] = 0;
}
}
}
}
}
3、z型打印
例如 :
1 2 3 4
5 6 7 8
9 10 11 12
打印出来是1 2 5 9 6 3 4 7 10 11 8 12 (用模拟的方法)
class Main {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
print(matrix);
}
static void print(int[][] matrix) {
int rows = matrix.length-1;
int cols = matrix[0].length-1;
boolean l2r = true; //为true就是从左到右
int r = 0,c=0;
while (r<=rows && c<=cols){
if(l2r){ //走上坡的情况
System.out.print(matrix[r][c]+" ");
//如果在第一行的情况,只能往右走
if(r==0 && c<=cols){
l2r = !l2r; //把方向切换掉
c++;
continue;
}
else if(r>0 && c == cols){ //现在在最后一列
l2r = !l2r; //方向换掉
r++;
continue;
}else {
r--;
c++;
}
}else { //走下坡的情况
System.out.print(matrix[r][c]+" ");
if(c ==0 && r<=rows){
l2r = !l2r;
r++;
continue;
}
else if(r == rows && c<cols){
l2r = !l2r;
c++;
continue;
}else {
r++;
c--;
}
}
}
}
}
4、找出边界为1的最大子方阵
给定一个N×N的矩阵matrix 矩阵中只有0和1两种值,返回边框全是1的最大正方形边长长度
{0, 1, 1, 1, 1},
{0, 1, 0, 0, 1},
{0, 1, 0, 0, 1},
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 1}
打印出是4
思路:
一个一个枚举:
class test3{
public static void main(String[] args) {
int [][] a = {
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 0},
{0, 1, 1, 1, 1},
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 1}
};
int x = found(a);
System.out.println(x);
}
static int found(int [][]a){
int len = a.length;
int n = len;
while (n-->=0){
for(int i=0;i<n;i++){
if(i+n>len){
break;
}
l3:
for(int j=0;j<n;j++){
if(j+n>len){
break;
}
int r =i;
int c = j;
while (c<j+n){
if(a[r][c] ==0){
continue l3;
}c++;
}
c--;
while (r<i+n){
if(a[r][c] ==0){
continue l3;
}r++;
}
r--;
while (c>=j){
if(a[r][c]==0){
continue l3;
}c--;
}
c++;
while (r>=i){
if(a[r][c]==0){
continue l3;
}r--;
}
r++;
}
}
}
return n;
}
}
代码好像不太对?、思路没毛病 输出-2不知道咋回事??
优化::预处理法优化(生成打表的话都是从下面开始)
预处理优化的话可以在查找那里优化很多 要有辅助数组(二维数组里套着一位数组 所以是三维数组)
package org.lanqiao.algo.elementary._04matrix;
/**
* 给定一个N×N的矩阵matrix,在这个矩阵中,只有0和1两种值,返回边框全是1的最大正方形的边长长度。
例如:
{0, 1, 1, 1, 1},
{0, 1, 0, 0, 1},
{0, 1, 0, 0, 1},
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 1}
其中,边框全是1的最大正方形的大小是4*4,返回4
*/
public class Case04_MaxSquare {
public static void main(String[] args) {
int[][] A = {
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 0},
{0, 1, 1, 1, 1},
{0, 1, 1, 1, 1},
{0, 1, 0, 1, 1}
};
A = new int[][]{
{1, 1, 1, 1},
{1, 0, 0, 1},
{1, 1, 1, 1},
{1, 1, 0, 1},
};
generateHelpRec(A);
print(rec, A.length);
int res = solve(A);
System.out.println(res);
}
private static void print(int[][][] rec, int N) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(rec[i][j][0] + "," + rec[i][j][1] + "\t");
}
System.out.println();
}
}
/**
* 记录每个元素往右和往下有多少个连续的1
* @param A
*/
private static void generateHelpRec(int[][] A) {
int N = A.length;
rec = new int[N][N][2];
int row = N - 1;
//初始化最后一行
for (int j = N - 1; j >= 0; j--) {
int value = A[row][j];
if (value == 1) {
if (j == N - 1) {
rec[row][j][0] = 1;//右侧连续1的个数
} else {
//A的元素值为1,rec在这个位置的连续1的个数=右边位置的连续1的个数+1
rec[row][j][0] = rec[row][j + 1][0] + 1;
}
//最后一行的下方的1的连续数==1
rec[row][j][1] = 1;
}
}
row--;
for (int i = row; i >= 0; i--) {
for (int j = N - 1; j >= 0; j--) {
int value = A[i][j];
// 利用右边和下边已经生产的数据来推出现在这个位置上右侧和下方有多少个1
if (value == 1) {
if (j == N - 1)
rec[i][j][0] = 1;//右侧连续1的个数
else
rec[i][j][0] = rec[i][j + 1][0] + 1;
rec[i][j][1] = rec[i + 1][j][1] + 1;//向下连续1的个数
}
}
}
}
static int[][][] rec;
//O(n³)
private static int solve(int[][] A) {
int N = A.length;
int n = N;
while (n > 0) {
for (int i = 0; i < N; i++) {
if (i + n > N) break;
l3:
for (int j = 0; j < N; j++) {
if (j + n > N) break;
//
// //检查四个边
// int r = i, c = j;
// while (c < j + n) {
// if (A[r][c++] == 0) continue l3;
// }
// c--;
// while (r < i + n) {
// if (A[r++][c] == 0)
// continue l3;
// }
// r--;
// while (c >= j) {
// if (A[r][c--] == 0)
// continue l3;
// }
// c++;
// while (r >= i) {
// if (A[r--][c] == 0)
// continue l3;
// }
if (check(i, j, n))
return n;
}
}
n--;
}
return n;
}
//O(1的)
private static boolean check(int i, int j, int n) {
//左上角那个点往右数的1的数目要≥n
//左上角那个点往下数的1的数目要≥n
//右上角那个点往下数的1的数目要≥n
//左下角那个点往右数的1的数目要≥n
if (rec[i][j][0] >= n && rec[i][j][1] >= n && rec[i][j + n - 1][1] >= n && rec[i + n - 1][j][0] >= n)
return true;
return false;
}
}
5、子数组的最大累加和
×子数组不同于子序列,,数组必为连续
arr = [1,-2,3,5,-2,6,-1] 所有子数组[3,5,-2,6]可以累加出最大的和为12 所以返回12
思路:只要有正数,就把他留下来作为下一个的基础 我自己一直不会这个题的原因是总以为他是动态规划,,无法判断这个负值是加还是不加,
正确的纠正办法是:我想到的那里还没有做完这道题,,sum大于0就继续加,sum小鱼0了就把sum归0重新开始,,,max的值一直更新(被超越,就更新)
class test3{
public static void main(String[] args) {
int []arr ={1,-2,3,5,-2,6,-1};
int sum =arr[0];
int max = arr[0];
for(int i= 1;i<arr.length;i++){
if(sum>=0){
sum+= arr[i];
}else {
sum = arr[i];
}
if(sum>max){
max = sum;
}
}
System.out.println(max);
}
}
6、求子矩阵的最大累加和
给定matrix,返回子矩阵的最大累加和
-1 -1 -1
-1 2 2
-1 -1 -1
最大累加子矩阵 (子矩阵 中间不跳空就可以了) 这个复杂度也不低,,在n的三次方了
import java.util.Arrays;
class Main{
public static void main(String[] args) {
int [][]arr = {
{-1,-1,-1},
{-1,2,2},
{-1,-1,-1}
};
int m = arr.length;
int n = arr[0].length;
int max= 0; //这个可不太一定啊。,,历史上最大的子矩阵之和
int num = arr.length*(arr.length-1)/2;
int [] sum = new int[n];
int beginrow =0;
while (beginrow<m){
for(int i=beginrow;i<m;i++){
for(int j =0;j<n;j++){
sum[j] += arr[i][j];
}
int t = sub(sum);
if(t>max){
max =t;
}
// Arrays.fill(sum,0); //,为什么不在这里清掉sum我觉得是因为beginrow是已经有了数字,下一次不会从头开始加
}
Arrays.fill(sum,0); //int数组也可以用arrays。fill来填
beginrow++;
}
System.out.println(max);
}
static int sub(int []arr){
int sum =0;
int max = arr[0];
for(int i=0;i<arr.length;i++){
if(sum>0){
sum+= arr[i];
}
else {
sum = arr[i];
}
if(sum>max){
max= sum;
}
}
return max;
}
}
7、矩阵相乘
class test3{
static int[][] matrix(int a[][], int b[][]){
int x = a.length;
int y = b[0].length;
int c[][] = new int[x][y];
for(int i=0;i<x;i++){
for (int j =0;j<y;j++){
for (int k =0;k<b.length;k++){
c[i][j] += a[i][k]*b[k][j];
}
}
}
return c;
}
}
8、
描述
有一副由NxN矩阵表示的图像,这里每个像素用一个int表示,请编写一个算法,在不占用额外内存空间的情况下(即不使用缓存矩阵),将图像顺时针旋转90度。
给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵,保证N小于等于500,图像元素小于等于256。
样例输入
3
1 2 3
4 5 6
7 8 9
样例输出
7 4 1
8 5 2
9 6 3
9、
描述
给定一个NxN的整数矩阵,小Hi每次操作可以选择两列,将这两列中的所有数变成它的相反数。
小Hi可以进行任意次操作,他的目标是使矩阵中所有数的和尽量大。你能求出最大可能的和吗?
输入
第一行一个整数N。
以下N行,每行N个整数Aij。
对于30%的数据,2 ≤ N ≤ 10
对于100%的数据,2 ≤ N ≤ 200, -1000 ≤ Aij ≤ 1000
输出
最大可能的和
样例输入
4
-1 1 1 2
-2 -3 1 2
-3 -2 1 2
-4 -1 1 2
样例输出
27
import java.util.Arrays;
import java.util.Scanner;
class Teat48{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int [][]matrix = new int[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
matrix[i][j] =sc.nextInt();
}
}
int sum[] = new int[n];
for(int j=0;j<n;j++){//j是列
for (int i=0;i<n;i++){//i是行
sum[i] += matrix[j][i];
}
}
Arrays.sort(sum);
int jiahe[] = new int[n/2];
for(int k=0;k<=n/2;k+=2){
jiahe[k] = sum[k]+sum[k+1];
System.out.println(jiahe[k]);
if(jiahe[k]>0){
System.out.println(k);
break;
}
}
}
}
补题:
描述
给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该子矩阵中所有元素的和不超过K。
输入
第一行包含三个整数N、M和K。
以下N行每行包含M个整数,表示A。
对于40%的数据,1 <= N, M <= 10
对于100%的数据,1 <= N, M <= 250 1 <= K <= 2147483647 1 <= Aij <= 10000
输出
满足条件最大的子矩阵所包含的元素数目。如果没有子矩阵满足条件,输出-1。
样例输入
3 3 9
1 2 3
2 3 4
3 4 5
样例输出
4
这个代码超时,,过不了,,
思路:
这类矩阵题目,第一反应就是首先需要在O(mn)时间将矩阵内每个位置到左上角所构成的子矩阵包含的元素和求出来,一次从左上向右下求解,每次运算利用之前的信息来计算: a[i][j] = a[i-1][j] + a[i][j-1] - a[i-1][j-1] + a[i][j]; 做完这个处理之后,任意的子矩阵均可通过下边的公式在O(1)时间求出:
第i行到第j行、第p列到第q列构成的子矩阵则可由上一步预处理过的矩阵和 sum=a[j][q] + a[i-1][p-1] - a[j][p-1] - a[i-1][q];
import java.util.Scanner;
class Main{
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
Scanner sc = new Scanner(System.in);
int m =sc.nextInt();
int n = sc.nextInt();
int k =sc.nextInt();
int a[][] = new int[m+1][n+1];
int ans =0;
for(int i=1;i<=m;i++){
for(int j =1;j<=n;j++){
a[i][j] = sc.nextInt();
}
}
//第一行
for(int i=2; i<=n; i++){
a[1][i] = a[1][i-1] + a[1][i];
}
//第一列
for(int j=2; j<=m; j++){
a[j][1] = a[j-1][1] + a[j][1];
}
for(int i=2; i<=n; i++)
for(int j=2; j<=m; j++)
a[i][j] = a[i-1][j] + a[i][j-1] - a[i-1][j-1] + a[i][j];
for(int i=1;i<=m;i++){
for(int j=i;j<=n;j++){
for(int q = 1;q<=m;q++){
for(int p=1;p<=q;p++){
int sum = a[j][q] + a[i-1][p-1] - a[j][p-1] - a[i-1][q]; //矩阵 i, j, p, q
if (sum <= k)
{
ans = Math.max(ans, (j-i+1)*(q-p+1));
}
}
}
}
}
if(ans ==0){
System.out.println(-1);
}else {
System.out.println(ans);
}
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
}
}