Month: November 2016

Java PriorityQueue does not store the whole sequence in-order. So if we try to print it using System.out.println(Q), the output will usually not be in-order. But every time we do a poll() on a priority queue, it will give the smallest number in the current sequence.

A second type of matrix transformation problem involves swapping matrix elements in different ways. One example is matrix transpose, which merely involves swapping element A[i][j] with element A[j][i]. A much more interesting example involves matrix rotation, e.g., the “rotate image” problem, which asks us to rotate a matrix by 90 degrees (clockwise or counterclockwise). This rotation problem can be solved through layer-level traversal. But different from the “layer rotation” problem discussed in “matrix transformation (1)“, the relative positions of elements at different layers are fixed in the “rotate image” problem. The following solution is from CTCI v6 page 203. The trick is to introduce 3 additional variables: “first” (start of a row or column), “last” (end of a row or column), and “offset” (index relative to the start).

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

publicclassSolution{

publicvoidrotate(int[][]matrix){

intN=matrix.length;

for(intlayer=0;layer<N/2;layer++){

intfirst=layer;// start

intlast=N-1-layer;// end

for(inti=first;i<last;i++){

intoffset=i-first;// index relative to first

inttop=matrix[first][i];// save top

matrix[first][i]=matrix[last-offset][first];// left to top

matrix[last-offset][first]=matrix[last][last-offset];// bottom to left

This type of problems are quite different from those discussed in “changing matrix elements” in the sense that the traversal can no longer be implemented using a simple nested loop that goes through row index and column index in order. One example is the “matrix layer rotation” problem, in which each layer of the matrix is rotated counterclockwise by a certain amount, which is different for different layers. In my solution in the following, I first traverse the matrix layer by layer from outside towards center and store the elements in each layer into a separate list. After this re-arrangement of the matrix elements, the elements in a rotated layer can be accessed through indexing as discussed in “querying the rotated array“. I then reconstruct the rotated matrix using the layers with the rotated index. During all those operations, it is important to fix a reference point and I used the upper-left corner, row = 0 and column = 0, as the reference.

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

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

importjava.util.*;

publicclassMatrixLayerRotation{

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intM=in.nextInt();// row number

intN=in.nextInt();// column number

intR=in.nextInt();// rotation number

int[][]mat=newint[M][N];// original matrix

booleanidentical=true;// for corner case, if all elements are identical, matrix is the same after rotation

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

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

mat[r][c]=in.nextInt();

if(mat[r][c]!=mat[0][0]){

identical=false;

}

}

}

if(identical){// if all elements are identical, just print out the matrix and return

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

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

System.out.print(mat[r][c]+" ");

}

System.out.println();

}

return;

}

List<List<Integer>>layers=matrixToLayers(mat);// store the layers

int[]shifts=newint[layers.size()];// the shift amount is different for different layer, because the lengths of different layers are different

for(intl=0;l<layers.size();l++){

shifts[l]=R%layers.get(l).size();

}

int[][]matr=layersToMatrix(layers,shifts,M,N);// reconstruct the matrix from layers after rotation

for(intr=r0+1;r<=M-1-r0;r++){// clockwise right, note the "r0 + 1", not "r0", because "r0" was access in top traversal above

mat[r][N-1-c0]=layer.get((i+shifts[l])%layer.size());

i++;

}

for(intc=N-2-c0;c>=c0;c--){// clockwise bottom, note the "N - 2 - c0"

mat[M-1-r0][c]=layer.get((i+shifts[l])%layer.size());

i++;

}

for(intr=M-2-r0;r>=r0+1;r--){// clockwise left, note the "M - 2 -r0"

mat[r][c0]=layer.get((i+shifts[l])%layer.size());

i++;

}

r0++;

c0++;

l++;

}

returnmat;

}

privatestaticList<List<Integer>>matrixToLayers(int[][]mat){

List<List<Integer>>result=newArrayList<>();

intM=mat.length;

intN=mat[0].length;

intr0=0;

intc0=0;

while(r0<M/2&&c0<N/2){// layer-level traversal

List<Integer>layer=newArrayList<>();

for(intc=c0;c<=N-1-c0;c++){// top

layer.add(mat[r0][c]);

}

for(intr=r0+1;r<=M-1-r0;r++){// right

layer.add(mat[r][N-1-c0]);

}

for(intc=N-2-c0;c>=c0;c--){// bottom

layer.add(mat[M-1-r0][c]);

}

for(intr=M-2-r0;r>=r0+1;r--){// left

layer.add(mat[r][c0]);

}

result.add(layer);

r0++;

c0++;

}

returnresult;

}

}

A closely related problem is the “spiral matrix” problem, in which we need to traverse the matrix in spiral order. For this problem, it is important to check for corner cases (matrix that is very elongated along horizontal or vertical direction). My solution is the following.

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

importjava.util.*;

publicclassSolution{

publicList<Integer>spiralOrder(int[][]matrix){

List<Integer>result=newArrayList<>();

if(matrix.length==0)returnresult;

intr0,r1,c0,c1;

intm=matrix.length;

intn=matrix[0].length;

intcount=0;

r0=0;r1=m-1;

c0=0;c1=n-1;

while(count<m*n){

for(intc=c0;c<=c1;c++){// top

result.add(matrix[r0][c]);

count++;

}

if(r0+1<=r1){// check for corner case

for(intr=r0+1;r<=r1;r++){// right

result.add(matrix[r][c1]);

count++;

}

}

if(c1-1>=c0&&r1>r0){// check

for(intc=c1-1;c>=c0;c--){// bottom

result.add(matrix[r1][c]);

count++;

}

}

if(r0+1<=r1-1&&c1>c0){// check

for(intr=r1-1;r>=r0+1;r--){// left

result.add(matrix[r][c0]);

count++;

}

}

r0++;

r1--;

if(r0>r1)break;

c0++;

c1--;

if(c0>c1)break;

}

returnresult;

}

}

There is also a problem that asks us to reconstruct a matrix from its spiral order traversal (the “spiral matrix II” problem). My solution is the following.

Some of the problems ask us to rearrange a sequence of characters into different forms, e.g., a matrix, and then traverse the rearranged characters in different ways. One example is the “encryption” problem. The logic of the code can often be simplified significantly if we use a special character, e.g., “$”, to fill all the elements after the end of the original character array. My solution is in the following.

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

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

Strings=in.next();

char[]input=s.toCharArray();

intL=input.length;

introws=(int)Math.floor(Math.sqrt(L));

intcols=(int)Math.ceil(Math.sqrt(L));

if(rows*cols<L){// if the matrix is not large enough, increase the row number by 1

rows++;

}

char[][]grid=newchar[rows][cols];

inti=0;

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

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

grid[r][c]=(i>=L)?'$':input[i++];// mark the elements after the end of the char array as $

}

}

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

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

if(grid[r][c]!='$'){// check if the element is in the original char array

When multiplying two very big integers together, say “c = a * b”, the result can overflow. If we just make “c” a long integer, the result of the right-hand-side will be implicitly cast from integer to long during the assignment. But that does not prevent the overflow! If “a * b” (the RHS) overflows, the number implicitly cast to long and assigned to “c” is the overflown integer (a negative integer), not the correct answer. So to prevent the RHS from overflow, we need to explicit cast at least one of the numbers on the RHS to long, i.e., “long c = (long)a * b”, in which “b” will be implicitly cast into a long integer and the result of the RHS will be a long before assigned to “c”. One example is the “modified Kaprekar numbers” problem and my code is following.

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

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intp=in.nextInt();

intq=in.nextInt();

intcount=0;

for(inti=p;i<=q;i++){

if(isKaprekar(i)){

System.out.print(i+" ");

count++;

}

}

if(count==0){

System.out.println("INVALID RANGE");

}

}

privatestaticbooleanisKaprekar(intn){

longn2=(long)n*n;// explicit cast to long on the RHS to prevent overflow

intnumDigit=String.valueOf(n).length();

Stringsquare=String.valueOf(n2);

if(square.length()==numDigit){// corner case: square has same number of digits as original

Some of the problems ask us to convert numbers to English words or phrases, for example, the “time in words” problem, which asks us to convert a time specified using numbers to words. For this type of problems, a HashMap that binds the numbers to their corresponding words can be quite handy. My solution is int the following.

Another related problem is to convert numbers to other types of text representations, such as the “integer to Roman” and the opposite conversion “Roman to integer“. The opposite conversion (from Roman to integer) is simpler. Again, a HashMap is used to map Roman characters to their corresponding integers (the mapping can be found on wiki) in my following solution. The only issue is that some of the Roman numerals are two-character long and both characters also exist in the HashMap as independent keys, so I check for the existence of a 2-character key before checking for the existence of a 1-character key.

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

publicclassSolution{

privatestaticMap<String,Integer>convertMap=newHashMap<>();

static{

convertMap.put("I",1);

convertMap.put("V",5);

convertMap.put("X",10);

convertMap.put("L",50);

convertMap.put("C",100);

convertMap.put("D",500);

convertMap.put("M",1000);

convertMap.put("IV",4);

convertMap.put("IX",9);

convertMap.put("XL",40);

convertMap.put("XC",90);

convertMap.put("CD",400);

convertMap.put("CM",900);

}

publicintromanToInt(Strings){

s=s.toUpperCase();

intres=0;

inti=0;

while(i<s.length()){

if(i<s.length()-1&&convertMap.containsKey(s.substring(i,i+2))){

res+=convertMap.get(s.substring(i,i+2));

i+=2;

}

elseif(convertMap.containsKey(s.substring(i,i+1))){

res+=convertMap.get(s.substring(i,i+1));

i++;

}

elsethrownewRuntimeException();

}

returnres;

}

}

Mapping integers to Roman numerals is more complicated. In addition to the HashMap that binds single-character Roman numerals to corresponding integers, we also need a separate simplification map that binds 2-character Roman numerals to corresponding sequences of 1-character Roman numerals. After we map the integer to a sequence of single-character Roman numerals, we apply a simplification process that maps subarrays of single-character Roman numerals to corresponding 2-character Roman numerals. In order to iteration through all the keys in the HashMap in a specific order (decreasing order in my following code), I used a separate array to store the keys in descending order. The following is my code.

Java provides a data structure for storing very large integers that cannot fit into the 64-bit long type. It is called “BigInteger”. One example is the factorial calculation (e.g., the “extra long factorials” problem), which can overflow 64-bit long very quickly. My solution using BigInteger is the following.

Java provide a very convenient data structure for storing bits (true/false) in an array, which is called BitSet. One example that can make use of this data structure is the “ACM ICPC team” problem, in which we need to find a team (two bit arrays) whose combined “1s” cover the most number of bits. My solution is the following.

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

importjava.util.*;

publicclassSolution{

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intN=in.nextInt();// number of people

intM=in.nextInt();// number of topics

BitSet[]bits=newBitSet[N];// an array of BitSet, one BitSet for each person

In this type of problems, we repeat the same experiment for “n” times and each time the outcome is either “a” or “b” and we are asked to find all possible combinations of the “n” outcomes. One example is the “Manasa and stones” problem. If the number of outcomes with value “a” is “i”, we know for sure that the number of outcomes with value “b” is “n – i”. So we can just loop through all possible values for “i”, which is from 0 (no “a”) to n (all “a”), and store the result of each iteration into a list. My solution is in the following.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intT=in.nextInt();

for(intt=0;t<T;t++){

intn=in.nextInt();

inta=in.nextInt();

intb=in.nextInt();

List<Integer>last=newArrayList<>();

for(inti=0;i<n;i++){

intj=n-1-i;// subtract 1 to adjust to 0-based index

intl=i*b+j*a;// the total number of outcomes with value b is i and those with value a is j

In the post “searching a matrix for patterns (1)“, I discussed an example of searching for a specific shape (a plus) in a matrix. In this post, we look at another example, the “grid search” problem, in which we have to search for the occurrence of a rectangular block of numbers.

The basic idea is straight-forward. I first search for the occurrence of the upper-left corner element of the smaller matrix inside the larger matrix. If I find a match, I loop through every element inside the smaller matrix and compare with the corresponding element in the larger matrix. If one of the element does not match, I break out the inner match loops and check the next location where the element in the larger matrix matches the upper-left corner of the smaller matrix. As soon as I find a complete match, I break out the outer match loop. For this type of problems, the ranges of the loops are particularly important and it is very easy to make a mistake. Pay special attention to line 21-22 in my solution in the following.

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

publicstaticvoidmain(String[]args){

Scanner in=newScanner(System.in);

intT=in.nextInt();

for(intt=0;t<T;t++){

intR=in.nextInt();// row of the larger matrix

intC=in.nextInt();// column of the larger matrix

char[][]G=newchar[R][C];// the larger matrix

for(inti=0;i<R;i++){

Strings=in.next();

G[i]=s.toCharArray();

}

intr=in.nextInt();// row of the smaller matrix

intc=in.nextInt();// column of the smaller matrix

char[][]P=newchar[r][c];// the smaller matrix (pattern)

for(inti=0;i<r;i++){

Strings=in.next();

P[i]=s.toCharArray();

}

booleanmatch=false;

matchLoop:// label for breaking the outer match loop

for(inti=0;i<R-r+1;i++){// note the "R - r + 1"

for(intj=0;j<C-c+1;j++){// note the "C - c + 1"

if(G[i][j]==P[0][0]){

booleancheck=true;

checkLoop:// label for breaking the inner match loop

for(intp=0;p<r;p++){

for(intq=0;q<c;q++){

if(G[i+p][j+q]!=P[p][q]){

check=false;

breakcheckLoop;// break the two inner loops as soon as one element does not match

}

}// for q

}// for p

if(check){

match=true;

breakmatchLoop;// break the two outer loops as soon as one complete match of the pattern is found