Making a copy of the second half of an array - java

I want to make a function that takes as parameters an array and a boolean. The boolean tells the function if the rest of the division of the array is to be included. It then returns a new array which is the copy of the second half of the first:
secondHalf({1, 2, 3, 4, 5}, true) → {3, 4, 5}
secondHalf({1, 2, 3, 4, 5}, false) → {4, 5}
For this assignment, I'm not supposed to use any other classes.
Here's what I've attempted:
static int[] secondHalf(int[] vector, boolean include) {
int size = vector.length/2;
if(vector.length%2 == 0)
include = false;
if(include)
size ++;
int[] vector_2 = new int[size];
int i = 0;
while(i < size){
if(include)
vector_2[i] = vector[i+size-1];
vector_2[i] = vector[i+size+1];
i++;
}
return vector_2;

To find the size of vector_2, I've decided to use compound assignment operators. So the first part of this solution checks for the required condition and assigns a value to size in a single statement.
Since we know how many times to iterate over the loop, I think a for loop would be more appropriate than a while loop.
The loop retrieves all the values in vector from the middle of the array to the end of the array and places each value into vector_2.
static int[] secondHalf(int[] vector, boolean include) {
int size = vector.length/2 + (include && vector.length%2 != 0 ? 1 : 0);
int[] vector_2 = new int[size];
for(int i = 0; i < size; i++)
vector_2[i] = vector[vector.length - size + i];
return vector_2;
}

People have hinted at System#arraycopy, but with Arrays.copyOfRange there is an even simpler method, where you only have to define the proper start index and directly receive the copy.
The start index is array.length / 2 by default. Iff the include flag is true, then you have to add the remainder of dividing the array length by 2 to that.
An MCVE:
import java.util.Arrays;
public class ArrayPartCopy
{
public static void main(String[] args)
{
int array0[] = { 1, 2, 3, 4, 5 };
System.out.println("For " + Arrays.toString(array0));
System.out.println(Arrays.toString(secondHalf(array0, true)));
System.out.println(Arrays.toString(secondHalf(array0, false)));
int array1[] = { 1, 2, 3, 4 };
System.out.println("For " + Arrays.toString(array1));
System.out.println(Arrays.toString(secondHalf(array1, true)));
System.out.println(Arrays.toString(secondHalf(array1, false)));
}
static int[] secondHalf(int[] array, boolean include)
{
int start = array.length / 2;
if (include)
{
start += array.length % 2;
}
return Arrays.copyOfRange(array, start, array.length);
}
}
The output is
For [1, 2, 3, 4, 5]
[4, 5]
[3, 4, 5]
For [1, 2, 3, 4]
[3, 4]
[3, 4]

Related

Google Foobar challenge Minion Work Assignment Java test cases not passing

I have tried solving this problem using Java and for some reason only 2 out of 9 test cases pass but locally all my test cases pass. I am 99% positive that there is some issue with Google Foobar Java test cases for this challenge. Did someone encounter this and if yes, what did you do to solve it?
Question was...
Write a function called solution(data, n) that takes in a list of
less than 100 integers and a number n, and returns that same list
but with all of the numbers that occur more than n times removed
entirely.
The returned list should retain the same ordering as the original
list - you don't want to mix up those carefully-planned shift
rotations! For instance, if data was [5, 10, 15, 10, 7] and n was 1,
solution(data, n) would return the list [5, 15, 7] because 10 occurs
twice, and thus was removed from the list entirely.
-- Java cases --
Input:
Solution.solution({1, 2, 3}, 0)
Output:
Input:
Solution.solution({1, 2, 2, 3, 3, 3, 4, 5, 5}, 1)
Output:
1,4
There are 6 more test cases that are hidden.
Below is the solution I created.
public class MinionShift {
public static int[] solution(int[] data, int n) {
if(n<1)
return new int[0];
if(data.length < 1)
return data;
Map<Integer, Integer> map = new HashMap<>();
for(int d: data) {
map.put(d, map.getOrDefault(d, 0) + 1);
}
return Arrays.stream(data).filter(c->map.containsKey(c) && !(map.get(c)>n)).toArray();
}
}
Test cases that I have tried...
[{1, 2, 3}, 0]
[{1, 2, 2, 3, 3, 3, 4, 5, 5}, 1]
[{1, 2, 2, 3, 3, 3, 4, 5, 5}, 10]
[{1, 2, 2, 3, 3, 3, 4, 5, 5}, -1]
[{}, 5]
[{1, 1, 1, 1, 1}, 5]
[{101, 102, 103, 104, 105}, 5]
Edit...
I tried a Java stream based solution as follows but unfortunately the challenge went away as I submitted a Python solution. But I am posting it here anyways.
public class MinionShift {
public static int[] solution(int[] data, int n) {
if(n<1)
return new int[0];
if(data.length < 1)
return data;
return Arrays.stream(data).filter(d->Arrays.stream(data).filter(i->i==d).count()<=n).toArray();
}
}
This is how I got it to work, you have to work backwards with the array. You need to create another array to check for duplicates to remember them.
public static int[] solution(int[] data, int n){
if(n < 1){
return new int[0];
}
if(data.length < 1){
return data;
}
List<Integer> a = Arrays.stream(data).boxed().collect(Collectors.toList());
for(int i = a.size()-1; i > -1; i--){
ArrayList<Integer> t = new ArrayList<>();
for(int j = 0; j < a.size(); j++){
if(a.get(j) == a.get(i)){
t.add(j);
}
}
if(t.size() > n){
for(int j = t.size()-1; j > -1; j--){
a.remove((int) t.get(j));
}
i -= t.size()-1;
}
}
data = new int[a.size()];
int c = 0;
for(int d : a){
data[c] = d;
c++;
}
return data;
}

How do I correct this For Each loop in java (incorrect output on final test)?

I'm struggling to run this java correctly with a for each loop. It is fine for every test but the last. Could anyone kindly assist in letting me know where I'm going wrong? I feel confident I could do it with a for loop but would like to do it with a for each loop (if suitable).
Drill Question:
Given an array of ints, return true if the sequence of numbers 1, 2, 3 appears in the array somewhere.
arrayOneTwoThree([1, 1, 2, 3, 1]) -> true.
arrayOneTwoThree([1, 1, 2, 4, 1]) -> false.
arrayOneTwoThree([1, 1, 2, 1, 2, 3]) -> true.
For example:
int[] array = {2, 1, 2, 3, 2, 3, 2, 4, 1};
System.out.println(arrayOneTwoThree(array));
Result: true
public static void main(String[] args) {
//int[] array = {2, 1, 2, 3, 2, 3, 2, 4, 1};
//int[] array = {1, 1, 2, 3, 1};
//int[] array = {1, 1, 2, 4, 1};
int[] array = {1, 1, 2, 1, 2, 3};
System.out.println(arrayOneTwoThree(array));
}
public static boolean arrayOneTwoThree(int[] nums) {
for (int num : nums) {
//System.out.print(num);
if (nums[num] == 3 && nums[num-1] == 2 && nums[num-2] == 1)
return true;
}
return false;
}
In the loop, num is NOT the index within the array, it is the value.
I think you are expecting num to be the index, which would be the case if you did a for loop of the form for (int num =0; num < nums.length; num++)
If you want to compare n adiacent elements of array you have to use a loop ending to length - n - 1 : in your case n = 3 so your method can be written like below:
private static boolean arrayOneTwoThree(int[] array) {
final int n = array.length;
if (n < 3) { return false; } //<-- for arrays with less than 3 elements
for (int i = 0; i < n - 2; ++i) {
if (array[i] == 1 && array[i + 1] == 2 && array[i + 2] == 3) {
return true;
}
}
return false;
}
First tree test cases accidentally shoved correct result!
Your code works ONLY for cases, when index of 1 is 1, index of 2 is 2, and index of 3 is 3:
[*, 1, 2, 3, ......... ]
You are probably confused with another programming language. (Maybe for in construction of JavaScript?).
In Java for each over array (or anything else) iterates over values and never over indexes. (As was already specified)
I can see commented out System.out.print(num); why you've ignored it prints values not indexes?
Another issue is ignoring array bounds... Try to examine your code with next array:
int[] array = {2, 3, 2, 1, 2, 3};
It'll end up with ArrayIndexOutOfBoundsException
And answer for your question, how to solve with for each.
Yes, you can introduce external counter, but what would be the sense then?
public static boolean arrayOneTwoThree(int[] nums) {
int i = 0;
for (int num : nums) {
//System.out.print(num);
if (i < 2) continue; // we do not want ArrayIndexOutOfBoundsException happened, right?
if (nums[i] == 3 && nums[num-1] == 2 && nums[num-2] == 1)
return true;
}
return false;
}
If you wish to use for each you should avoid of using indexes to be consistent.
There could be tons of different solutions. You can use some flags or save previous and beforePrevious:
public static boolean arrayOneTwoThree(int[] nums) {
int beforePrevious;
int previous = 0;
int current = 0;
for (int num : nums) {
//System.out.print(num);
beforePrevious = previous;
previous = current;
current = num;
if (current == 3 && previous == 2 && beforePrevious == 1)
return true;
}
return false;
}
Beware: It's just first thought, so this solution may be not optimal and far from perfect, probably you can do better.

How do you split an Array List into sublists everytime there is a duplicate value in the Array List

I have the following array list which contains the following
point ids (1,2,3,4,1,8,5,6,8,9,7,9). I am using Java 7
I was wondering how it could be split into sublists i.e the sublists below
(1,2,3,4,1)
(8,5,6,8)
(9,7,9)
I have had problems trying to use a loop within a loop (i.e check each point
from the outer loop with each of the other points in the inner loop) to get
index positions (starPosIndex and endPosIndex) where there are duplicate point ids and ArrayList.sublist(startPosIndex,endPosIndex) to get the correct sublist
int startPos = 0;
int endPos = 0;
for (int j = 0; j < polygonList3.size(); j++){
Point pointToCheck = polygonList3.get(j);
for (int k = 1; k < polygonList3.size(); k++){
Point pointToCheck2 = polygonList3.get(k);
if (pointToCheck.getID() == pointToCheck2.getID()){
startPos = startPos + endPos;
endPos = endPos + k;
//startPos = startPos + endPos;
//for (int startPos = j; startPos < polygonList3.size(); startPos = (startPos) + endPos) {
//endPos = Math.min(startPos + endPos, polygonList3.size());
finalPolygonLists.add(new ArrayList<Point>(polygonList3.subList(startPos, endPos)));//originalPtsSublist2);
//}
}
}
I would solve it in the following manner:
Allocate a HashSet to contain unique values encountered
Allocate a new list for the first sublist
Iterate over the whole list, adding each value to the set. When we encounter a value that is already in the set, we are done with the first sublist, so clear the set, and allocate a new sublist
After iteration, you will have your list of sublists, obtained in O(n) runtime
You can walk along the list, and create slices of the list (using List#subList) as you go. This can be done efficiently, by always checking whether the first element of the current segment of the list appears somewhere else in the list. If it does, you can store this "slice", and continue with the "tail" of the list. If it doesn't, you are finished (and the tail of the list may or may not be part of the result - that's up to you)
Implemented here as an example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ListSlicing
{
public static void main(String[] args)
{
runTest(1,2,3,4,1,8,5,6,8,9,7,9);
runTest(1,2,3,4);
runTest(1,1,1,1);
runTest(1,2,1,2,1,2,1,2,1,2,1,2);
runTest();
}
private static void runTest(Integer ... numbers)
{
List<Integer> list = Arrays.asList(numbers);
System.out.println("Input: "+list);
System.out.println("Output: "+slices(list));
}
private static <T> List<List<T>> slices(List<T> input)
{
List<List<T>> slices = new ArrayList<List<T>>();
List<T> current = input;
while (current.size() > 0)
{
T first = current.get(0);
int appearance = current.subList(1, current.size()).indexOf(first);
if (appearance == -1)
{
slices.add(current);
return slices;
}
List<T> slice = current.subList(0, appearance+2);
slices.add(slice);
current = current.subList(appearance+2, current.size());
}
return slices;
}
}
The output is
Input: [1, 2, 3, 4, 1, 8, 5, 6, 8, 9, 7, 9]
Output: [[1, 2, 3, 4, 1], [8, 5, 6, 8], [9, 7, 9]]
Input: [1, 2, 3, 4]
Output: [[1, 2, 3, 4]]
Input: [1, 1, 1, 1]
Output: [[1, 1], [1, 1]]
Input: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
Output: [[1, 2, 1], [2, 1, 2], [1, 2, 1], [2, 1, 2]]
Input: []
Output: []
The following code tracks the last position for each number and as soon as it founds a duplicate, it will create the sublist and clears all previously tracked entries.
List<Integer> list = Arrays.asList( 1,2,3,4,1,8,5,6,8,9,7,9);
List<List<Integer>> sublists = new ArrayList<>();
Map<Integer,Integer> lastPos = new HashMap<>();
for(int i = 0; i < list.size(); i++) {
Integer current = list.get(i);
if(lastPos.containsKey(current)){
sublists.add(list.subList(lastPos.get(current), i+1));
lastPos.clear();
} else {
lastPos.put(current, i);
}
}
System.out.println(sublists);

(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);
}

Sum of 4 elements in java array equaling to k, duplicated array elements

I've a homework of a code which searches for four numbers in an array whose sum equals to k (in this example, k = 10). The same array elements can be used more than once. In other words, it sums four elements of the array, compares the sums to value k, and returns true if they are equal, or moves on to other elements if not. So far the code sums four distinct elements of the array but I would need to alter it so that it works also when any single element is used in the sum of four elements more than once, for example if array[2] * 4 == k or array[0] * 2 + array[1] * 2 == k, it returns true.
"static int[][] esim" in the code are example inputs. For instance, {1, 2, 3, 4} returns true, because 1 + 2 + 3 + 4 == k when k = 10. {4, 3, 1, 5, 5, 6, 6} returns false when true is expected, because the code does not take into account duplicated elements and therefore ignores that 2 * 4 + 2 * 1 == k. Similarly {2, 3} returns false when true is expected, although 2 * 2 + 2 * 3 == k.
Anyone could give me a hint how to achieve what I want?
import java.util.Arrays;
public class Etsinta2 {
public static boolean etsi(int[] tl, int k) {
Arrays.sort(tl);
for (int i = 0; i < tl.length; i++) {
int b = i + 1;
int c = i + 2;
int d = tl.length - 1;
while (b < d) {
if (tl[i] + tl[b] + tl[c] + tl[d] == k) {
return true;
} else if (tl[i] + tl[b] + tl[c] + tl[d] < k) {
b++;
c++;
} else {
d--;
}
}
}
return false;
}
static int[][] esim = new int[][]{{5},
{2, 3},
{1, 1, 1, 1},
{1, 2, 3, 4},
{4, 2, 3, 1},
{4, 6, 5, 5},
{6, 4, 5, 5},
{6, 6, 6, 4},
{4, 4, 1, 1, 1, 6, 6},
{9, 1, 1, 1, 1, 5, 6},
{4, 3, 1, 5, 5, 6, 6}};
public static void main(String[] args) {
for (int[] taulu : esim) {
System.out.println(Arrays.toString(taulu) + " 10 : " + etsi(taulu, 10));
}
}
}
Are you checking if the total sum of elements is a multiple of k? If so, you could just sum all elements and check if % (mod) k is zero (i.e. no remainder after dividing by k).
Edit: Okay I read the question again and I think the question is to find 4 numbers from the array (and duplicating the numbers are okay) to sum to k.
(Sorry I tried to delete this answer but couldn't easily)
So here's a swing at the solution: Have four nested loops, one for each "number slot". Let each loop pick one number at a time from the array (therefore allowing duplicate selections). Check the sum in the inner-most loop. If it's k, break w/ true. If not true at the end, false.
Ok, I found a different solution which should bring the time complexity to O(n^2 log n). This uses an auxiliary list which stores all possible sums of pairs of array elements and then compares the sums of pairs of these sums to k. Here's the edited method where I've used an ArrayList. It works fine, except that it's still too slow: the homework is submitted via a robo tester, and a hidden test apparently testing with large numbers, clocks 27.0 ms whereas the required max is 25.0 ms. Is there any way I could speed up the code a little with some minor changes?
public static boolean etsi(int[] tl, int k) {
ArrayList<Integer> summat = new ArrayList<Integer>()
Arrays.sort(tl);
for (int i = 0; i < tl.length; i++) {
for (int j = 0; j < tl.length; j++) {
summat.add(tl[i] + tl[j]);
}
}
int a = 0;
int b = summat.size() - 1;
for (int i = 0; i < summat.size(); i++) {
if (summat.get(a) + summat.get(b) == k) {
return true;
} else if (summat.get(a) + summat.get(b) < k) {
a++;
} else {
b--;
}
}
return false;
}

Categories