Above answer is very simple and clear. Including my answer below which skips columns as there cannot be any lakes. The same optimization can be applied on @liupangzi answer

Complexity is still O(mn)

```
public int islandPerimeter(int[][] grid) {
int perimeter = 0, lastRowLength=0;
for (int i = 0; i <= grid.length; i++) {
boolean visitedAlandOnThisRow = false;
int j = 0;
for (; j <= grid[0].length; j++) {
int current = isLand(grid, i, j);
//count area only for top and left edges
if (current == 1) {
//when we are on land flip the values of top and left cells to consider or ignore the edge.
perimeter += (isLand(grid, i - 1, j) == 0 ? 1 : 0);
perimeter += (isLand(grid, i, j - 1) == 0 ? 1 : 0);
visitedAlandOnThisRow = true;
} else {
perimeter += isLand(grid, i, j - 1); //left
int top = isLand(grid, i - 1, j);
perimeter += top;
/*
optimization:
when land ends on this row, no need to visit rest of the water if we
dont have a land on the previous row whose j > current j in order to count it's bottom
*/
if (visitedAlandOnThisRow && top == 0 && i > 0 && j > lastRowLength) {
break;
}
}
}
lastRowLength = j-1;
}
return perimeter;
}
/*
Method to address boundary cells
returns 0 for water and 1 for land for a given location i,j
*/
private int isLand(int[][] grid, int i, int j) {
return (i < 0 || j < 0 || i == grid.length || j == grid[0].length) ? 0 : grid[i][j];
}
```