Rearranging (swapping) array values - java

I'm trying to solve the fix34 problem of CodingBat:
Return an array that contains exactly the same numbers as the given array, but rearranged so that every 3 is immediately followed by a 4. Do not move the 3's, but every other number may move. The array contains the same number of 3's and 4's, every 3 has a number after it that is not a 3, and a 3 appears in the array before any 4.
fix34([1, 3, 1, 4]) → [1, 3, 4, 1]
fix34([1, 3, 1, 4, 4, 3, 1]) → [1, 3, 4, 1, 1, 3, 4]
fix34([3, 2, 2, 4]) → [3, 4, 2, 2]
My code works for all cases except:
1. fix34([1, 3, 1, 4, 4, 3, 1])
→ [1, 3, 4, 1, 1, 3, 4] (Expected)
[1, 3, 4, 1, 4, 3, 1] (Actual Output)
2. fix34([5, 3, 5, 4, 5, 4, 5, 4, 3, 5, 3, 5])
→ [5, 3, 4, 5, 5, 5, 5, 5, 3, 4, 3, 4] (Expected)
[5, 3, 4, 5, 5, 4, 5, 4, 3, 5, 3, 5] (Actual Output)
Can't seem to figure out why, thanks in advance!
public int[] fix34(int[] nums) {
int [] result = new int [nums.length];
int temp = 0;
for(int i = 0; i < nums.length; i++){
if(nums[i] == 3){
result[i] = 3;
for(int j = i + 1; j < nums.length; j++){
if(nums[j] == 4){
temp = nums[i + 1];
result[i + 1] = 4;
result[j] = temp;
nums[j] = temp;
break;
}
}
}else if(result[i] == 0){
result[i] = nums[i];
}
}
return result;
}

The pseudo-code for your current implementation is:
for (each_element_in_nums) {
if (that_element_is_a_3) {
scan_the_following_elements_for_a_4;
if (we_found_a_4) {
swap_that_4_with_the_element_immediately_following_the_3;
}
}
}
The unsuccessful test cases are failing when no 4 appears after the 3 you are trying to pair up. Based on the expected output
1. fix34([1, 3, 1, 4, 4, 3, 1])
→ [1, 3, 4, 1, 1, 3, 4] (Expected)
your code will also have to be able to move a 4 that appears before the 3 you are currently working on, as shown in the second swap below:
↔↔
↕ ↕
[1, 3, 1, 4, 4, 3, 1]
↕ ↕
↔↔↔↔↔
In other words, your current code can only move a 4 to the left. You'll also need to be able to move a 4 to the right.
Here is a fairly simple implementation that seems to do the trick:
/**
* Returns an array with elements rearranged.
* <p>
* Rules:<br>
* 1. [input] The array contains the same number of 3's and 4's.<br>
* 2. [input] Every 3 has a number after it that is not a 3.<br>
* 3. [input] A 3 appears in the array before any 4.<br>
* 4. [output] Return an array that contains exactly the same numbers as the
* given array, but rearranged so that every 3 is immediately
* followed by a 4.<br>
* 5. [output] Do not move the 3's, but every other number may move.<br>
*/
public static int[] fix34(int[] nums) {
if (nums.length > 0 && nums[nums.length - 1] == 3) {
// bulletproofing: Really should not happen, per rule #2
throw new IllegalArgumentException("Input array cannot end with a 3");
}
List<Integer> positionOf3s = new ArrayList<>();
List<Integer> positionOf4s = new ArrayList<>();
int[] result = nums.clone();
for (int resultArrayIndex = 0; resultArrayIndex < result.length; resultArrayIndex++) {
if (result[resultArrayIndex] == 4) {
positionOf4s.add(resultArrayIndex); // position of swap candidate
} else if (result[resultArrayIndex] == 3) {
if (result[resultArrayIndex + 1] == 3) {
// bulletproofing: Really should not happen, per rule #2
throw new IllegalArgumentException("Input array cannot contain two successive 3's");
} else if (result[resultArrayIndex + 1] == 4) {
// 3 already paired with 4, so no need to move, just skip the 4
resultArrayIndex++;
} else {
// this 3 is lonely, so add its position to the list to be paired
positionOf3s.add(resultArrayIndex);
}
}
}
if (positionOf3s.size() > positionOf4s.size()) {
// bulletproofing: Really should not happen per rule #1
throw new IllegalArgumentException(
String.format("3's needing to be paired: %d; 4's available for swapping: %d",
positionOf3s.size(), positionOf4s.size()));
}
/*
* perform swap for each "lonely" 3 in listOf3sIndex, using the corresponding
* swap candidate from positionOf4s
*/
for (int listOf3sIndex = 0; listOf3sIndex < positionOf3s.size(); listOf3sIndex++) {
result[positionOf4s.get(listOf3sIndex)] = result[positionOf3s.get(listOf3sIndex) + 1];
result[positionOf3s.get(listOf3sIndex) + 1] = 4;
}
return result;
}

Related

Longest Plateau Solution: the length and location of the longest continuous sequence of equal values

Here is a full program description with test cases and below it is my solution:
Given an array of integers int A[], find the length and location of the longest contiguous sequence of equal values for which the values of the elements just before and just after this sequence are smaller.
You should just print these two numbers (first is the length and second is the starting index of the plateau).
To complete the definition, we can consider there are imaginary index positions at A[-1] and A[A.length] where A[-1] < A[0] and A[A.length] < A[A.length-1]. Therefore, the plateau can start/end at both ends of array A. This condition guarantees the existence of a plateau. A plateau can be of length 1.
Example 1:
java LongestPlateau 1 2 2 2 2 1
With these command-line arguments, the program should print:
4
1
Example 2:
java LongestPlateau 1 2 2 2 2 3
With these command-line arguments, the program should print:
1
5
Example 3:
java LongestPlateau 3 2 2 2 1 2 1 1 1 2 2 0 1 1 1 1 0
With these command-line arguments, the program should print:
4
12
Here is my Solution:
public class LongestPlateau {
private static int[] parseInputArray(String[] args) {
int[] value = new int[args.length+1];
for(int i = 0 ; i < args.length; i++){
if (i == args.length-1) value[i] = 0; // this imaginary last value of the array ensures that if the plateau is the last value of the array, then it outputs the correct answer
value[i] = Integer.parseInt(args[i]);
}
return value;
}
public static void printLargestPlateau(int[] values) {
int biggestStartIndex = -1;
int biggestLength = 0;
int currentIndex = 1;
int currentPlateauStartIndex = 1;
int currentLength = 1;
boolean plateauStarted = false;
while (currentIndex < values.length) {
if(isStartOfPlateau(currentIndex, values)){
currentLength = 1;
plateauStarted = true;
currentPlateauStartIndex = currentIndex;
} else if (isEndOfPlateau(currentIndex, values)) {
if(plateauStarted && currentLength > biggestLength){
biggestLength = currentLength;
biggestStartIndex = currentPlateauStartIndex;
}
plateauStarted = false;
currentLength = 1;
} else {
currentLength++;
}
currentIndex++;
}
System.out.println(biggestLength +"\n"+biggestStartIndex);
}
private static boolean isStartOfPlateau(int index, int[] values){
if(index <= 0){
return false;
}
return values[index-1] < values[index];
}
private static boolean isEndOfPlateau(int index, int[] values){
if(index <= 0){
return false;
}
return values[index - 1] > values[index];
}
public static void main(String[] args) {
int[] values = parseInputArray(args);
printLargestPlateau(values);
}
}
As I mentioned in the comments, existing code fails to detect plateaus at the start and the end of the input data, and the following implementation fixes this issue.
static void printLargestPlateau(int ... arr) {
int start = -1, maxStart = -1;
int length = 0, maxLength = -1;
boolean onPlateau = false;
if (arr.length > 0) {
start = 0;
length = 1;
onPlateau = true;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == arr[i - 1]) {
if (onPlateau) {
length++;
}
} else if (arr[i] < arr[i - 1]) {
if (length > maxLength) {
maxLength = length;
maxStart = start;
}
onPlateau = false;
} else { // possible start of new plateau
onPlateau = true;
start = i;
length = 1;
}
}
// check possible plateau at the end
if (length > maxLength) {
maxLength = length;
maxStart = start;
}
}
System.out.println(maxLength);
System.out.println(maxStart);
}
Tests:
int[][] tests = {
{},
{1},
{1, 1},
{1, 2},
{1, 1, 2},
{1, 2, 2},
{1, 2, 1},
{1, 2, 3},
{1, 2, 2, 2, 3, 3, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 1},
{1, 2, 2, 2, 2, 3},
{3, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 0, 1, 1, 1, 1, 0},
{3, 3, 3, 3, 1, 1, 0, 2, 2, 2, 2, 2, 2}
};
for (int[] arr : tests) {
System.out.println(Arrays.toString(arr));
printLargestPlateau(arr);
System.out.println("-".repeat(arr.length * 3));
}
Output:
[]
-1
-1
[1]
1
0
---
[1, 1]
2
0
------
[1, 2]
1
1
------
[1, 1, 2]
1
2
---------
[1, 2, 2]
2
1
---------
[1, 2, 1]
1
1
---------
[1, 2, 3]
1
2
---------
[1, 2, 2, 2, 3, 3, 1, 1, 1, 1]
2
4
------------------------------
[1, 2, 2, 2, 2, 1]
4
1
------------------
[1, 2, 2, 2, 2, 3]
1
5
------------------
[3, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 0, 1, 1, 1, 1, 0]
4
12
---------------------------------------------------
[3, 3, 3, 3, 1, 1, 0, 2, 2, 2, 2, 2, 2]
6
7
---------------------------------------

How to populate a 2d array with values from a 1d array?

I have a single array populated with some values that I receive from another method, and I want to populate a bidimensional array with values from the first, example:
int[] singleArray; // there's no values here to demonstrate,
// let's think that's populated
int[][] bidimArray = new int[80][80];
for (int i = 0; i < 80; i++) {
for (int j = 0; j < 80; j++) {
for (int x = 0; x < singleArray.length; x++) {
bidimArray[i][j] = singleArray[x];
}
}
}
I thought in the solution above, besides it seems very ugly solution, it only saves the last position of singleArray in bidimArray[][]. May anyone help me, please?
There is no need for the third for loop here. This is where you went wrong. The change to your code is to simply increment x for every value entered into the new 2D array and omitting the third for loop.
int[] singleArray;
int[][] bidimArray = new int[80][80];
int x = 0;
for (int i = 0; i < 80; i++) {
for (int j = 0; j < 80; j++) {
bidimArray[i][j] = singleArray[x];
x++;
}
}
You can also combine the two inner lines in the loop like this:
bidimArray[i][j] = singleArray[x++];
As pointed out in the comments, you should not hard code array sizes. For your approach, you will have to make sure that the singleArray contains at least 80*80 elements. If this is not given, you should make sure to check that constraint beforehand.
Circular populating of a 2d array 8x7 with values from a 1d array 6. It works the same with larger and smaller arrays regardless of size:
int[] arr1 = {1, 2, 3, 4, 5, 6};
int m = 8;
int n = 7;
int[][] arr2 = IntStream.range(0, m)
.mapToObj(i -> IntStream.range(0, n)
.map(j -> arr1[(j + i * n) % arr1.length])
.toArray())
.toArray(int[][]::new);
// output
Arrays.stream(arr2).map(Arrays::toString).forEach(System.out::println);
[1, 2, 3, 4, 5, 6, 1]
[2, 3, 4, 5, 6, 1, 2]
[3, 4, 5, 6, 1, 2, 3]
[4, 5, 6, 1, 2, 3, 4]
[5, 6, 1, 2, 3, 4, 5]
[6, 1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 1]
[2, 3, 4, 5, 6, 1, 2]
See also: Copying a 1d array to a 2d array

how to add values in an array from last value to first

How can I add the values in the arrNumbers that exceed 6 to add to a new array starting from the last value and ending at the first.
This is what I have written, but does not produce the right output.
int[] arrNumbers = new int[] { 1, 2, 3, 4, 5, 6, 1, 2 };
int[] newArrNumbers = new int[6];
for(int i = 0; i < arrNumbers.length ; i++){
newArrNumbers[i % 6] += arrNumbers[i];
}
The actual output:
newArrNumbers = [2, 4, 3, 4, 5, 6]
However, I want the output to ADD to the LAST VALUE in the arrNumbers, going from right to left, not left to right. So result should be:
newArrNumbers = [1, 2, 3, 4, 7, 7]
Try this.
int[] arrNumbers = new int[] { 1, 2, 3, 4, 5, 6, 1, 2 };
int[] newArrNumbers = new int[6];
for(int i = 0; i < arrNumbers.length ; i++){
newArrNumbers[i < 6 ? i : (6 - (i % 6) - 1)] += arrNumbers[i];
}
System.out.println(Arrays.toString(newArrNumbers));
output:
[1, 2, 3, 4, 7, 7]

Insert column in desired location of 2D array

I'm looking to choose a column of my array, lets say column 2. I want this column to be inserted at a specific location in the 2D array, lets say column 4.
For example:
1 3 5 5 2
2 4 6 2 1
3 6 9 1 1
The desired output would be:
1 5 5 3 2
2 6 2 4 1
3 9 1 6 1
I know I could loop the following code until I 1 by 1 swap every column until the column is in the desired location.
for (int[] array1 : array) {
int temp = array1[col1];
array1[col1] = array1[col1];
array1[col2] = temp;
}
However, if I'm using large matrices such as 30 columns wide, this would be incredibly inefficient. Is there a way to insert the column anywhere in the 2D array without iterating through each swap until it is in the right spot?
Possibly, a performance may be improved by using parallel processing with streams.
IntStream of row indexes should be used to handle each row separately.
// basic shift method
// from, to - indexes starting from 1
public static void shiftArray(int[] arr, int from, int to) {
int tmp = arr[from - 1];
for (int i = from; i < to; i++) {
arr[i - 1] = arr[i];
}
arr[to - 1] = tmp;
}
public static void main(String[] args) {
int[][] arr2d = {
{1, 3, 5, 5, 2},
{2, 4, 6, 2, 1},
{3, 6, 9, 1, 1}
};
int fromColumn = 2;
int toColumn = 4;
IntStream.range(0, arr2d.length)
.parallel()
.forEach(i -> shiftArray(arr2d[i], fromColumn, toColumn)); // shift each row in parallel
// print the 2D array after shift
Arrays.stream(arr2d)
.map(Arrays::toString)
.forEach(System.out::println);
}
Output:
[1, 5, 5, 3, 2]
[2, 6, 2, 4, 1]
[3, 9, 1, 6, 1]
Try this.
public static void moveColumn(int[][] matrix, int from, int to) {
--from; --to; // If column number begins with zero, remove this line.
int srcPos = from < to ? from + 1 : to;
int destPos = from < to ? from : to + 1;
int length = Math.abs(from - to);
for (int[] array : matrix) {
int temp = array[from];
System.arraycopy(array, srcPos, array, destPos, length);
array[to] = temp;
}
}
and
int[][] matrix = {
{1, 3, 5, 5, 2},
{2, 4, 6, 2, 1},
{3, 6, 9, 1, 1}
};
moveColumn(matrix, 2, 4);
for (int[] row : matrix)
System.out.println(Arrays.toString(row));
output
[1, 5, 5, 3, 2]
[2, 6, 2, 4, 1]
[3, 9, 1, 6, 1]

(Java) Use for loop to get all combinations and add to ArrayList, but ArrayList only have the last add one

I have had a problem when I am doing my java program. I want to generate all the possible combinations of the element in a String array, and store each possible one into an overall ArrayList.
I used a for loop to go through all the possible combinations and use ArrayList.add to add each String array. However, when I was trying to print out the ArrayList to check, it only have the last String array at all the positions.
If I move the System.out.println to the inside of for loop, everything looks just fine. If I move the print to the outsides the loop, it just show that I only have the same String array at all positions.
Problem related to two parts of code:
String[] inputs = {"1", "2", "3", "4", "5", "6"};
int maxLength = 4;
//Get the total number of all combinations with replacement, used for the for loop
int total = (int) Math.pow(inputs.length, maxLength);
ArrayList<String[]> allList = new ArrayList<>();
System.out.println(total);
String[] subSets = new String[maxLength];
int [] index = new int [maxLength];
Arrays.fill(index, 0);
for (int i = 0; i < total; i++)
{
for (int j = 0; j < maxLength; j++)
{
subSets[j] = inputs[index[j]];
}
allList.add(i, subSets);
if (i != (total - 1))
index = nextIndex (index, maxLength, inputs.length);
// Set the print here everything looks fine
System.out.println(Arrays.toString(allList.get(i)));
}
// However, if you pit it here to check if you get the correct ArrayList, problem happens
//for (int g = 0; g < total; g++)
//System.out.println(Arrays.toString(allList.get(g)));
Another part is:
// Get the index of the next possible combination
public static int[] nextIndex (int[] index, int maxLength, int siZe)
{
for (int i = (maxLength - 1); i > 0; i--)
{
if (index[i] == (siZe - 1))
{
index[i] = 0;
if(index[i-1] == (siZe - 1)){
continue;
}
index[i - 1]++;
break;
}else{
index[i]++;
break;
}
}
The idea of this part of my program is to generate all possible combinations (with replacement) from the String array "inputs" and store the combinations into an overall ArrayList. Printing them out just my habit to check whether each step is correct or not.
The wrong output that I keep getting (just part of the output):
[6, 6, 6, 6]
[6, 6, 6, 6]
[6, 6, 6, 6]
[6, 6, 6, 6]
[6, 6, 6, 6]
[6, 6, 6, 6]
The correct output that I want to get:
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 1, 3]
[1, 1, 1, 4]
[1, 1, 1, 5]
[1, 1, 1, 6]
You are creating the subsets array just outside the for loops, so you are always updating the same array. this is the reason why, at the end you get the last permutation.
move the "String[] subSets = new String[maxLength];" just inside the for loop related to "i"
for (int i = 0; i < total; i++)
{
//create the new array here
String[] subSets = new String[maxLength];
...
}
and you will get the right output:
1296
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 1, 3]
[1, 1, 1, 4]
[1, 1, 1, 5]
.....
[6, 6, 6, 4]
[6, 6, 6, 5]
[6, 6, 6, 6]
You are creating the subSets Array outside your for loop and hence everything in the list is referring to the last updated subSets object i.e. [6, 6, 6, 6]. You are adding the same object to your list again and again and hence it will update the latest values at all the places in your list.
Move it inside your for loop as follows:
for (int i = 0; i < total; i++)
{
/* Move It Here */
String[] subSets = new String[maxLength];
for (int j = 0; j < maxLength; j++)
{
subSets[j] = inputs[index[j]];
}
allList.add(subSets);
if (i != (total - 1))
index = nextIndex (index, maxLength, inputs.length);
}

Categories