Flatten a Jagged 2D Array - java

I have an assignment that asks me to flatten a 2D array into a single array.
Here's what I have so far:
public static int[] flatenArray(int [][] a){
//TODO
int length = 0;
for(int y = 0; y < a.length; y++){
length += a[y].length;
}
int[] neu = new int[length];
int x = 0;
for (int i = 0; i < a.length; i++){
for(int j = 0; j < a[0].length; j++){
neu[x] = a[i][j];
x++;
}
}
return neu;
}
When doing a JUnit Test for the following test case
assertArrayEquals(new int[] {1,2,3,4,5,6,7,8,9,10,11},Ass06.flatenArray(new int[][] {{1,2,3},{4,5,6},{7,8,9,10,11}}));
I get the following error:
arrays differed at element[9]; expected <10> but was <0>
Somehow at the point where the array length of the 3rd "inner array" surpasses 3, the last 2 numbers ("10, 11") are not copied into the new array.

There are multiple ways to solve this this, but it all comes down to you counting things wrong.
In a new int[1], the first element is index 0. In an array of 1 element, .length will return 1, but there will be no array[1]. That's why you're missing the the count by 1.

Related

(Java) Search indexes of values of an array in another array

I have written the following code that takes two arrays and searches the index of the first occurrence of each value from the first array in the second one. For example if first = {15, 10, 18, 17, 15} and second = {10, 15, 10, 17} then the output would be an array with an equal length to first which contains the indices output = {1, 0, -1, 3, 1}, as e.g. 15 occurs in index 1 of the second array, 10 occurs at the 0th index, etc. The index will be -1 if the value in first doesn't occur in second. The code I've written to loop through the arrays is as follows:
public static int[] searchIndexes(int[] first, int[] second) {
int[] indices = new int[first.length];
int index = -1;
for (int i = 0; i < first.length; i ++) {
for (int j = 0; j < second.length; j ++) {
if (first[i] == second[j])
index = j;
}
indices[i] = index;
}
return indices;
}
However, for the given example the output is instead {1, 2, 2, 3, 1}. I think I do understand the issue; since 10 occurs twice in second then the index of the second occurrence is recorded, but I don't know how to get around this. Putting a break; statement after the if clause doesn't seem to fix it.
This would be straightforward by using the ArrayUtils.indexOf() utility method. Moving through the second array, call ArrayUtils.indexOf() for each of its elements in reference to the first array, storing the results in the indices array. This will also mean that there would be a single loop, not a nested loop.
The ArrayUtils class is a part of the org.apache.commons.lang3 library.
A different option, not requiring an external library, would be to convert your arrays to Lists and then take advantage of the List.indexOf() method.
I hope that helps!
Two issues in your code:
Once index is set to any value at all, it can never again become -1
Once you find the first occurrence in the second array, you keep going - need a break.
Updated code:
public static int[] searchIndexes(int[] first, int[] second) {
int[] indices = new int[first.length];
int index;
for (int i = 0; i < first.length; i ++) {
// reset index on each iteration
index = -1;
for (int j = 0; j < second.length; j ++) {
if (first[i] == second[j]) {
// once the first match is found, break out of the inner loop
index = j;
break;
}
}
indices[i] = index;
}
return indices;
}
try this
public static int[] searchIndexes(int[] first, int[] second) {
int[] indices = new int[first.length];
//fill all values with -1
Arrays.fill(indices,0,first.length - 1, -1);
for (int i = 0; i < first.length; i++) {
for (int j = 0; j < second.length; j++) {
// when you met with same value fill your indices array with second array's value's index and break the loop
if (first[i] == second[j]) {
indices[i] = j;
break;
}
}
}
return indices;
}
Just add break after found the element and reset the index
public static int[] searchIndexes(int[] first, int[] second) {
int[] indices = new int[first.length];
int index = -1;
for (int i = 0; i < first.length; i++) {
index = -1;
for (int j = 0; j < second.length; j++) {
if (first[i] == second[j]) {
index = j;
break;
}
}
indices[i] = index;
}
return indices;
}
, main
public static void main(String args[]) {
int[] indices = searchIndexes(new int[] { 15, 10, 18, 17, 15 }, new int[] { 10, 15, 10, 17 });
for (int i = 0; i < indices.length; i++)
System.out.print(indices[i] + " ");
System.out.println();
}
, output
1 0 -1 3 1

LeetCode 1365 - looking for a better solution than O(n^2)

I am working leetcode problem number 1365. Here is the problem below in italicized characters:
Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i].
Return the answer in an array.
Example 1: Input: nums = [8,1,2,2,3] Output: [4,0,1,1,3] Explanation: For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). For nums[1]=1 does not exist any smaller number than it. For nums[2]=2 there exist one smaller number than it (1). For nums[3]=2 there exist one smaller number than it (1). For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).
https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
I am able to complete the task using brute force which gives an O(n^2) time. Is there a faster way to code this problem?
public static void main(String[] args) {
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
}
public static int[] smallerNumbersThanCurrent(int[] nums) {
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++) {
int ctr = 0;
for (int y = 0; y < nums.length; y++) {
if (nums[y] < nums[x]) {
ctr++;
}
result[x] = ctr;
}
}
return result;
}
A simple O(nlgn) solution with an O(n) space would be:
Copy the array into a temp array, O(n)
Sort the new array O(ngln)
Iterate over the original array
For every element, do a binary search over the sorted array and get the first index of the element.
The index would be the count you are after.
There is a slightly better O(n^2) approach, where you only compare each pair of indices once and updating the counts accordingly:
public static int[] smallerNumbersThanCurrent(int[] nums)
{
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++)
{
for (int y = x + 1; y < nums.length; y++)
{
if (nums[y] < nums[x])
result[x]++;
else if (nums[y] > nums[x])
result[y]++;
}
}
return result;
}
However, at the cost of an additional array we can do it in O(ngln) by sorting the indices of the original array and then iterating through these sorted indices, updating the count accordingly. The only complication is in dealing with repeated numbers, e.g. the 2s in your example.
public static int[] smallerNumbersThanCurrent(int[] nums)
{
Integer[] idx = new Integer[nums.length];
for(int i=0; i<idx.length; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> (nums[a]-nums[b]));
int[] res = new int[nums.length];
for(int i=1; i<idx.length; i++)
{
if(nums[idx[i]] == nums[idx[i-1]])
res[idx[i]] = res[idx[i-1]];
else
res[idx[i]] = i;
}
return res;
}
Test:
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
Output:
[4, 0, 1, 1, 3]

Combining elements in jagged 2D arrays into one new jagged 2D array (Deep Copy issue)

Given two jagged arrays: a & b where a + b will always have the same # of rows:
int[][] a = { {1,2}, {4,5,6} };
int[][] b = { {7}, {8,9,0} };
how exactly can I manipulate a new jagged array c to return:
{ {1,2,7}, {4,5,6,8,9,0} }?
Here's what I have so far:
int[][] c = null;
for(int i = 0; i<a.length; i++){
c = new int[a.length][a[i].length + b[i].length];
}
//rest of my code for assigning the values into the appropriate position works.
The trouble arises, as you all can see, that I am performing a deep copy, which, on the second iteration of the for-loop, is setting ALL rows to a length of the length of the current row on the step of the iteration.
Flaw in your approach
You are creating a new 2D array object each iteration of your loop. Each time through, you are reassigning c, thus throwing out all of your previous work. Additionally, placing a number in both set of brackets at the same time results in each row having the same length.
Using your example, the first time through the loop, c is assigned to a 2D array with two rows, each of length three. The second time through the loop, you throw out your previous 2D array and create a new one having two rows, each of length six.
But what you need to be doing is creating a new row each time through the loop, not the entire 2D array.
Solution
First, we create a 2D array called c and specify that it has a.length rows. We don't put a value in the second bracket, because that would indicate that all of the rows are of the same length. So at this point, c does not know about row length. It just knows how many rows it can have. Keep in mind: c doesn't actually have any rows yet, just a capacity for a.length rows.
Next, we must create the rows and assign a length/capacity to them. We set up our loop to run as many times as there are rows. The current row index is denoted by i, and therefore, c[i] refers to a specific row in the 2D c array. We use new int[] to create each individual row/array, but inside the brackets, we must specify the length of the current row. For any row c[i], its length is given by the sum of the lengths of a[i] and b[i]; that is, a[i].length + b[i].length.
What we are left with is an array c that contains rows/arrays, each with a set length/capacity that matches the sum of the corresponding rows lengths in a and b.
Keep in mind that c still does not contain any integer values, only containers that are of the correct size to hold the values in a and b. As you mentioned, you already have code to populate your array with values.
int[][] c = new int[a.length][];
for (int i = 0; i < a.length; i++) {
c[i] = new int[a[i].length + b[i].length];
}
When initialize Java 2D array, lets consider it as a table; you only have to give the number of rows and in each row of your table can have different number of columns.
Eg. Say we have a 2D array call c defined as follows,
int[][] c = new int[10][];
It says you defined c contains 10 of int[] elements. But in order to use it you have to define the number of columns each row has.
Eg. Say we have 3 columns in the second row
int c[1] = new int[3];
So in this example you have to add the column values of 2D arrays a and b to calculate the resultant array which is c.
c[i] = new int[a[i].length + b[i].length];
This will give you what you expected.
int[][] a = { {1,2}, {4,5,6} };
int[][] b = { {7}, {8,9,0} };
int[][] c = new int[a.length][];
for(int i = 0; i<a.length; i++){
c[i] = new int[a[i].length + b[i].length];
for (int j=0;j< a[i].length; j++) {
c[i][j] = a[i][j];
}
int length = a[i].length;
for (int j=0;j< b[i].length; j++) {
c[i][length+j] = b[i][j];
}
}
Try c[i] = new int[a[i].length + b[i].length]
int[][] c = new int[a.length][];
for(int i = 0; i < c.length; i++){
c[i] = new int[a[i].length + b[i].length];
int x = 0;
for (int num : a[i]) {
c[i][x] = num;
x++;
}
for (int num : b[i]) {
c[i][x] = num;
x++;
}
}
or even simpler...
int[][] c = new int[a.length][];
for(int i = 0; i < c.length; i++){
c[i] = new int[a[i].length + b[i].length];
System.arraycopy(a[i], 0, c[i], 0, a[i].length);
System.arraycopy(b[i], 0, c[i], a[i].length, b[i].length);
}
Try this one:
int[][] c = new int[a.length][];
for(int i = 0; i<a.length; i++){
c[i] = new int [a[i].length + b[i].length];
int j;
for(j=0; i < a[i].length; j++){
c[i][j] = a[i][j];
}
for(int k=0; i < b[i].length; k++){
c[i][j+k] = b[i][j];
}
}
public static void main(String [] args) {
int[][] a = { {1,2}, {4,5,6} };
int[][] b = { {7}, {8,9,0} };
int[][] c = null;
for(int i = 0; i<a.length; i++){
c = new int[a.length][a[i].length + b[i].length];
}
for(int i = 0; i<a.length; i++){
for (int j = 0; j < a[i].length+b[i].length; j++) {
if(j< a[i].length){
c[i][j]=a[i][j];
}
if(j< a[i].length+b[i].length && j>= a[i].length){
c[i][j]=b[i][j-a[i].length];
}
}
}
for(int i = 0; i<a.length; i++){
for (int j = 0; j < a[i].length+b[i].length; j++) {
System.out.print(c[i][j]);
}
System.out.println();
}
}
This works in my system ...........

Java 2-D selection sort

I am preparing for an exam, and we are likely to be tasked with sorting a two dimensional array of ints. Sorted meaning the first row, first column is the lowest and the last row, last column is the highest.
I approached the task by creating a 1-D array, and then populating it with all the values in the 2d array. Then, I passed it through a sorting method. Finally, I wrote each value of the sorted array back into the 2d array and returned it.
This sort of worked, as you can see from the output below. I am confused as to where my process is breaking down, I would appreciate any input.
Input:
int[][] nums = {{1,5,9},{8,9,3},{0,7,6}};
output:
0 0 0
0 0 0
0 0 1
public int[][] sort2D(int[][]nums){
int[] temp = new int[((nums.length+1)*(nums.length+1))];//make one long array
for(int i =0; i<nums.length; i++){ //populate
int counter = 0; //indices for long array
for(int j = 0; j<nums[i].length; j++){
System.out.println(temp[counter]);
temp[counter] = (int)nums[i][j];
counter++;
}
}
temp = sort(temp); //sort it (verified code)
for(int i = 0; i<nums.length; i++){ //reverse the above process
int counter = 0;
for(int j = 0; j<nums.length; j++){
nums[i][j] = temp[counter];
counter++;
}
}
return nums;
}
The first thing I think you're doing wrong is this:
int[] temp = new int[((nums.length+1)*(nums.length+1))];//make one long array
nums.length +1 = 4 in your case. you are copying your 3*3 array into a 4*4 array.
This has the funny effect of adding 5 0's to your result. (temp[9] till temp[15] will be 0 filled)
After you sort, these 0's will show up
the place where your code breaks down is:
for(int i =0; i<nums.length; i++){ //populate
>> int counter = 0; //indices for long array
for(int j = 0; j<nums[i].length; j++){
System.out.println(temp[counter]);
temp[counter] = (int)nums[i][j];
counter++;
}
}
You initialize the counter to 0 every time you go through one of your outer arrays.
this means that on the 3rd pass (last array) you overwrite temp[0], temp1 and temp[2] with nums[2][0], nums2, nums[2][2]
I assume in your actual code, you do
int counter = 0; //indices for long array
for(int i =0; i<nums.length; i++){ //populate
for(int j = 0; j<nums[i].length; j++){
System.out.println(temp[counter]);
temp[counter++] = (int)nums[i][j];
}
}
You could also use System.arrayCopy, especially if you know the length and suchlike.

Flattening uneven array - Out of bounds exception error

I am trying to flatten this array:
int[][] arr = { {1, 2, 3},
{4, 5},
{6},
null,
{},
{7,8}};
I can see that in the first couple of steps it fills out the new array, but then I get the out of bounds exception error. I don't understand where my mistake is.
public static int[] concAr (int[][] arr) {
int countels=0;
for (int r = 0; r < arr.length; r++) {
if (arr[r] == null|| arr[r].length==0)
continue;
for (int c = 0; c < arr[r].length; c++) {
countels++;
}
}
int[] flatAr = new int[countels];
for(int i = 0; i < countels; i ++) {
if(arr[i]!=null) {
for(int j = 0; j < arr[i].length; j ++) {
flatAr[(i * arr.length) + j] = arr[i][j];
}
}
}
return flatAr;
}
The following indexing is wrong, because array lengths are different
flatAr[(i * arr.length) + j] = arr[i][j];
Use this after setting count to zero:
flatAr[count++] = arr[i][j];
countels is the length of the flattened array, in this case, 8. However, in your second outer loop, you index through the original, unflattened array up to countels, even though your unflattened array only has 6 elements. Once you get past those 6, you get the out of bounds exception.
The second time through, you still need to iterate the way you did the first time, and increment the index of the flattened array within the second set of loops.

Categories