问题
Write a method named removeSomePoints. This method takes an array of Points, and returns a new array of points that is the same as the original array, except that it removes all points that have x- and y-coordinates that differ by less than 20. In other words, the returned array will probably have a smaller size than the original array. This method should leave the original array untouched. To clarify: If any of the following points were in the original array, they would not be in the array that is returned.
100 90 (x and y differ by 10)
90 100 (x and y differ by 10)
3 22 (x and y differ by 19)
On the other hand, any of the following points would be in the array that is returned:
100 80 (x and y differ by 20)
80 100 (x and y differ by 20)
2 25 (x and y differ by 23)
My code:
public static Point[] removeSomePoints(Point[] arr)
{
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (Math.abs(arr[i].getX() - arr[i].getY()) > 19) {
count++;
}
}
Point[] finalArr = new Point[count];
for (int i = 0; i < finalArr.length; i++) {
if (Math.abs(arr[i].getX() - arr[i].getY()) > 19) {
finalArr[i] = arr[i];
}
}
return finalArr;
}
Can't seem to figure out what is going wrong. It is returning an array but it doesn't change anything.
回答1:
Ok, so your program is currently not working because you determine the number of matching items (lets say N
), in your input array of length M
. Now given that N
is guaranteed to be less than M
, notice that you are then iterating over a subset of your input array (of length N
) and copying any matches in that subset into your output array. This is simply incorrect.
I take it this is a learning project - and its obvious the key point of the lesson is in picking appropriate data structures for your code. Arrays are great when dealing with fixed size sets, but not so appropriate for variable sized sets. For variable data, lists are definitely the way to go.
So let's take a look at some pseudocode:
public static Point[] removeSomePoints(Point[] arr) {
// If 'arr' is null, return null
// If 'arr' is empty, return empty
// Initialize a variable list structure, of at least arr.length in size
// For each element in arr
// if element matches condition, add to variable list
// End for
//
// Convert variable list into array and return
}
Thats your algorithm, in a nutshell. Converting that into real code:
public static Point[] removeSomePoints(Point[] arr) {
if(arr == null) return null;
if(arr.length == 0) return new Point[0];
List<Point> outputList = new ArrayList<Point>(arr.length);
for(Point p : arr) {
if (Math.abs(p.getX() - p.getY()) > 19) outputList.add(p);
}
return outputList.toArray(new Point[outputList.size());
}
Don't forget to go over the documentation for List and ArrayList, in order to better understand how they work.
回答2:
Your second loop should be:
int j = 0;
for (int i = 0; i < arr.length; ++i) {
if ((Math.abs(arr[i].getX() - arr[i].getY()) > 19) {
finalArr[j++] = arr[i];
}
}
回答3:
The key flaw in the logic is that the shorter array index is being used in the raw array.
This means that the array [[90,100],[75,100],[85,100],[80,100]] would first count 2 valid entries, create a new array of size 2, and then copy the first two entries from the raw array to create [[90,100],[75,100]] rather than the desired [[75,100],[80,100]].
One approach is to add a "resizeArray()" function (example here: http://www.source-code.biz/snippets/java/3.htm), populate your new array during the initial loop using a separate index (eg "count") which is only incremented upon adding to the new array, then resize the new array down to the target size.
Like so:
public static Point[] removeSomePoints(Point[] arr)
{
int count = 0;
Point[] finalArr = new Point[arr.length];
for (int i = 0; i < arr.length; i++)
{
if (Math.abs(arr[i].getX() - arr[i].getY()) > 19)
{
finalArr[count] = arr[i];
count++;
}
}
return (Point[])resizeArray(finalArr, count);
}
回答4:
As others have mentioned, the problem is due to the logic flaw in the second loop. You should iterate over the original array instead of the one to be returned.
The answers that make use of ArrayList
and resizeArray
are both good. In @Perception's answer, ArrayList
is used as an intermediate data structure while in @DreadPirateShawn's answer, Array
is used as an intermediate data structure. In the end both of them will be resized to the result array to be returned. Since random access to the intermediate data structure is not required, I would prefer using LinkedList
instead. Using a linked list does not require any resizing, thus potentially saving some time and space.
public static Point[] removeSomePoints(Point[] arr) {
if(arr == null) return null;
if(arr.length == 0) return new Point[0];
List<Point> outputList = new LinkedList<Point>();
for(Point p : arr) {
if (Math.abs(p.getX() - p.getY()) > 19) outputList.add(p);
}
return outputList.toArray(new Point[outputList.size()]);
}
来源:https://stackoverflow.com/questions/14408134/removing-points-from-an-array-and-returning-a-new-array-java