来啃硬骨头——各种矩阵相关的题 c++

被这道题折磨了一上午,解法好想,但是扣边界真的是太!恶!心!了!!!!!!!!

于是乎我决定把所有矩阵相关扣边界的题都挖过来,就是干!

先来看看折磨我一上午的小妖精

题目一——zigzag方式打印矩阵

用zigzag的方式打印矩阵,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
打印顺序为:0 1 4 8 5 2 3 6 9 10 7 11

我的问题主要出在了变量名上,二维数组a[i][j]里面,i是行,对应了直角坐标里面的y,j是列,对应了直角坐标里面的x。以后二维矩阵的题,我变量名都取行列吧,再也不取xy了,绕晕了,啊啊啊啊啊。

思路:

用两个指针A和B,用(xa,ya)表示A的位置,(xb,yb)表示B的位置。依次移动这两个指针,使得他们每次都处在一条斜线上。置于来回打印,可以用一个bool变量来控制打印方向即可。

上代码。

代码里还是有很多边界需要考虑的,比如print函数里面的while循环,两个变量的比较顺序放反了,就会导致你少打印点东西,具体例子看代码的注释

/*
用zigzag的方式打印矩阵,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
打印顺序为:0 1 4 8 5 2 3 6 9 10 7 11
*/
#include<iostream>
#include<vector>
using namespace std;

void helper(vector<vector<int>>&num, int av, int ah, int bv, int bh, bool flag){
	//打印顺序,先左上(flag=true时),后右下(flag=false时)
	if(!flag){
		//向左下方打印(坐标和二维矩阵的是不一样的,阿西吧)
		//从(0,2)走到(2,0)
		while(ah!=bh-1)
			cout<<num[av++][ah--]<<endl;
	}else{
		//向左上方打印
		//从(1,0)到(0,1)
		while(bv!=av-1)
			cout<<num[bv--][bh++]<<endl;
	}
}

void Print(vector<vector<int>>&num){
	if(num.size()==0) return;

	int  av=0, ah=0, bv=0, bh=0;
	bool flag=true;
	int hor=num[0].size()-1, ver=num.size()-1;

	while(av!=(ver+1)){
		helper(num, av, ah, bv, bh, flag);
		//av为什么写在ah的上面?思考情况:
		//ah=hor-1时,如果ah写在上面,则ah=ah+1,此时ah=hor,
		//本来应该指向矩阵右上角的,结果av一看ah=hor了,就猥琐的执行了 av=av+1
		av=ah==hor?av+1:av;
		ah=ah==hor?ah:ah+1;

		bh=bv==ver?bh+1:bh;
		bv=bv==ver?bv:bv+1;
		flag=!flag;
	}
}

int main(){
	vector<vector<int>>num={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
	Print(num);
	return 0;
}

题目二——用螺旋的方式打印矩阵,比如如下的矩阵

用螺旋的方式打印矩阵,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
打印顺序为:0 1 2 3 7 11 10 9 8 4 5 6

不要跟着打印的线路走,宏观去看,每次都是打印最外面的一圈(如下图),所以可以设置两个点,一个指向矩形的左上角(ar和ac分别表示a行和a列),一个指向矩形的右下角。每次打印完一圈。就把左上角的向右下角移动一位,同理右上角的指针向左上角移动一位。

打印会遇到两个特殊情况

1、ar=br 即两个指针指向了同一行元素(例子看下侧实现代码的helper函数)

2、ac=bc 即两个指针指向了同一列元素(例子看下侧实现代码的helper函数)

对于这两种情况,在打印的时候要区分出来

#include<iostream>
#include<vector>
using namespace std;

void helper(vector<vector<int>>& matrix, 
		vector<int>&res, int ar, int ac, int br, int bc){
	//说明此时要打印一条水平线
	/*
	1234
	5678
	1234
	当打印中间的67的时候,会出现这种情况
	*/
	if(ar==br){
		while(ac<bc+1){
			res.push_back(matrix[ar][ac++]);
		}
	//此时打印一列的情况
	/*
	123
	456
	789
	123
	当打印中间的那一竖58的时候,会出现该种情况
	*/
	}else if(ac==bc){
		while(ar<br+1){
			res.push_back(matrix[ar++][ac]);
		}
	}else{
		int hor=ac, ver=ar;
		//打印上面的横向边框
		while(hor<bc){
			res.push_back(matrix[ar][hor++]);
		}
		//打印右侧的纵向边框
		while(ver<br){
			res.push_back(matrix[ver++][hor]);
		}
		//打印下方的横向边框
		while(hor>ac){
			res.push_back(matrix[ver][hor--]);
		}
		//打印左侧的竖向边框
		while(ar<ver){
			res.push_back(matrix[ver--][hor]);
		}
	}
}

vector<int> spiralOrder(vector<vector<int>>& matrix) {
	vector<int>res;
	if((matrix.size()==0)||(matrix[0].size()==0))  return res;

	int ar=0, ac=0, br=matrix.size()-1, bc=matrix[0].size()-1; 
	while(1){
		//打印边框的函数
		helper(matrix, res,ar,ac,br,bc);
		//打印之后移动指针,以便于打印内层的边框
		ar++;
		ac++;
		br--;
		bc--;
		if((ar>br)||(ac>bc)) break;
	}
	for(auto i:res)
		cout<<i<<" ";
	return res; 
}

int main(){
	vector<vector<int>>matrix={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
	spiralOrder(matrix);
	cout<<endl;
	return 0;
}

这题是leetcode 54题

上AC代码

class Solution {
public:
    void helper(vector<vector<int>>& matrix, 
            vector<int>&res, int ar, int ac, int br, int bc){
        //说明此时要打印一条水平线(ar=br的情况)
        if(ar==br){
            while(ac<bc+1){
                res.push_back(matrix[ar][ac++]);
            }
        }else if(ac==bc){
            while(ar<br+1){
                res.push_back(matrix[ar++][ac]);
            }
        }else{
            int hor=ac, ver=ar;
            while(hor<bc){
                res.push_back(matrix[ver][hor++]);
            }
            while(ver<br){
                res.push_back(matrix[ver++][hor]);
            }
            while(hor>ac){
                res.push_back(matrix[ver][hor--]);
            }
            while(ar<ver){
                res.push_back(matrix[ver--][hor]);
            }
        }
    }
    
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int>res;
        if((matrix.size()==0)||(matrix[0].size()==0))  return res;
        
        //设置两个角的坐标
        int ar=0, ac=0, br=matrix.size()-1, bc=matrix[0].size()-1; 
        while(1){
            helper(matrix, res,ar,ac,br,bc);
            ar++;
            ac++;
            br--;
            bc--;
            if((ar>br)||(ac>bc)) break;
        }
        return res; 
    }
};

题目三——给定一个正方形矩阵,只用有限几个变量,实现矩阵中每个位置的数顺时针转动

给定一个正方形矩阵,只用有限几个变量,实现矩阵中每个位置的数顺时针转动
90度,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
矩阵应该被调整为:
12 8 4 0
13 9 5 1
14 10 6 2
15 11 7 3

思路

还是要宏观,假设一行有k个元素,这个矩阵里面的所有元素可以分成 k-1 组,每组四个元素。前提,这个矩阵一定是正方形,不是正方形你没办法转。对应的第 i 组的地个点的坐标为m[a][b+1] , m[a+i][d] ,  m[c][d-i] ,  m[c-i][b]. 每次旋转的时候,就是把这四个位置的值交换即可。

#include<iostream>
#include<vector>
using namespace std;

void helper(vector<vector<int>>&matrix, int a, int b, int c, int d){
	int temp=0;
	int time=d-c;
	for(int i=0; i<time; i++){
		temp=matrix[c-i][b];
 		matrix[c-i][b]=matrix[c][d-i];
 		matrix[c][d-i]=matrix[a+i][d];
		matrix[a+i][d]=matrix[a][b+i];
		matrix[a][b+i]=temp;
	}
}

void rotate(vector<vector<int>>&matrix){
	int a=0, b=0, c=matrix.size()-1, d=matrix[0].size()-1;
	while(a<=c&&b<=d)	
		helper(matrix, a++, b++, c--, d--);
}

int main(){
	vector<vector<int>>matrix={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
	rotate(matrix);
	return 0;
}

这题是leetcode 48 旋转图像

class Solution {
public:
    void helper(vector<vector<int>>& matrix, int a, int b, int c, int d){
        int temp=0;
        //将四个点的元素相互交换
        for(int i=0; i<d-b; i++){
            temp=matrix[c-i][b];
            matrix[c-i][b]=matrix[c][d-i];
            matrix[c][d-i]=matrix[a+i][d];
            matrix[a+i][d]=matrix[a][b+i];
            matrix[a][b+i]=temp;
        }
    }
    
    void rotate(vector<vector<int>>& matrix) {
        int a=0, b=0, c=matrix.size()-1, d=matrix[0].size()-1;
        //选定四个点,开始转框
        while(a<=c&&b<=d)
            helper(matrix, a++,b++,c--,d--);
    }
};

猜你喜欢

转载自blog.csdn.net/qq_29996285/article/details/85221861
今日推荐