学习耗时:2h
给跪了,看了一个大佬的方法,一直没有反应过来,是我太笨了
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。
示例:输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,4,7,5,3,6,8,9]
解释:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25Id4cts-1574304115365)(evernotecid://67870364-B5C3-4F4A-8FF1-2923A0094441/appyinxiangcom/27027923/ENResource/p10)]
解答:
(1)解题思路:
结合题目的图来看,得知:
1.每一趟对角线中元素的标号(x,y)相加的和是递增的。
第一趟:1的坐标(0,0),x+y=0;
第二趟:2的坐标(0,1),4的坐标(1,0)。x+y=1;
第三趟:7的坐标(2,0),5的坐标(1,1),3的坐标(0,1)。x+y=2;
第四趟:…
2.每一趟都是x或y其中一个从大到小(每次-1),另一个从小到大(每次+1)。
第二趟:2的坐标(0,1),4的坐标(1,0),x每次+1,y每次-1。
第三趟:7的坐标(2,0),5的坐标(1,1),3的坐标(0,1)。x每次-1,以每次+1。
3.确定初始值。例如这一趟是y从大到小,y尽量取最大,当初始值超过x上限时,不足的部分加到y上面。
第二趟:2的坐标(0,1),4的坐标(1,0),y的初始值取1,x取0.
第四趟:6的坐标(1,2),8的坐标(2,1),y的初始值取2,剩下的加到x上,x取1。
4.确定结束值。例如这一趟是x从大到小,这一趟结束的判断是,x减到0或y值达到上限。
第三趟:7的坐标(2,0),5的坐标(1,1),3的坐标(0,1)。x + y =2,x减到0为止。
5.这一趟是 x 从大到小,那么下一趟是 y 从大到小,循环进行。 并且方向相反时,逻辑处理是一样的,除了x,y和他们各自的上限值是相反的。
x从大到小,第三趟:7的坐标(2,0),5的坐标(1,1),3的坐标(0,1)。x+y=1,x初值取2,y初值取0,结束值x减到0为止。
x从小到大,第二趟:2的坐标(0,1),4的坐标(1,0),y的初始值取1,x取0,结束值y减到0为止。
规律变成代码
无论这一趟的方向是从左下到右上,还是从右上到左下,逻辑处理都是一样的,因此在换方向的时候,标志位进行更改。
bool bXFlag=true;
使用一个bool值标记,将用到的数据正确定位。例如:
//5.逻辑处理是一样的,x,y的上限值是相反的
int pm=bXFlag ? m : n;
int pn=bXFlag ? n : m;
这样就能保证逻辑计算的代码一样,数据不同。
以一趟未一个单元,那么i就是每一趟的和。
//1.坐标(x,y)相加的和是递增的
for(int i = 0; i < m +n;i++)
根据规律,就可以确定x和y的初值。
//3.当初是值超过x的上限时,不足的部分加到y上面
int x=(i<pm) ? i : pm-1;
int y=i-x;
每趟的结束条件。
//4.这一趟结束的判断是,x减到0或者y加到上限
while(x>=0&&y<pn)
一趟之中,x和y变化。
//2.每一趟都是x和y其中一个从大到小(每次-1),另一个从小到大(每次+1)
x--;y++;
输出数字。根据标志位变化
//5.方向相反时,x和y是相反的
nums.push_back(bXFlag?matrix[x][y]:matrix[y][x]);
这一趟结束了,循环起来,标志位变化。
下面是完整代码。
vector<int> findDiagonalOrder(vector<vector<int>>& matrix)
{
vector<int>nums;
int m=matrix.size();//二维数组的行数
if(m==0) return nums;
int n=matrix[0].size();//二维数组的列数
if(n==0) return nums;
bool bXFlag=true;
for(int i=0;i<m+n;i++)
{
int pm=bXFlag?m:n;
int pn=bXFlag?n:m;
int x=(i>pm)?i:pm-1;
itn y=i-x;
while(x>=0&&y<pn)
{
nums.push_back(bXFlag?matrix[x][y]:matrix[y][x]);
x--;
y++;
}
bXFlag=!bXFlg;
}
return nums;
}
int main()
{
int temp=1;
int i,j;
vector<vector<int>>array(3);//定义一个二维vector,行数为3.
vector<int>ret;
for(i=0;i<array.size();i++)
{array[i].resize(3);}//对其每一行resize为3,及列数为3.
for(i=0;i<array.size();i++)
{
for(j=0;j<array[0].size();j++)
{
array[i][j]=temp;
temp++;
cout<<array[i][j]<<" in"<<i<<","<<j<<endl;
}
cout<<endl;
}
ret=findDiagonalOrder(array);
for(int i=0;i<ret.size();i++)
{
cout<<ret[i]<<endl;
}
return 0;
}
说到我为啥要写出来主函数,是因为这个答主的“坐标”和我理解的二维数组的元素“下标”不太一样,搞了半天没搞懂为啥他写点2的坐标是(1,0),是我太笨了,于是写了主函数出来验证一下二维vector的元素下表是否是正常理解的那样,而且手动推了一遍他的程序,最后才发现了**bXFlag=!bXFlg;**这个东西,很骚的一个操作,真的是我太笨了。。
原答案链接
https://leetcode-cn/problems/diagonal-traverse/solution/dui-jiao-xian-bian-li-fen-xi-ti-mu-zhao-zhun-gui-l/
答主GitHub
https://github.com/AhJo53589/leetcode-cn
学习向量(vector)
https://www.cnblogs.com/mr-wid/archive/2013/01/22/2871105.html