Is there a simpler solution for Codingbat fix45? - java

I am trying to solve this CodingBat problem:
(This is a slightly harder version of the fix34 problem.) Return an array that contains exactly the same numbers as the given array, but rearranged so that every 4 is immediately followed by a 5. Do not move the 4's, but every other number may move. The array contains the same number of 4's and 5's, and every 4 has a number after it that is not a 4. In this version, 5's may appear anywhere in the original array.
fix45({5, 4, 9, 4, 9, 5}) → {9, 4, 5, 4, 5, 9}
fix45({1, 4, 1, 5}) → {1, 4, 5, 1}
fix45({1, 4, 1, 5, 5, 4, 1}) → {1, 4, 5, 1, 1, 4, 5}
I initially used a method which passed all of the sites tests, but I don't think it would work for longer arrays. The initial method used 2 loops and did not use a new array. I have created a solution which introduces a new array and a 3rd nested loop and I believe will work for all instances of the problem. However, the site states that the problems in this section can be solved with 2 loops, so I am wondering if there actually is a 2 loop solution that will work for anyinstance of the problem. Here is the question and my 3 loop solution:
public int[] fix45(int[] nums) {
int[] locations = {-1};
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i] == 4) {
JLoop:
for (int j = nums.length-1; j >= 0; --j) {
if (nums[j] == 5) {
for (int k = locations.length-1; k>=0 ; --k) {
if (locations[k] == j) {
continue JLoop;
}
}
nums[j] = nums[i + 1];
nums[i + 1] = 5;
locations[locations.length - 1] = i+1;
locations = java.util.Arrays.copyOf(locations,
locations.length + 1);
locations[locations.length-1] = -1;
break;
}
}
}
}
return nums;
}

Restarting the search for a suitable 5 from one end of the array every time a 4 is found seems wasteful. Part of the array has already been scanned and is known not to contain a 5 that can be moved. This is O(n) time and O(1) space.
public static int[] fix45(int[] nums) {
int j = 0;
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i] == 4 && nums[i + 1] != 5) {
/*
* Need to find the next movable 5 That means an element that is 5 and
* either is the first element or is preceded by anything other than 4
*/
while (nums[j] != 5 || (j != 0 && nums[j - 1] == 4)) {
j++;
}
nums[j] = nums[i + 1];
nums[i + 1] = 5;
}
}
return nums;
}

Using an extra array, here's a solution with "one loop" (loops without nested loops):
public int[] fix45(int[] nums) {
int[] otherValues = new int[nums.length];
for(int i = 0, c = 0; i < nums.length; i++)
if(nums[i] != 4 && nums[i] != 5)
otherValues[c++] = nums[i];
for(int i = 0, c = 0; i < nums.length; i++)
if(nums[i] == 4)
nums[++i] = 5;
else
nums[i] = otherValues[c++];
return nums;
}
We fix the fours, take out the non-fours and non-fives, and put the values all back in in order.
To improve the space usage (perhaps not by much), you can count the number of fours before you make the extra array.

public int[] fix45(int[] nums) {
int t=0;
for(int i=0; i< nums.length ; i++)
for(int j=0;j<nums.length ; j++)
if(nums[i]==5 && nums[j]==4)
{
t=nums[j+1];
nums[j+1]=nums[i];
nums[i]=t;
}
return nums;
}

The following method will run in O(n) time using O(n) space:
public int[] fix45(int[] nums) {
if (nums == null || nums.length <= 1) {
return nums;
}
// store all the 5s pos
int[] pos = new int[nums.length];
int j = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 5) {
pos[j++] = i;
}
}
j = 0;
for (int i = 0; i <= nums.length - 2; i++) {
if (nums[i] == 4 && nums[i + 1] != 5) {
if (j >= pos.length) {
System.err
.println("No more 5s: there are more 4 than 5 in the input array");
break;
}
// fix45 swapping
nums[pos[j++]] = nums[i + 1];
nums[i + 1] = 5;
}
}
return nums;
}

public int[] fix45(int[] nums) {
int idx4 = -1;
int idx5 = -1;
while (true) {
while (true) { // find a 4 without a 5 after it
idx4 = find(nums, 4, ++idx4);
if (idx4 == -1) // done if no more 4's
return nums;
if (nums[idx4+1] != 5)
break;
}
while (true) { // find a 5 without a 4 before it
idx5 = find(nums, 5, ++idx5);
if (idx5 == 0 || nums[idx5-1] != 4)
break;
}
nums[idx5] = nums[idx4+1]; // swap the 4 and 5
nums[idx4+1] = 5;
}
}
public int find(int[] nums, int num, int start) {
for (int i = start; i < nums.length; i++)
if (nums[i] == num)
return i;
return -1;

Fix after dansalmos remark:
public int[] fix45(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 4) {
if(nums[i+1] == 5) continue;
for( int j = 0; i < nums.length; j++){
if(nums[j] == 5 && (j==0 || nums[j-1] != 4)){
nums[j] = nums[i+1];
nums[i+1] = 5;
break;
}
}
}
}
return nums;
}

public int[] fix45(int[] nums) {
if (nums.length < 2) {
return nums;
}
int index = 0;
int index2 = 0;
int index3 = 0;
int[] only5 = fives(nums);
int[] after4 = new int[count4(nums)];
for (int a = 0; a < nums.length - 1; a++) {
if (nums[a] == 4) {
after4[index] = nums[a + 1];
index++;
nums[a + 1] = only5[index2];
index2++;
}
}
//This while loop gets the frst number that is not a 5 that is after a 4
while (nums[0] == 5) {
nums[0] = after4[index3];
index3++;
}
if (nums[nums.length - 2] != 4 && nums[nums.length - 1] == 5) {
nums[nums.length - 1] = after4[index3];
index3++;
}
for (int b = 1; b < nums.length; b++) {
if (nums[b] == 5 && nums[b - 1] != 4) {
nums[b] = after4[index3];
index3++;
}
}
return nums;
}
public int count4(int[] nums) {
int cnt = 0;
for (int e : nums) {
if (e == 4) {
cnt++;
}
}
return cnt;
}
public int[] fives(int[] nums) {
int index = 0;
int[] only5 = new int[count4(nums)];
for (int e : nums) {
if (e == 5) {
only5[index] = e;
index++;
}
}
return only5;
}
//long solution, scroll up

I realise this thread is years old, but I just wanted to add my solution:
public int[] fix45(int[] nums){
int notAFourOrFive = 0;
int[] ary = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 4) {
ary[i] = 4;
ary[i+1] = 5;
}
else if (nums[i] != 5) {
notAFourOrFive = nums[i];
}
}
for (int j = 0; j < ary.length; j++) {
if (ary[j] == 0) {
ary[j] = notAFourOrFive;
}
}
return ary;
}
Seeing as the amount of 4s and 5s are equal, it is safe to add them to a new array whenever a 4 is found. It is safe to use i+1 in this case, because a 4 never comes at the end of the array. It is also safe to set the 'other' number whenever a non-4 or non-5 is reached, because all the other numbers are the same, in each test.

public int[] fix45(int[] nums)
{
for(int i=0; i<nums.length; i++)
{
if(nums[i]==5)
{
for(int j=0; j<nums.length; j++)
if(nums[j]==4&&nums[j+1]!=5)
{
f(nums, i, j+1);
}
}
}
return nums;
}
///this "helper" function swaps 2 elements of the array
public void f(int []nums , int m, int n)
{
int t= nums[m];
nums[m] =nums[n];
nums[n] = t;
}

public int[] fix45(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 5 && i == 0 || nums[i] == 5 && nums[i - 1] != 4) {
int a5 = i;
for (int j = 0; j < nums.length; j++) {
if (nums[j] == 4 && nums[j + 1] != 5) {
int temp = nums[j + 1];
nums[j + 1] = 5;
nums[a5] = temp;
break;
}
}
}
}
return nums;
}

Here's a simple solution that works that I have found.
Simply create ArrayLists that track the 4's and 5's, and swap the values.
How's this for easy to understand?
public int[] fix45(int[] nums)
{
//Create a copy array to manipulate and eventually return.
int[] ret = nums;
//Create two ArrayLists that let us track for and five positions.
ArrayList<Integer> fourPositions = new ArrayList<Integer>();
ArrayList<Integer> fivePositions = new ArrayList<Integer>();
//Get the positions of fours and fives and add them to their respective ArrayLists.
for (int i = 0; i < ret.length; i++)
{
if (ret[i] == 4)
{
fourPositions.add(i);
}
if (ret[i] == 5)
{
fivePositions.add(i);
}
}
//Swap all of the places right after the fours with a respective number of the fives,
for (int i = 0; i < fourPositions.size(); i++)
{
int temp = ret[fourPositions.get(i) + 1];
ret[fourPositions.get(i) + 1] = ret[fivePositions.get(i)];
ret[fivePositions.get(i)] = temp;
}
//Return the array.
return ret;
}

This solution uses LinkedHashSet. I think O-notation for time is O(n), and for space is also O(n).
public int[] fix45(int[] nums) {
Set<Integer> ind4 = new LinkedHashSet<>();
Set<Integer> ind5 = new LinkedHashSet<>();
//Store positions for all fours and fives except those fives
//that immediately follow number four.
for (int i = 0; i < nums.length; ++i) {
if (nums[i] == 4){
ind4.add(i);
if (i + 1 < nums.length && nums[i + 1] == 5){
i++;
}
}else if (nums[i] == 5){
ind5.add(i);
}
}
Iterator<Integer> iter5ind = ind5.iterator();
for (Integer i : ind4){
if (i + 1 > nums.length || !iter5ind.hasNext()) break;
if (nums[i + 1] == 5){
continue;
}
int j = iter5ind.next();
int tmp = nums[i + 1];
nums[i + 1] = nums[j];
nums[j] = tmp;
}
return nums;
}

import java.util.Arrays;
public class Fix45 {
public static void main(String[] args) {
assertArrays(new int[]{9, 4, 5, 4, 5, 9}, new int[]{5, 4, 9, 4, 9, 5});
assertArrays(new int[]{1, 4, 5, 4, 5}, new int[]{5, 4, 5, 4, 1});
assertArrays(new int[]{1, 1, 4, 5, 4, 5}, new int[]{5, 5, 4, 1, 4, 1});
assertArrays(new int[]{4, 5, 4, 5, 1}, new int[]{4, 5, 4, 1, 5});
assertArrays(new int[]{4, 5, 4, 5, 2}, new int[]{4, 2, 4, 5, 5});
}
public static int[] fix45(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if(nums[i] == 4 && nums[i + 1] != 5){
int location = i + 1;
for (int j = 0; j < nums.length; j++) {
if(nums[j] == 4 && nums[j + 1] == 5){
j++;
continue;
}
if (nums[j] == 5) {
int temp = nums[j];
nums[j] = nums[location];
nums[location] = temp;
}
}
}
}
return nums;
}
private static void assertArrays(int[] expected, int[] input) {
int[] actual = fix45(input);
System.out.println(Arrays.toString(actual));
boolean status = Arrays.equals(expected, actual);
System.out.println(status);
}
}

There are so many complicated code in here. I think we simplified like this :
public int[] fix45(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 4) {
for (int j = 0; j < nums.length; j++) {
if (nums[j] == 5) {
if (j > 0 && nums[j - 1] != 4) {
int tmp = nums[i + 1];
nums[i + 1] = 5;
nums[j] = tmp;
} else if (j == 0) {
int tmp = nums[i + 1];
nums[i + 1] = 5;
nums[j] = tmp;
}
}
}
}
}
return nums;
}

I just want to add My Solution, as far I tested on CodingBat and passed all test and without use of 2 for loops
public int[] fix45(int[] nums) {
if (nums.length == 0 || nums.length == 1 || nums.length == 2) {
return nums;
}
int indexof4 = 0, indexof5 = 0;
int indexToWorkonForRplcmnt = -1;
while (indexof4 < nums.length && indexof5 < nums.length) {
if ((indexof4 + 1) < nums.length && nums[indexof4] == 4 && nums[indexof4 + 1] != 5) {
indexToWorkonForRplcmnt = indexof4 + 1;
// System.out.println("IndexOf4:"+indexToWorkonForRplcmnt);
} else {
indexof4++;
}
if ((indexof5) < nums.length && nums[indexof5] == 5) {
if (indexof5 == 0 && nums[indexof5] == 5) {
// System.out.println("IndexOf5:"+indexof5);
} else if (nums[indexof5 - 1] != 4 && nums[indexof5] == 5) {
// System.out.println("IndexOf5:"+indexof5);
} else {
indexof5++;
}
} else {
indexof5++;
}
if (indexToWorkonForRplcmnt != -1 && (indexof5) < nums.length && nums[indexof5] == 5) {
System.out.println("IndexOf4:" + indexToWorkonForRplcmnt);
System.out.println("IndexOf5:" + indexof5);
int temp = nums[indexToWorkonForRplcmnt];
nums[indexToWorkonForRplcmnt] = nums[indexof5];
nums[indexof5] = temp;
indexToWorkonForRplcmnt = -1;
indexof4++;
indexof5++;
}
}
return nums;
}

Here is simple answer :)
public int[] fix45(int[] nums) {
int p5=0;//tracker for 5's
for(int i=0;i<nums.length;i++){
if(nums[i] == 4){// got a 4
for(int j = p5 ;j<nums.length;j++){
//finding a 5 for that 4 at nums[i]
if(nums[j] == 5 && ( (j > 0 && nums[j-1]!=4 ) || (j==0) )){
// found 5 and checking if it is not preceded by a 4
//swap if not preceded by a 4
int temp = nums[i+1];
nums[i+1] = nums[j];
nums[j] = temp;
p5 = j;//set the tracker to where we found 5 for nums[i]
break;//break out of loop
}
}
}
}
return nums;
}

It can be done in one while loop also !
public int[] fix45(int[] nums) {
int start = 0;
int end = nums.length-1;
boolean is4 = false;
boolean is5 = false;
while( start < nums.length ){
if(nums[start] == 4 && nums[start+1]!=5){
is4 = true;
}
if(nums[end] == 5 && (end == 0 || (end-1>=0 && nums[end-1]!=4))){
is5 = true;
}
if(is4 && is5){
int temp = nums[start+1];
nums[start+1] = nums[end];
nums[end] = temp;
is4 = false;
is5 = false;
end = nums.length-1;
}
if(is4){
end--;
continue;
}
start++;
}
return nums;
}

public int[] fix45(int[] nums) {
int[] array = new int[nums.length];
int temp = 0;
for (int i = 0; i < array.length; i++) {
if (nums[i]==4) {
array[i] = 4;
array[i+1]= 5;
}
}
for (int i = 0; i < array.length; i++) {
if (nums[i]!=4 && nums[i]!=5) {
temp = nums[i];
}
for (int j = 0; j < array.length; j++) {
if (array[j]==0) {
array[j]=temp;
}
}
}
return array;
}

Simplest probably:
for(int i = 0; i < nums.length; i++){
if(nums[i] == 5 && i == 0 || nums[i] == 5 && nums[i-1] != 4){
int pos5 = i;
for(int j = 0; j < nums.length; j++){
if(nums[j] == 4 && nums[j+1] != 5){
int temp = nums[j+1];
nums[j+1] = 5;
nums[pos5] = temp;
break;
}
}
}
}
return nums;

Related

How do I delete duplicates in my array merging method?

I have a method that takes 2 attributes which are 2 arrays and merges them in the ascending order. All that's left for me is to figure out how to delete duplicates. Here's the code:
public static int[] mergeArrays(int[] a, int[] b){
int[] c = new int[a.length+b.length];
int aIt = 0;
int bIt = 0;
while(true) {
if(aIt < a.length && bIt < b.length) {
if(a[aIt] == b[bIt]){
c[aIt+bIt] = a[aIt++];
}
else{
c[aIt+bIt] = b[bIt++];
}
} else if(aIt < a.length) {
c[aIt+bIt] = a[aIt++];
} else if(bIt < b.length) {
c[aIt+bIt] = b[bIt++];
} else {
break;
}
}
return c;
}
As you can imagine, this is an assignment, so I'm not supposed to use any external libraries, otherwise this would be a lot easier.
I tried this method, but when I run this code in the console it seems to put it in some never-ending loop which consumes my CPU core entirely until I stop the process:
public static int[] mergeArrays(int[] a, int[] b){
int[] c = new int[a.length+b.length];
int aIt = 0;
int bIt = 0;
int lastVal = 0;
while(true) {
if(c[aIt+bIt] == lastVal){
continue;
}
else{
if(aIt < a.length && bIt < b.length) {
if(a[aIt] == b[bIt]){
c[aIt+bIt] = a[aIt++];
lastVal = c[aIt+bIt];
}
else{
c[aIt+bIt] = b[bIt++];
lastVal = c[aIt+bIt];
}
} else if(aIt < a.length) {
c[aIt+bIt] = a[aIt++];
lastVal = c[aIt+bIt];
} else if(bIt < b.length) {
c[aIt+bIt] = b[bIt++];
lastVal = c[aIt+bIt];
} else {
break;
}
}
}
return c;
}
It seems as though the "continue" keyword is the problem. When I try break in its place, the code executes.
EDIT:
I've added a new array to the mergeArrays method:
public static int[] mergeArrays(int[] a, int[] b)
{
int a_size = a.length;
int b_size = b.length;
int[] c = new int[a_size + b_size];
int[] d = null;
int i = 0 , j = 0, x = -1;
for(; i < a_size && j < b_size;)
{
if(a[i] <= b[j])
{
c[++x] = a[i];
++i;
}
else
{
if(c[x] != b[j])
{
c[++x] = b[j]; // avoid duplicates
}
++j;
}
}
--i; --j;
while(++i < a_size)
{
c[++x] = a[i];
}
while(++j < b_size)
{
c[++x] = b[j];
}
d = new int[uniqueValues(c)];
for(int g=0; g<uniqueValues(c); g++){
d[g] = c[g];
}
return d;
}
Well you can certainly do these in following two steps task :
Sort both the arrays.
static void sortArray(int[] a) {
for (int lastPos = a.length - 1; lastPos >= 0; lastPos--) {
for (int index = 0; index <= lastPos - 1; index++) {
if (a[index] > a[index + 1]) {
int temp = a[index];
a[index] = a[index + 1];
a[index + 1] = temp;
}
}
}
}
Remove duplicates while merging them.
public static int[] mergeArrays(int[] a, int[] b)
{
int a_size = a.length;
int b_size = b.length;
int[] c = new int[a_size + b_size];
int i = 0 , j = 0, x = -1;
for(; i < a_size && j < b_size;)
{
if(a[i] <= b[j])
{
c[++x] = a[i];
++i;
}
else
{
if(c[x] != b[j])
{
c[++x] = b[j]; // avoid duplicates
}
++j;
}
}
--i; --j;
while(++i < a_size)
{
c[++x] = a[i];
}
while(++j < b_size)
{
c[++x] = b[j];
}
return c;
}
Count unique values in newly merged array.
static int uniqueValues(int[] c) {
int uniqueValues = c.length;
for (int i = 0; i < c.length; i++) {
while (c[i] == c[i + 1] && i + 1 < c.length && c[i] > c[i+1] ) {
i++;
uniqueValues--;
}
}
return unique;
}
Reestablish the merged array with unique value count i.e. delete the remaining elements after count finishes.
sortArray(a);
sortArray(b);
int[] c = mergeArrays(a, b);
c = deleteDuplicateEntries(c, uniqueValues(c));
Let me know if you find it useful.
Let the libraries work for you:
(Note, that outside of jshell, you have to terminate each non-empty line with ";")
int[] ai = {0, 1, 15, 16, 27, 84, 49, 4, 5 }
int[] bi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 4, 5 }
List <Integer> li = new ArrayList<> ()
Arrays.stream (ai).forEach (i -> li.add (new Integer (i)))
Arrays.stream (bi).forEach (i -> li.add (new Integer (i)))
Collections.sort (li)
int [] res = li.stream().distinct().mapToInt (i -> i.intValue()).toArray()
result in jshell:
for (int i: res) System.out.printf (" %d", i);
0 1 2 3 4 5 6 7 8 9 10 11 12 15 16 27 49 84

How to find number of tuples whose sum is equal or less than a given number?

I'm designing an algorithm to find the number of tuples whose sum is equal or less than a given number. I know other ways of solving it using LinkedList, so, not looking for that solution. I just want to traverse through the array and count the possible matches that satisfy the relation. I come up so far,
public static int numberOfPairs(int[] a, int k ){
int len = a.length;
if (len == 0){
return -1;
}
Arrays.sort(a);
int count = 0, left = 0, right = len -1;
while( left < right ){
if ( a[left] + a[right] <= k ){
// System.out.println(a[left] + "\t" + a[right]);
count++;
/*may be the same numbers will also satisfy the relation*/
if ( a[left] + a[left+1] <= k) {
count ++;
// System.out.println(a[left] + "\t"+a[left+1]);
}
/*now, use iteration to traverse the same elements*/
while (a[left] == a[left+1] && left < len-1 ){
left++;
}
/*may be the same numbers will also satisfy the relation*/
if ( a[right] + a[right-1] <= k) {
count ++;
// System.out.println(a[right] +"\t"+ a[right-1]);
}
/*now, use iteration to traverse
the same elements*/
while ( a[right] == a[right-1] && right >1 ){
right-- ;
}
}
// traverse through the array
left++;
right--;
}
return count;
}
This is not providing the correct solution, say, if I pass array and number as following,
int [] arr = { 3, 3, -1, 4, 2,5, 5, 1};
System.out.println(numberOfPairs(arr, 8));
The correct solution will be 15 pairs as following,
{
{-1,1}, {-1,2} , {3,-1}, {-1,4 }, {-1,5},
{2,1},{3,1 },{4,1}, { 5,1},
{3,2 },{4,2}, {2,5 },
{3,4 } , {3,5 },
{3,3}
}
How can I improve my code ? thanks.
Note: the other way I solve it using LinkedList is as following,
public static int numberOfPairs10(int[] arr, int sum){
/*1.can be the same values of i
2. can be the same valus of j for the same i*/
List<Integer> li = new ArrayList<Integer>();
List<Integer> lj;
int count = 0;
for ( int i =0; i < arr.length -1 ; i++){
if (li.contains(arr[i]) )
continue;
lj = new ArrayList<Integer>();
for (int j = i+1; j < arr.length; j++){
if (lj.contains(arr[j]))
continue;
// if ( arr[i]+ arr[j] <= sum){
if ( arr[i]+ arr[j] == sum){
count++;
lj.add(arr[j]);
}
}
li.add(arr[i]);
}
return count;
}
This is tested with just
int [] arr = { 3, 3, -1, 4, 2,5, 5, 1};
numberOfPairs(arr, 8);
and here is codes
public static int numberOfPairs(int[] a, int k ) {
int len = a.length;
int counter = 0;
boolean isCheckedLeft = false;
boolean isCheckedRight = false;
int i, j, h;
Arrays.sort(a);
for (i = 0; i < len; i++) {
isCheckedLeft = false;
for (j = i - 1; j >= 0; j--) {
if (a[i] == a[j]) {
isCheckedLeft = true;
break;
}
}
if (isCheckedLeft) {
continue;
}
for (j = i + 1; j < len; j++) {
isCheckedRight = false;
for (h = j - 1; h > i; h--) {
if (a[j] == a[h]) {
isCheckedRight = true;
break;
}
}
if (isCheckedRight) {
continue;
}
System.out.print("("+a[i]+", "+a[j]+") ");
if (a[i] + a[j] <= k) {
counter++;
}
}
}
return counter;
}
If you are not too worried about performance then you could just find all unique combinations and then filter according to your condition. For example, using Java 8 streams:
public int numberOfPairs(int[] values, int maxVal) {
return IntStream.range(0, values.length)
.flatMap(i1 -> IntStream.range(i1 + 1, values.length)
.map(i2 -> Arrays.asList(values[i1], values[i2])))
.distinct().filter(l -> l.stream().sum() <= maxVal).count();
}

ArrayIndexOutOfBoundExceptions on certain inputs when sorting elements of an array?

My task is to write a function that rearranges an array so that the odd numbers occur in the beginning of the array, from greatest to least, and the even numbers from least to greatest at the end. We are not allowed to use any other libraries except for the standard input and output streams.
The output works when the numbers are:
{-15, 450, 6, -9, 54}
But if I changed the elements to:
{-55, 45, 6, 11, 54}
There is an exception error. Here is my code:
public class ary1 {
public static void sort(int A[], int n) {
int tmp;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (A[0] % 2 == 0) //even
{
if (A[i] < A[j]) {
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
} else {
if (A[i] > A[j]) {
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
}
}
}
public static void showAray(int A[], int n) {
for (int i = 0; i < n; i++) {
System.out.println(A[i]);
}
}
public static void main(String args[]) {
int array1[] = {-55, 45, 6, 11, 54};
int odd = 0;
int even = 0;
for (int i = 0; i < array1.length; i++) {
if (array1[i] % 2 == 0) {
even++;
} else {
odd++;
}
}
int[] array2 = new int[even];
int[] array3 = new int[odd];
for (int i = 0, j = 0, k = 0; i < array1.length; i++) {
if (array1[i] % 2 == 0) {
array2[j++] = array1[i];
} else {
array3[k++] = array1[i];
}
}
System.out.println("Original array:\n");
showAray(array1, array1.length);
sort(array2, even);
sort(array3, odd);
for (int i = 1; i < array1.length; i++) {
if (i < odd) {
array1[i] = array3[i];
} else {
array1[i] = array2[(i + 1) - even];
}
}
System.out.println("\nAfter sorting:\n");
showAray(array1, array1.length);
}
}
I know there is a logical error here, but I can't figure out what exactly. Is there any way to change the logic to work with all integers? Thanks.
array1[i] = array2[(i + 1) - even];
EDIT - Here is the stacktrace.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at ary.main(arytest.java:67)
Java Result: 1
Change this
array1[i] = array2[(i + 1) - even];
to
array1[i] = array2[i - odd];
I guess this is what you want

How do I find the largest negative value in an array with both positive and negative values?

I need to return the greatest negative value, and if there are no negative values, I need to return zero.
Here is what I have:
public int greatestNegative(int[] list) {
for (int i = 0; i < list.length; i++) {
if (list[i] < 0)
negativeNumbers ++;
}
int j = list.length - 1;
while (j >= 0) {
if (list[j - negativeNumbers] < 0) {
list[j] = 0;
list[j - 1] = list[j - negativeNumbers];
negativeNumbers--;
j--;
}
else{
list[j] = list[j - negativeNumbers];
j--;
}
}
}
You just need to think of this problem as 2 steps:
Only consider negative values in list[].
In the loop within negative values, update current result if (result == 0) or (value > result).
Code:
public int greatestNegative(int[] list) {
int result = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] < 0) {
if (result == 0 || list[i] > result) {
result = list[i];
}
}
}
return result;
}
Just go about finding the max number with an added condition.
public static int greatestNegative(int[] list) {
int max = Integer.MIN;
boolean set = false;
for (int i = 0; i < list.length; i++) {
if (list[i] < 0 && list[i] > max) {
max = arr[i];
set = true;
}
}
if (!set)
max = 0;
return max;
}
Here is the code which return the smallest negative number
public static int greatestNegative(int[] list) {
int negativeNumbers = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] < 0 && list[i] < negativeNumbers)
negativeNumbers = list[i];
}
return negativeNumbers;
}
Input : 1, 2, -3, 5, 0, -6
Output : -6
Input : 1, 2, 3, 5, 0, 6
Output : 0
If you need the greatest negative number then sort array thin search for first negative number
import java.util.Arrays;
class Main {
public static void main(String[] args) {
int arr[] = { 2, 4, 1, 7,2,-3,5,-20,-4,5,-9};
System.out.println(greatestNegative(arr));
}
private static int greatestNegative(int[] arr) {
Arrays.sort(arr);
for (int i = arr.length - 1; i >= 0; i--) {
if (isNegative (arr[i])) {
return arr[i];
}
}
return 0;
}
private static boolean isNegative (int i) {
return i < 0;
}
}
Output : -3
Please check following code, which will
first calculate small number from array,
then check is it positive? if yes return 0 else return negative.
public static int greatestNegative(int[] list)
{
int negativeNumbers = Integer.MAX_VALUE;
for (int i = 0; i < list.length; i++) {
if (list[i] < negativeNumbers)
negativeNumbers = list[i];
}
if(negativeNumbers >=0)
return 0;
else
return negativeNumbers;
}
You have to try this....
public int greatestNegative(int[] list) {
int negNum = 0;
for(int i=0; i<list.length; i++) {
if(list[i] < negNum){
negNum = list[i];
}
}
return negNum;
}
public int largNegative(int[] list) {
int negNum = 0;
boolean foundNeg = false;
for(int i=0; i<list.length; i++) {
if(list[i] < negNum && !foundNeg){
foundNeg = true;
negNum = list[i];
} else if(foundNeg && list[i] < 0 && negNum < list[i]) {
negNum = list[i];
}
}
return negNum;
}
Start by setting your "maxNegative" value to 0. Then assign the first negative number you come across. After that, only assign negative numbers that are higher. If there are no negative numbers, then your "maxNegative" will still be zero.
public static void main(String[] args) {
int arr[] = {2, -1, 4, 1, 0, 7, 2, -3, 5, 9, -4, 5, -9};
int maxNegative = 0;
for (int i = 0; i < arr.length; i++) {
if (maxNegative == 0 && arr[i] < maxNegative) {
// Set the first negative number you come across
maxNegative = arr[i];
} else if (maxNegative < arr[i] && arr[i] < 0) {
// Set greater negative numbers
maxNegative = arr[i];
}
}
System.out.println(maxNegative);
}
Results:
-1
Java 8
Then there are streams, that allow you to do this with one line of code.
public static void main(String[] args) {
int arr[] = {2, 4, 1, 0, 7, 2, -3, 5, 9, -4, 5, -9};
int maxNegative = Arrays.stream(arr).filter(a -> a < 0).max().orElse(0);
System.out.println(maxNegative);
}
Results:
-3

Java > Array-2 > zeroMax

my code only misses 5 cases and i dont know why, somebody help me.
problem
Return a version of the given array where each zero value in the array
is replaced by the largest odd value to the right of the zero in the
array. If there is no odd value to the right of the zero, leave the
zero as a zero.
zeroMax({0, 5, 0, 3}) → {5, 5, 3, 3}
zeroMax({0, 4, 0, 3}) → {3, 4, 3, 3}
zeroMax({0, 1, 0}) → {1, 1, 0}
my code
public int[] zeroMax(int[] nums) {
int acum = 0;
int i = 0;
for( i = 0; i < nums.length;i++){
if(nums[i]==0){
for(int j = i; j < nums.length;j++){
if (nums[j]%2!=0){
acum = nums[j];
break;
}
}
nums[i]=acum;
}
}
return nums;
}
This can be done much more efficiently by rearranging the problem a bit.
Instead of traversing left-to-right, then scanning the integers on the right for the replacement, you can instead just go right-to-left. Then, you can store the previous replacement until you encounter a larger odd number.
public int[] zeroMax(final int[] nums) {
int replace = 0; // Stores previous largest odd - default to 0 to avoid replacement
for (int i = nums.length - 1; i >= 0; i--) { // start from end
final int next = nums[i];
if (next == 0) { // If we should replace
nums[i] = replace;
} else if (next % 2 == 1 && next > replace) {
// If we have an odd number that is larger than the replacement
replace = next;
}
}
return nums;
}
Given your examples, this output:
[5, 5, 3, 3]
[3, 4, 3, 3]
[1, 1, 0]
What you are missing is, that there could be more than one odd number on the right side of your zero and you need to pick the largest one.
Edit: And you also need to reset 'acum'. I updated my suggestion :)
Here's a suggestion:
public int[] zeroMax(int[] nums) {
int acum = 0;
int i = 0;
for (i = 0; i < nums.length; i++) {
if (nums[i] == 0) {
for (int j = i; j < nums.length; j++) {
if (nums[j] % 2 != 0 && nums[j] > acum) {
acum = nums[j];
}
}
nums[i] = acum;
acum = 0;
}
}
return nums;
}
public int[] zeroMax(int[] nums) {
for (int i=0; i<nums.length; i++)
{
if (nums[i] == 0)
{
int maxindex = i;
for (int j=i+1; j<nums.length; j++)
{
if ((nums[j]%2 == 1) && (nums[j] > nums[maxindex]))
{
maxindex = j;
}
}
nums[i] = nums[maxindex];
}
}
return nums;
}
This alows you to find the index of the maximum odd number to the right, replacing the zero with the number at that index
The basic problem is that this algorithm doesn't search for the biggest odd value, but for the first odd value in the array, that is to the right of a given value. Apart from that, you might consider creating a table for the biggest odd value for all indices to simplify your code.
Here is one of the possible solutions to this :)
public int[] zeroMax(int[] nums) {
for(int i=0;i<nums.length;i++){
if(nums[i] == 0){
int val = largestOddValue(nums,i);//finding largest odd value
nums[i] = val; // assigning the odd value
}
}
return nums;
}
//finds largest odd value from the index provided to end
public int largestOddValue(int[] nums,int i){
int value = 0; // for storing value
for(int k=i;k<nums.length;k++){
if(nums[k]%2!=0 && value<nums[k]) // got the odd value
value = nums[k];
}
return value;
}
public int[] zeroMax(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == 0) {
int max = 0;
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] % 2 != 0 && nums[j] > max) {
max = nums[j];
}
}
nums[i] = max;
max = 0;
}
}
return nums;
}
public int[] zeroMax(int[] nums) {
int val = 0;
for(int i = 0; i < nums.length; i++) {
if(nums[i] == 0) {
for(int j = i + 1; j < nums.length; j++) {
if(val <= nums[j]) {
if(nums[j] % 2 == 1) {
val = nums[j];
}
}
}
nums[i] = val;
val = 0;
}
}
return nums;
}
public int[] zeroMax(int[] nums) {
int[] result = nums.clone();
for (int i = nums.length - 1, max = 0; i >= 0; i--)
if (isOdd(nums[i])) max = Math.max(nums[i], max);
else if (nums[i] == 0) result[i] = max;
return result;
}
boolean isOdd(int num) { return (num & 1) == 1; }
We iterate backwards, always storing the biggest encountered odd number (or 0, if none was found) in max.
When we find a 0, we simply override it with max.
The input is untouched to avoid ruining somebody else's input.
Here is the code which works for every input. Try this on your IDE
public int[] m1(int a[]){
int j = 0;
for (int i = 0; i < a.length; i++) {
if(a[i]!=0){
continue;
}
else if(a[i]==0){
j=i;
while(j<a.length){
if(a[j] % 2 != 0){
if(a[i]<=a[j]){
a[i] = a[j];
j++;
}
else{
j++;
continue;
}
}
else{
j++;
continue;
}
}
}
}
return a;
}

Categories