Changing matrix elements

Sometimes we need to traverse a matrix and change the elements along the way according to some given rules. The difficulty with such problems is that current modifications of some elements could alter the process of the following modifications. One such example is the “set matrix zeroes” problem. When we set a certain column or row to all zeroes, we are destroying the information about which elements are not zeroes along that row or column and very soon the entire matrix will become all zeroes. One solution is to use two lists to store the row/column IDs on which we have a zero and after we have gathered all the information we do a second pass thorough the matrix and turn the corresponding rows and columns to zeroes. This approach uses extra memory. A better approach with no extra memory usage is to use the first row and first column to keep the indexes of the row and column indexes of the zero elements. This solution is from CTCI v6 page 204.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

importjava.util.*;

publicclassSolution{

publicvoidsetZeroes(int[][]matrix){

if(matrix==null||matrix.length==0)return;

intnumRow=matrix.length;

intnumCol=matrix[0].length;

booleanfirstRowZero=false;

booleanfirstColZero=false;

for(intcol=0;col<numCol;col++){// check the first row for zeros

if(matrix[0][col]==0){

firstRowZero=true;

break;

}

}

for(introw=0;row<numRow;row++){// check the first column for zeros

if(matrix[row][0]==0){

firstColZero=true;

break;

}

}

for(introw=0;row<numRow;row++){

for(intcol=0;col<numCol;col++){

if(matrix[row][col]==0){

matrix[0][col]=0;// set the corresponding element on first row to zero

matrix[row][0]=0;// set the corresponding element on first column to zero

}

}

}

for(intcol=1;col<numCol;col++){// col MUST start from 1 because 0th col is still needed in the following

if(matrix[0][col]==0){

setColZero(matrix,col);

}

}

for(introw=1;row<numRow;row++){// row MUST start from 1

if(matrix[row][0]==0){

setRowZero(matrix,row);

}

}

if(firstRowZero){

setRowZero(matrix,0);

}

if(firstColZero){

setColZero(matrix,0);

}

}

privatevoidsetRowZero(int[][]matrix,introw){

for(intcol=1;col<matrix[row].length;col++){// col MUST start from 1

matrix[row][col]=0;

}

}

privatevoidsetColZero(int[][]matrix,intcol){

for(introw=1;row<matrix.length;row++){// row MUST start from 1

matrix[row][col]=0;

}

}

}

Another example is the “bomberman game” problem, in which a bomb can explode and change a set of elements surrounding it. The same issue exists for this problem. So my solution in the following uses a separate list to keep track of bomb locations and go through the matrix two times. The first time is to gather information about the locations of the bombs and their affected elements. The second time is to modify the matrix based on the information gathered in the previous pass.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

import java.util.*;

publicclassSolution{

staticclassCoor{

introw,col;

Coor(intr,intc){row=r;col=c;}

}

privatestaticvoidexplode(int[][]bombs){

intR=bombs.length;

intC=bombs[0].length;

for(intr=0;r<R;r++){

for(intc=0;c<C;c++){

if(bombs[r][c]>=1)bombs[r][c]--;

elseif(bombs[r][c]<0)bombs[r][c]=3;

}

}

List<Coor>l=newArrayList<>();

for(intr=0;r<R;r++){// first pass to get locations

for(intc=0;c<C;c++){

if(bombs[r][c]==0){

l.add(newCoor(r,c));

if(r-1>=0)l.add(newCoor(r-1,c));

if(r+1<R)l.add(newCoor(r+1,c));

if(c-1>=0)l.add(newCoor(r,c-1));

if(c+1<C)l.add(newCoor(r,c+1));

}

}

}

for(Coorc:l){// second pass to change elements

bombs[c.row][c.col]=-1;

}

}

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intR=in.nextInt();

intC=in.nextInt();

intN=in.nextInt();

int[][]bombs=newint[R][C];

for(introw=0;row<R;row++){

for(intcol=0;col<C;col++){

bombs[row][col]=-1;

}

}

char[][]grid1=newchar[R][C];

char[][]grid2=newchar[R][C];

for(introw=0;row<R;row++){

Strings=in.next();

grid1[row]=s.toCharArray();

for(intcol=0;col<C;col++){

grid2[row][col]=79;

if(grid1[row][col]==79){

bombs[row][col]=2;

}

}

}

explode(bombs);// 2

explode(bombs);// 3

char[][]grid3=newchar[R][C];

for(intr=0;r<R;r++){

for(intc=0;c<C;c++){

if(bombs[r][c]<0)grid3[r][c]='.';

elsegrid3[r][c]=79;

}

}

explode(bombs);// 4

explode(bombs);// 5

char[][]grid5=newchar[R][C];

for(intr=0;r<R;r++){

for(intc=0;c<C;c++){

if(bombs[r][c]<0)grid5[r][c]='.';

elsegrid5[r][c]=79;

}

}

if(N==1){

for(introw=0;row<R;row++){

for(intcol=0;col<C;col++){

System.out.print(grid1[row][col]);

}

System.out.println();

}

}

if(N%2==0){

for(introw=0;row<R;row++){

for(intcol=0;col<C;col++){

System.out.print(grid2[row][col]);

}

System.out.println();

}

}

if(N%4==3){

for(introw=0;row<R;row++){

for(intcol=0;col<C;col++){

System.out.print(grid3[row][col]);

}

System.out.println();

}

}

if(N>1&&N%4==1){

for(introw=0;row<R;row++){

for(intcol=0;col<C;col++){

System.out.print(grid5[row][col]);

}

System.out.println();

}

}

}

}

A third example is the “cavity map” problem, in which we need to find and mark the elements that are larger than their neighbors. Again, my solution following uses two passes of the entire matrix. The first pass finds out all the elements that are larger than their four neighbors and store their row/column numbers into two separate lists (one for row number, the other for column number). In the second pass, all selected elements are marked.