题目:给一个M*N的二维数组,数组元素的值为0或者1,要求转换数组,将含有1的行和列全部置1.
比如原数组:
0 1 0 0
0 0 0 0
0 0 1 0
0 0 0 0
需要转换成:
1 1 1 1
0 1 1 0
1 1 1 1
0 1 1 0
这个题目看起来很简单,可是我在面试过程的40分钟硬是没写出个满意的答案。
首先想到的就是遍历数组,然后遇到1,就设置对应的行和列;但是这样会有问题,因为前面的设置的值会影响后续元素的判断。我的应对方案是将数组复制一份b[m,n],然后遍历第二个数组,如果b[i,j]==1,则设置a数组对应的行和列为1。
这样导致空间复杂度也为m*n了,面试官提醒我有什么办法不用复制数组,我当时脑袋已经一团浆糊了(不巧正好重感冒,本来就不清醒),结果没有回答出来,时间到了。
第二天早上灵光一现,思路突然清晰,花了五分钟完成了下面这个答案:
其实思想就是使用两个一维数组分别记录行和列的状况,数组b[m] , c[n] 用来映射有1的列和行;这样不用复制整个二维数组了,不过还是需要小号点额外空间。于是我就想办法在原有数组a上作文章。
是将1映射到首行首列I相应的位置(不过第一行的1先不映射,因为那样的话a[0,0]会出错),第一步完成为:
0 1 1 0
0
1
0
然后分别根据第一行处理其他行,根据第一列处理其他列;
最后再来处理第一行,第一列;
void convert(int a[][], m, n)
{
int i,j = 0;
int x, y = 0;
/*首先在数组未做任何改变之前确认第一行和第一列应该如何处理*/
for(j=0;j<n;j++)
{
if (a[0,j]==1)
{
x=1; /*第一行含有1,应该全部置1*/
break;
}
}
for(i=0;i<m;i++)
{
if (a[i,0]==1)
{
y=1;/*第一列含有1,应该全部置1*/
break;
}
}
/*映射除了第一行和第一列的所有的1到第一行第一列的相应位置*/
for(i=1;i<m;i++)
for(j=1;j<n;j++)
if(a[i,j] == 1)
{
a[i,0] = a[j,0] = 1;
}
/*处理行元素置1*/
for(i=0;i<m; i++)
{
if (a[i,0] == 1)
{
for(j=1;j<n;j++)
a[i,j]=1;
}
}
/*处理列元素置1*/
for(j=0;j <n; j++)
{
if (a[0,j] == 1)
{
for(i=1;i<n;i++)
a[i,j]=1;
}
}
/*处理第一行*/
if(x)
for(j=0; j<n; j++)
a[0,j] = 1;
if(y)
for(i=0;i<m;i++)
a[i,0] = 1;
return;
}