Replacing elements in array by the larger of its neighbour - java

I'm currently stuck on this one assignment where I don't know if I got the instructions wrong, or if the code is as it should be. The instructions is:
Replace each element except the first and last by the larger of its two neighbors.
I've completed the code, but the one problem I have is that the last element is being replaced even though it shouldn't. It'd very nice if you could take a look at my code.
public static void replaceWithNeighbours(int[] array) {
for (int i = 1; i < array.length - 1; i++) {
int larger = array[i - 1];
if (larger < array[i + 1]) {
larger = array[i + 1];
}
array[i] = larger;
}
}

A naive solution, the array management can be done better, however this works.
public static void replaceWithNeighbours(int[] array, int[] out) throws Exception
{
// checkif lengths match
if (array.length != out.length)
{
throw new Exception("Lengths don't match");
}
// replace values in output array
out[0] = array[0];
out[out.length - 1] = array[array.length - 1];
for (int i = 1; i < array.length - 1; i++) {
int larger = array[i - 1];
if (larger < array[i + 1]) {
larger = array[i + 1];
}
out[i] = larger;
}
}
Your main problem is that you iterate over the array and update it, however do not consider previous iterations. This means you can look at a neighbor who already holds an updated value and use this value, because the old is overwritten.
Since you also have a problem with the last element being updated:
Go through your code using the debugger or simple print statements and find out where exactly your index 9 is actually accessed. It is not in replaceWithNeighbours, so must be somewhere else. You can solve this by yourself however, just look what indices are used and when you see a 9, look for what is entered and where.

This can be done in a simple way:
public int[] replaceWithNeighbours(int[] arr) {
int[] ret = new int[arr.length];
for (int i = 0; i < arr.length; ++i) {
if (i == 0 || i == arr.length - 1) {
ret[i] = arr[i];
} else {
ret[i] = Math.max(arr[i-1], arr[i+1]);
}
}
return ret;
}
A short explanation: first we create a new array ret which will hold desired result and set it to the same length as original array. Then we loop over contents of original array. If we're dealing with first or last element we just copy them to ret. If we're dealing with other elements, we use Java's Math.max method to determine maximum value of 2 neighbours and set i-th element in ret to that value.

Related

Rearrange elements in an integer array in a fashion where-you first replace and then move the replaced integer to first part of the array

I came across a Hackerearth coding problem where you have to perform the following tasks over an integer array-
Search for a particular number in the array and replace it's occurrences with 1
Move all the 1s to the first part of the array, maintaining the original order of the array
For example- if we have an integer array {22,1,34,22,16,22,35,1}, here we search for the number "22" (let us assume it is present in the array), replace it with 1 and move all those 1s (including the 1s already present) to the first part of the array and the resultant array should look like {1,1,1,1,1,1,34,16,35} -maintaining the original order of the array, preferably in Java.
I actually have coded a solution and it works fine but is not optimal, can anyone help me find an optimal solution (w.r.t. time-space complexity)?
Below is my solution-
public static void main(String[] args) {
int[] n = rearr(new int[] {22,1,34,22,16,22,1,34,1}, 22);
for(int i=0; i<n.length; i++) {
System.out.print(n[i]+" ");
}
}
static int[] rearr(int[] a, int x) {
int[] temp = new int[a.length];
int j=0, c=0, k=0;
//search and replace
for(int i=0; i<a.length; i++) {
if(a[i] == x) {
a[i] = 1;
}
}
//shift all 1s to first part of array or shift all non-1s to last part of the array
for(int i=0; i<a.length; i++) {
if(a[i] != 1) {
temp[j] = a[i];
j++;
}
if(a[i] == 1) {
c++;
}
}
j=0;
for(int i=0; i<a.length && c>0; i++, c--) {
a[i] = 1;
j++;
}
for(int i=j ;i<a.length; i++) {
a[i] = temp[k];
k++;
}
return a;
}
This can be done in linear time and space complexity, by returning a completely new list instead of modifying the original list.
static int[] rearr(int[] a, int x) {
// allocate the array we'll return
int[] b = new int[a.length];
int fillvalue = 1;
// iterate backwards through the list, and transplant every value OTHER than
// (x or 1) to the last open index in b, which we track with b_idx
int b_idx = b.length - 1;
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] != x && a[i] != fillvalue)) {
b[b_idx] = a[i];
b_idx--;
}
}
// once we've gone through and done that, fill what remains of b with ones
// which are either original or are replacements, we don't care
for (int i = b_idx; i >= 0; i--) {
b[i] = fillvalue;
}
return b;
}
This is linear space complexity because it requires additional space equal to the size of the given list. It's linear time complexity because, in the worst case, it iterates over the size of the list exactly twice.
As a bonus, if we decide we want to leave the original 1s where they were, we can do that without any trouble at all, by simply modifying the if condition. Same if we decide we want to change the fill value to something else.
Doing this with constant space complexity would require O(n^2) list complexity, as it would require swapping elements in a to their proper positions. The easiest way to do that would probably be to do replacements on a first run through the list, and then do something like bubblesort to move all the 1s to the front.
This can be done in a single iteration through the array. We can use 2 pointer approach here where we will use on pointer to iterate through the array and other one to point to the index of 1 in the array.
The code is below:
public static void main(String[] args) {
// input array
int[] arr = { 22, 1, 34, 22, 16, 22, 35, 1, 20, 33, 136 };
// element to be replaced
int x = 22;
int j = -1;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 1 || arr[i] == x) {
if (j == -1) {
j = i;
}
// incase arr[i]==x
arr[i] = 1;
} else {
if (j != -1) {
arr[j] = arr[i];
arr[i] = 1;
j--;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
Here we initialise j=-1 since we consider there are no 1's present in the array.
Then we start iterating the array from the end towards the starting of the array as we have to push all the 1's to the starting of the array. Now when we reach to 1 or x (particular number in your case), we check if this is first occurrence of the x or 1, if yes then we initialise the j with this index and change arr[i] = 1 because this could be equal to x then we need to make it 1. If the arr[i] is not 1 or x it means its a number which we need to push at back of the array. We check if we have position of 1 or j=-1. If j=-1 it means this number is already pushed back at end of array else we swap the number at i and j, and decrement j by 1.
At the end of the array we will have the array sorted in a fashion which is required.
Time Complexity: Since we are only iterating the array one, hence the time complexity is O(n).
Space Complexity: Since there are no extra space being used or constant space being used hence the space complexity is O(1)

Gnomesort only works for first two strings

I need to implement a gnomesort to sort strings on how close they are to the string input. I measure this difference with the Levenshtein-algoritm.
The algoritm works fine but only with if I have two strings in the database. It then sorts it fine, but if there are more than two strings, it just prints them in the order they are in the database. I really can't find the problem
public static void retrieveFromDatabase(String string)
{
String[] sq = new String[database.size()];
database.toArray(sq);
int r = 0, index = 1, y = 2, tmp1 = 0;
String tmp2;
int[] ds = new int[sq.length];
for (int i = 0; i < database.size(); i++) {
ds[i] = sortLevenshtein(string, database.get(i), false);
}
for(index = 1; index < ds.length; index++) // gnomsort
{
if(ds[index - 1] <= ds[index] )
{
++index;
}
else
{
tmp1 = ds[index];
tmp2 = sq[index];
ds[index] = ds[index - 1];
sq[index] = sq[index - 1];
ds[index-1] = tmp1;
sq[index-1] = tmp2;
index--;
if (index == 0)
index++;
}
}
System.out.println("Best matches: ");
for(r=0; r<Math.min(3,sq.length); r++)
{
System.out.println(ds[r] + "\t" + sq[r]);
}
}
The problem
Your gnome sort is not sorting correctly when there are more than two elements to sort.
In your problematic case your ds contains 1, 1, 0 from the outset. In your for loop index is 1. You see that the elements at indices 0 and 1 are in the correct order (both elements are 1), so you increment index to 2 in the if statement. Next your for loop also increments index, so it is now 3. 3 is not less than ds.length (also 3), so the loop terminates.
I don’t know gnome sort, so I can’t tell you the fix. What I can tell you is that manipulating your for loop control variable — index in your code — inside the for loop is the sure way to code that is hard to understand and very hard to find errors in. I never ever do that.
for(index = 1; index < ds.length; index++) // OK: loop control variable is incremented here
{
if(ds[index - 1] <= ds[index] )
{
++index; // No-no: incrementing loop control variable, dangerous
}
else
{
tmp1 = ds[index];
tmp2 = sq[index];
ds[index] = ds[index - 1];
sq[index] = sq[index - 1];
ds[index-1] = tmp1;
sq[index-1] = tmp2;
index--; // No-no: decrementing loop control variable, problematic
if (index == 0)
index++; // No-no: incrementing loop control variable
}
}

Find the first duplicate with the minimal next occurrence

I am trying to solve a challenge,
I wrote my solution and it passes all test cases except some hidden test cases. I can't think another case in which my method fails and don't know what to do anymore.
Here it is:
int firstDuplicate(int[] a) {
int[] indexCount;
int duplicate, temp;
boolean check;
duplicate = -1; temp = a.length;
indexCount = new int[a.length];
check = false;
for( int i = 0; i < a.length; i++ ){
if( indexCount[a[i]-1] == 0 ){
indexCount[a[i]-1] = i+1;
check = false;
}else{
indexCount[a[i]-1] = (i+1) - indexCount[a[i]-1];
check = true;
}
if( check && indexCount[a[i]-1] < temp ){
duplicate = a[i];
temp = indexCount[a[i]-1];
}
}
return duplicate;
}
Instructions are:
Write a solution with O(n) time complexity and O(1) additional space complexity.
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index.
Example
For a = [2, 3, 3, 1, 5, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than than second occurrence of 2 does, so the answer is 3.
For a = [2, 4, 3, 5, 1], the output should be
firstDuplicate(a) = -1.
Here is what I have. Runs in O(n) and uses O(1) space. Correct me if I'm wrong here.
Since my input cannot have a value that's more than the length, I can use mod operator for indexing on the same array and add the length to the value in index. As soon as I encounter a value that larger than the length, that means I've already incremented that before, which gives me the duplicate value.
public int firstDuplicate(int[] arr) {
int length = arr.length;
for (int i = 0; i < length; i++) {
int expectedIndex = arr[i] % length;
if (arr[expectedIndex] > length) {
return arr[i] > length ? arr[i] - length : arr[i];
} else {
arr[expectedIndex] += length;
}
}
return -1;
}
This answer is based on #Mehmet-Y's answer and all credit goes to Mehmet-Y. This version addresses the three issues I pointed out in the comments. I will delete this answer if the original gets corrected.
The general approach is to use the original array for storage instead of allocating a new one. The fact that no value may be less than one or greater than the length suggests that you can use the array as a set of indices to flag an element as "already seen" by either negating it or adding/subtracting the array length to/from it.
To achieve O(n) time complexity, you have to solve the problem in a fixed number of passes (not necessarily one pass: the number just can't depend on the size of the array).
But how do you decide which duplicate has the smallest second index? I would suggest using two different flags to indicate an index that is already seen vs. the second item in a duplicate pair. For this example, we can set the index flag by incrementing the elements by the length, and marking duplicates by negating them. You will need a second pass to find the first negagive in the array. You can also use that pass to restore the elements to their original values without sacrificing O(n) time complexity.
Here is a sample implementation:
int firstDuplicate(int[] a)
{
// assume all elements of a are in range [1, a.length]
// An assertion of that would not increase the time complexity from O(n)
int len = a.length;
for(int i = 0; i < len; i++) {
// a[i] may be > len, but not negative.
// Index of bin to check if this element is already seen.
flagIndex = (a[i] - 1) % len;
if(a[flagIndex] > len) {
// If already seen, current element is the second of the pair.
// It doesn't matter if we flag the third duplicate,
// just as long as we don't tag the first be accident.
a[i] = -a[i];
} else {
// Flag the element as "already seen".
// This can be done outside the else, but you might run
// into (more) overflow problems with large arrays.
a[flagIndex] += len;
}
}
// Search and stash index of first negative number
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
return -a[i] % len;
}
}
// Nothing found, oh well
return -1;
}
If you want to take advantage of the second pass to restore the original values of the array, replace
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
return -a[i] % len;
}
}
return -1;
with
int duplicate = -1;
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
a[i] = -a[i];
if(duplicate == -1) {
duplicate = a[i] % len;
}
}
a[i] %= len;
}
return duplicate;

Finding all possible subset sum which is equal to 0 out of set of positive and negative numbers? [duplicate]

This question already has answers here:
given a set of n integers, return all subsets of k elements that sum to 0
(3 answers)
Closed 6 years ago.
You have an array which has a set of positive and negative numbers, print all the subset sum which is equal to 0.
I can think of approach where i can cam make all powersets of givcen array and check if their sum is 0. BUt that does not llok like optimized solution to
me.
After reading looks a bit similar problem on net , looks like it can be solved with dynamic programming like below program to find if there is combination exist
to make sum 11 just an example ?
public boolean subsetSum(int input[], int total) {
boolean T[][] = new boolean[input.length + 1][total + 1];
for (int i = 0; i <= input.length; i++) {
T[i][0] = true;
}
for (int i = 1; i <= input.length; i++) {
for (int j = 1; j <= total; j++) {
if (j - input[i - 1] >= 0) {
T[i][j] = T[i - 1][j] || T[i - 1][j - input[i - 1]];
} else {
T[i][j] = T[i-1][j];
}
}
}
return T[input.length][total];
}
public static void main(String args[]) {
TestDynamic ss = new TestDynamic();
int arr1[] = {2, 3, 7, 8};
System.out.print(ss.subsetSum(arr1, 11));
}
But i am not sure how to extend above programe to
1) Include negative number
2) find combination of elements whick makes sum as zero( Above program just finds whether its possible to make given sum but does not
find which set of numbers makes it zero)
Here is a full implementation in Javascript. You can run it with node.js.
function target_sum(a, k, x)
{
if (k == a.length) return [];
if (a[k] == x) {
return [[a[k]]];
} else {
var s = target_sum(a, k + 1, x); // not using a[k]
var t = target_sum(a, k + 1, x - a[k]); // using a[k]
for (var i = 0; i < t.length; ++i) {
t[i].unshift(a[k]); // a[k] is part of the solution
s.push(t[i]); // merge t[] into s[]
}
return s;
}
}
var s = target_sum([1,4,5,2,7,8,-3,-5,-6,9,3,-7,-1,5,6], 0, 0);
for (var i = 0; i < s.length; ++i)
console.log(s[i].join(","));
Note that this is an exponential algorithm. Don't use it on large arrays.
Erwin Rooijakkers also pointed to the right direction. In particular, this post gives another algorithm. I could be wrong about the following – I believe that algorithm trades speed for space. It avoids staging arrays into the call stack, but it has to do more recursions to achieve that.
EDIT: about the algorithm you mentioned. It is not exponential, but it only works for positive numbers if I am right. Its time complexity is also proportional to the target sum, which may not be ideal depending on input.

Count The Amount Of Data In An Array Including SOME Null

I'm coding in java and I need to create a function that returns the number of data objects that are currently in an ArrayList. At the moment I have this:
int count = 0;
for (int i = 0; i < data.length; i++)
{
if (data[i] != null)
{
count ++;
}
}
return count;
But the problem is that an array list that includes null data is acceptable, and I have to count their null data towards this counter. How do I include the null data that's in the middle of this array, and not the null data that's not supposed to be counted for?
For example, I have some tester code that adds (8),null,null,(23),(25) to the array, and this function should return 5 when the initial array size is 10.
I'm going to assume you're using a regular array (your question is somewhat ambiguous about this). Traverse through the array backwards until you find a non-null element:
public static int count(Object[] a) {
int i = a.length - 1;
for (; i >= 0 ; i--)
if (a[i] != null)
break;
return i + 1;
}
You could also have
public static <T> int count(T[] a) {
int i = a.length - 1;
for (; i >= 0 ; i--)
if (a[i] != null)
break;
return i + 1;
}
Let's test it out, using an example analogous to the one you provided:
Object[] a = new Object[10];
a[0] = new Object();
a[3] = new Object();
a[4] = new Object();
System.out.println(count(a));
Output:
5
You will need two separate counters. The first one will count normally. The second one starts counting when you find null data. Then when you find a non-null data, just add the second counter to the first one and continue counting with the first counter until you find a null again.
int count = 0;
for (int i = data.length - 1; i >= 0; i--)
if (data[i] != null || count > 0)
count += 1;
return count;
At least that's how I understood your requirements - count nulls, except for trailing nulls.
But maybe that's not actually what you meant?
Edit
Unless you're actually using ArrayList (as Jon was asking), where .size() is different from capacity and will count all added elements (including nulls). You can't actually even get the capacity from an ArrayList.

Categories