Leetcode: 733. Flood Fill - c#

I am doing this problem and struggling so I find this answer:
public class Solution {
public int[][] FloodFill(int[][] image, int sr, int sc, int color) {
if(image[sr][sc] == color) return image;
Fill(image,sr,sc,color,image[sr][sc]);
return image;
}
private void Fill(int[][] image,int x, int y, int color, int oldColor) {
if(x < 0 || y < 0 || x > image.Length - 1 || y > image[x].Length - 1 || image[x][y] == color || image[x][y] != oldColor) return;
image[x][y] = color;
Fill(image,x + 1,y,color,oldColor);
Fill(image,x - 1,y,color,oldColor);
Fill(image,x,y + 1,color,oldColor);
Fill(image,x,y - 1,color,oldColor);
}
}
I understand everything now, except for this part:
y > image[x].Length - 1
What exactly does that mean? I get the boundaries of x > image.Length - 1, but this one confuses me.
I am assuming that it means the boundaries of the xth column, but I would love clarification on this.

Your image seems to be stored as an array of arrays. It's an array of "rows" actually. Note that to access a pixel in the array you have to access image[row][column]. First you access the array at image[row], which is, itself, an array of all the pixels in that row, one for each column. Then you access the pixel at index column in that array. i.e.: (image[row])[column].
My first complaint: You've used the variable names x and y unconventionally. :(
Typically we assign rows the coordinate y and columns the coordinate x so we would expect to have to access image[y][x] But you've done the opposite.
The code provides sr and sc which I assume the letters r=row and c=column. This is corroborated by the quick-escape check: if(image[sr][sc] == color) return image; That sr is intended to be used in the major dimension (first index) and sc is intended to be used in the minor dimension (second index).
You have:
Fill(image,sr,sc,color,image[sr][sc]);
But you then have:
private void Fill(int[][] image,int x, int y, int color, int oldColor) {
So you're passing x = sr and y = sc. That's very confusing / atypical / unconventional / backwards. We usually use y for rows and x for columns.
However, it doesn't matter because you're actually using these variables consistently again by accessing image[x][y]. Which is also backwards, but in this case two wrongs have made a right -- you've bucked convention by swapping labelling and order. Most of us have come to terms with the fact that, with an image that is an array of arrays, we have to write image[y][x]. But you've just swapped the variable names. It means you can write image[x][y], which is appealing, but it's technically confusing for those of us that know better and stick to conventions.
The actual explanation
Setting aside your unconventional/backwards use of x and y,
it's checking y against "the length of the array representing the xth row" or "the number of columns in row x", which is image[x].length.
If y is in range, then y < length. So we test the opposite to conclude that y is out of range. Instead of checking !(y < length) it is logically equivalent to check y >= length or y > length - 1. The last of these is the check you are using. y > image[x].length - 1
The order of these tests is important: if x < 0 or x > image.length - 1 Then the x index is out of bounds and it would be unsafe to even look at the xth row array to see what its length is (the xth row doesn't even exist in that case.) So beware the order of the lazy || checks there. We can be certain that image[x] exists because we've already checked x is in range in the left part of that expression.
Due to lazy evaluation of ||, spelling it out explicitly,
x < 0 || y < 0 || x > image.Length - 1 // it's important this check comes first
|| y > image[x].Length - 1 // it's important this check comes after

Related

c# Problems assigning values to points class

I am having difficulty assigning integers to a points class. I have a list of coords class that contain an integer for X and Y values (Xp and Yp respectively). The integer type is Int32 and was converted from a string to a double and then to an integer using:
X = double.Parse(setX, System.Globalization.CultureInfo.InvariantCulture);
The minimum X and Y values in the list are deducted from each coordinate before being assigned to a point. A check showed that the calculation is performing correctly but in the points the values are all wrong. I am wondering if there is a problem with the way I am assigning using points[n] or if there is a better way of creating points to plot to a polygon? Sorry it is quite a length process procedure for producing the coords class, so I omitted it, but if you need more information please let me know.
Point[] points = new Point[coords.Count];
int n = 0;
foreach (var i in coords)
{
//These calculations are working fine:
int Xp = i.Xplt - minX;
int Yp = i.Yplt - minY;
//However when I assign to a new point. The calculation is wrong returning 0's and the incorrect result
points[n] = new Point(Xp, Yp);
n = +1;
}
On this line
n = +1;
You probably ment
n += 1;

C# - Filling an array using a Strings chars doesn't work properly

I've got an
int[,] map = int[100, 100];
and a
String mapString;
mapString simply contains a large amount of numbers (there are no other chars than numbers).
I now want to assign the first value in the array(map[0,0]) with the first char of mapString, the second value(map[0,1]) with the second char of mapString and so on. I use the following code:
int currentposition = 0;
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
map[x, y] = ArrayTest.Properties
.Settings
.Default
.mapSaveSetting
.ElementAt(currentposition);
currentposition++;
}
}
Now what happens is almost what I wished for.
The problem is that it assigns two numbers to each value instead of one. Also i can't figure out what numbers he's using as they're not the ones in my mapSaveSetting, but I can deal with that for myself.
The only problem I really don't get is that each value contains two numbers after executing this for-loop. Why does it happen? ElementAt(int) only returns one char, right?
It really looks like a logical mistake to me but I can't find it. Please don't be offensive if I just made a dumb mistake in my way of thinking.
EDIT
As it seems to be unclear what is the problem now, I'll add an example.
map[0, 0] == 42
...could be an output. Even if the String would start with e.g. 4245634 it would not make sense, as ElementAt(int) should only return the 4, not 42, right?
You are assigning char to int.Since there is implicit conversation from char to int you are getting the Unicode code of the character (in your case characters representing numbers).To fix you issue you should convert character to int.
In your case as the all characters are numeric you can do as trick like this:
map[x, y] =
ArrayTest.Properties.Settings.Default.mapSaveSetting.ElementAt(currentposition) - 48;
This work because Unicode codes of symbols [0..9] sequential and equals to [48..57].
I think that your mistake is related to the ASCII value of the characters. You should know that each character has a related ASCII value, in particular 0 has an ASCII value of 48, 1 of 49 and so on (you could check an ASCII table to check this out).
So, to get the right value of the character, you should subtract the value of the char 0 from the one in the string, like in the following piece of code.
map[x, y] = ArrayTest.Properties.Settings.Default.mapSaveSetting.ElementAt(currentposition) - '0';
You are assigning a char value to an int. A char designs a Unicode code point, and it converts implicitly to int but not in the way you expect: it gives you the code point.
Example:
Console.WriteLine((int)'A'); // Will print 65
You're actually trying to convert a single digit represented as a string to an int. Use int.Parse for this.
Console.WriteLine(int.Parse("5")); // Will print 5
Another issue: you shouldn't use ElementAt on a string, since it will needlessly iterate over the whole string until the specified index, as string doesn't implement IList<char>.
You could use the indexer like that:
int currentposition = 0;
var setting = ArrayTest.Properties.Settings.Default.mapSaveSetting;
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
map[x, y] = int.Parse(setting[currentposition].ToString());
currentposition++;
}
}
But it's actually a waste to convert each char in there to a new string, so just use some basic math instead:
int currentposition = 0;
var setting = ArrayTest.Properties.Settings.Default.mapSaveSetting;
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
map[x, y] = setting[currentposition++] - '0';
}
}
This works as the code points for the digits are consecutive.
To elaborate just a little on previous answers: In C and C++, a char is a byte (for all intents and purposes), while in C# it's a "Unicode" character. C# however has the 'byte' type matching pretty much 1:1 to the lower-level languages 'char' type.
The question suggests this could be a part of the issue.
Additionally (performance consideration): It should be noted that in C#, an array is a "heavy" type, and a multi-dimensional array is really an array-of-arrays. Depending on usage patterns, it could be more efficient to use a single-dimension array and scale one of the indices by row/col-size manually. Something like:
type this[int x, int y] { get { /* scale one of x/y and read from 1-dimensional array */ } }

Need help for search optimization

I am fairly new to programming and i need some help with optimizing.
Basically a part of my method does:
for(int i = 0; i < Tiles.Length; i++)
{
x = Tiles[i].WorldPosition.x;
y = Tiles[i].WorldPosition.y;
z = Tiles[i].WorldPosition.z;
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition == Tiles[i].WorldPosition +
new Vector3Int(0,1,0));
if(topsearch.isEmpty)
{
// DoMyThing
}
}
So i am searching for a Tile in a position which is 1 unit above the current Tile.
My problem is that for the whole method it takes 0.1 secs which results in a small hick up..Without Array.Find the method is 0.01 secs.
I tried with a for loop also, but still not great result, because i need 3 more checks for
the bottom, left and right..
Can somebody help me out and point me a way of acquiring some fast results?
Maybe i should go with something like threading?
You could create a 3-dimensional array so that you can look up a tile at a specific location by just looking what's in Tiles[x, y + 1, z].
You can then iterate through your data in 2 loops: one to build up Tiles and one to do the checks you are doing in your code above, which would then just be:
for(int i = 0; i < Tiles.Length; i++)
{
Tile toFind = Tiles[Tile[i].x, Tile[i].y + 1, Tile[i].z];
if (toFind != null) ...
}
You would have to dimension the array so that you have 1 extra row in the y so that Tiles[x, y + 1, z] doesn't cause an index-out-of-range exception.
Adding to Roy's solution, if the space is not continuous, as it might be, you could put a hashcode of WorldPosition (the x, y and z coordinates) to some good use here.
I mean you could override WorldPosition's GetHashCode with your own implementation like that:
public class WorldPosition
{
public int X;
public int Y;
public int Z;
public override int GetHashCode()
{
int result = X.GetHashCode();
result = (result * 397) ^ Y.GetHashCode();
result = (result * 397) ^ Z.GetHashCode();
return result;
}
}
See Why is '397' used for ReSharper GetHashCode override? for explanation.
Then you can put your tiles in a Dictionary<WorldPosition, Tile>.
This would allow for quickly looking up for dict[new WorldPosition(x, y, z + 1)] etc. Dictionaries use hashcode for keys, so it would be fast.
First, like #Roy suggested, try storing the values in an array so you can access them with x,y,z coordinates,
Another thing you could do is change the search to
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition.x == Tiles[i].WorldPosition.x &&
search.WorldPosition.y == (Tiles[i].WorldPosition.y + 1) &&
search.WorldPosition.z == Tiles[i].WorldPosition.z)
This might be faster as well, depending on how many fields your WorldPosition has

How to safely check arrays bounds

I am making game of life in 2D array. I need to determine when all adjacent cells are empty so I just test all of them. It works well unless the cell being checked is the boundary. Then of course testing X+1 throws an exception as the index is out of the array boundaries. Can I handle this somehow instead of handling the exception?
Thanks
use GetLength(0) and GetLength(1) to get the width and height of the array.
There is also a neat performance trick the runtime uses for its own bounds checks: casting to unsigned int to reduce the two checks into one. But since this costs readability you use it if the check is really performance critical.
(i >= 0) && (i < length)
becomes
(uint)i < length
If you want speed you'll have to treat the edge-cells differently and process the rest with a
for(int x = 1; x < Size-1; x++) // these all have x-1 and x+1 neighbours
I created an extension method for a 2D array to check if in bounds:
public static class ExtensionMethods
{
public static bool In2DArrayBounds(this object[,] array, int x, int y)
{
if (x < array.GetLowerBound(0) ||
x > array.GetUpperBound(0) ||
y < array.GetLowerBound(1) ||
y > array.GetUpperBound(1)) return false;
return true;
}
}
Yes, before accessing the element at index i + 1, check whether i + 1 is strictly inferior to array.Length.

Implementation of extremely sparse arrays

I have an extremely sparse static array with 4 dimensions of 8192 each that I want to do lookups from (C#). Only 68796 of these 4.5 * 10^15 values are non-zero. What is the fastest way to do this, with speed and low memory usage being vital?
Thanks
First, I would argue that plain arrays are quite clearly the wrong kind of data structure for your problem.
How about using a dictionary where you use a 4-tuple as index?
var lookup = new Dictionary<Tuple<int,int,int,int>, int>();
I've never done that myself, but it should work fine. If you don't have Tuple ready because you're working with a version of the .NET Framework preceding .NET 4, you could provide your own index type:
struct LookupKey
{
public readonly int First;
public readonly int Second;
public readonly int Third;
public readonly int Fourth;
…
}
var lookup = new Dictionary<LookupKey, int>();
You could use a plain Dictionary or create a similar map suited for your needs (it will be an array in which you place elements according to an hashvalue you calculate on your 4 values) but you'll need to care about collisions.
Also a binary seach tree can make the trick if you accept a logarithmic complexity for lookup..
Use hashtable (generic Dictionary is already implemented as Hashtable). As key use vector of 4 dimension index. As value store what you want.
What I'd do is use hash lists instead of "normal" arrays for this, then (pseudo-code):
// first, check bounds:
if(x < 0 || y < 0 || z < 0 || w < 0
|| x > xsize || y > ysize || z > zsize || w > wsize)
throw new Whatever(...);
// now return value if != 0
if(x in arr && y in arr[x] && z in arr[x][y] && w in arr[x][y][z])
return arr[x][y][z][w];
else
return 0;
I think the best way is to use a hash-table (Dictionary<T, int>), indexed with a custom struct containing the 4 indexes. Don't forgot to override object.Equals() and object.GetHashCode() on that struct.

Categories

Resources