debug problem in the checking, old wizards cult riddle - java

I'm trying to solve this riddle in java, about an old man who lives because his cult who gives the old man some of their life, this specific code should work to the rules which are given but one of the checks in the testing is an error.
public class hello {
/** set true to enable debug */
static boolean debug = true;
static long old(int n, int m, int k, int newp) {
int max;
int min;
boolean moreRows;
if (m > n) {
min = n;
max = m;
moreRows = true;
} else {
min = m;
moreRows = false;
max = n;
}
int sum = 0;
int[][] ar2 = new int[(int)m][(int)n];
// square part
for (int i = 0; i < min; i++) {
for (int j = 0; j < i; j++) {
int t = i ^ j;
ar2[i][j] = t - (t >= k ? k : 0);;
sum += 2 * t- (t >= k ? k : 0);;
}
}
for (int i = min; i < max; i++) {
for (int j = 0; j < min; j++) {
int t = i ^ j;
sum += t;
if (moreRows) {
ar2[i][j] = t - (t >= k ? k : 0);
} else {
ar2[j][i] = t;
}
}
}
//retrun time
while(newp<sum && newp>0) {
sum=sum-newp;//wrap it up
}
return sum;
}
}
here is the assert equals test which contains multiple examples:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class HelloTest {
#Test
public void example() {
assertEquals(5, Hello.olde(8, 5, 1, 100));
assertEquals(224, Hello.old(8, 8, 0, 100007));
assertEquals(11925, Hello.old(25, 31, 0, 100007));
assertEquals(4323, Hello.old(5, 45, 3, 1000007));
assertEquals(1586,Hello.old(31, 39, 7, 2345));
assertEquals(808451, Hello.old(545, 435, 342, 1000007));
// You need to run this test very quickly before attempting the actual tests :)
assertEquals(5456283, Hello.old(28827050410L, 35165045587L, 7109602, 13719506));
}
}
i get the following errors which looks like a long to int-
./src/test/java/HelloTest.java:19: error: incompatible types: possible lossy conversion from long to int
assertEquals(5456283, hello.old(28827050410L, 35165045587L, 7109602, 13719506));
^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
some more errors from harder examples-
assertEquals(5456283, Hello.old(28827050410L, 35165045587L, 7109602, 13719506));
^
./src/test/java/HelloTest.java:39: error: incompatible types: possible lossy conversion from long to int
long expected = Hello.old(m, n, l, t), actual = Hello.old(m, n, l, t);
debug some errors in one of the assert equals and harder examples, I can't really think what can be changed, I'm sure it's something small so help would be appreciated-Note: t will never be bigger than 2^32 - 1(from the instructions of the question)
thanks

The last test will NOT run on a single machine as long values cannot be used as array length and indexes. This has already been explained in the answer/comments to your previous question.
However, it can be deducted from the task that you do not need to store intermediate data in the array at all, you should just calculate the total.
And even if array is not used it is very likely to take a long time to complete the nested loop with 28_827_050_410 * 35_165_045_587L / 2 iterations. If you had a processor with performance of 100 GFlop/s it should be able to count that in over 160 years.
The calculation of t and sum is incorrect.
It should be:
int t = i ^ j;
if (t >= k) {
t -= k;
}
sum += 2 * t; // or sum += t in the second part.
The last loop seems to be replaceable with simple return sum % newp;
Update:
Function old may be refactored as follows (to get rid of the arrays), though it is still a "naive" solution which would not pass the last test.
static int old(int n, int m, int k, int newp) {
int max;
int min;
if (m > n) {
min = n;
max = m;
} else {
min = m;
max = n;
}
int sum = 0;
// square part
for (int i = 0; i < min; i++) {
for (int j = 0; j < i; j++) {
int t = i ^ j;
if (t >= k) {
t -= k;
sum += 2 * t;
}
}
}
for (int i = min; i < max; i++) {
for (int j = 0; j < min; j++) {
int t = i ^ j;
if (t >= k) {
t -= k;
sum += t;
}
}
}
return sum % newp;
}
Output for the 6 tests:
OK! 5
OK! 224
OK! 11925
OK! 4323
OK! 1586
OK! 808451

According to my knowledge, you cant take more than int in the size of an array but if you don't want to change your long everywhere, you can probably add cast.
long m = 434;
int[] obj = new int[(int) m];
Attempting to access beyond the maximum value allowed through an iterator associated with the array would likely result in one of OutOfMemoryException, IndexOutOfBoundsException or a NoSuchElementException depending on implementation.
This is a very impractical use of memory. If one was to want such a data structure, one should investigate less RAM intensive approaches such as databases, sparse arrays, and the like.

Related

Find "Missing" Integer in a Java Array

Given an array A[] of length n, find a "missing" number k such that:
k is not in A
0<=k<=n
I've seen similar questions asked where the A[] contains numbers 1 to n with one number missing, but in this question, A[] can contain any numbers. I need a solution in O(n) time. For example,
A = {1,2,3} -> 0
A = {0,1,2} -> 3
A = {2,7,4,1,6,0,5,-3} -> 3,8
I've gotten as far as checking if 0 or n are in the array, and if not, return 0 or n, but I cannot seem to think of any other solution. This problem seems considerably more difficult given the fact that A can contain any numbers and not necessarily numbers 1 to n or something like that.
Linearly iterate over the array and "cross out" every number you encounter. Then iterate of that listed of crossed out numbers again and see which one is missing.
public static int getMissingNumber(int[] A)
{
int n = A.length;
boolean[] numbersUsed = new boolean[n + 1]; //Because the definition says 0 <= k <= n, so k = n is also possible.
for(int k = 0; k < n; k++)
{
if(A[k] <= n && A[k] >= 0) //No negative numbers!
numbersUsed[A[k]] = true;
}
for(int k = 0; k <= n; k++)
{
if(numbersUsed[k] == false)
return k;
}
return -1; //nothing found
}
Complexity is 2*n because of the two for loops, giving overall complexity O(n).
Simple approach:
initialize a set with all the values you need. (In your case number 0 to n)
iterate over your arry and remove the number from the set
at the end the set is giving you the missing entries.
If you know that exactly one number is missing, there is a simple solution using xor.
static int missing(int[] arr) {
int result = 0;
for (int i = 0; i < arr.length; i++)
result ^= (i + 1) ^ arr[i];
return result;
}
If there may be more than one number missing you can return a Set like this:
static Set<Integer> missing(int[] arr) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i <= arr.length; i++)
set.add(i);
for (int a : arr)
set.remove(a);
return set;
}
Here is a solution that utilizes one loop. That's if we choose to ignore what Arrays.sort does
import java.util.Arrays;
class Solution {
public int solution(int[] A) {
Arrays.sort(A);
int min = 1;
for (int i = 0; i < A.length; i++){
if(A[i]== min){
min++;
}
}
min = ( min <= 0 ) ? 1:min;
return min;
}
}
class Missing{
public static void main(String[] args) {
int arr[]={1,2,4,5,6,7,9};
System.out.println(missingNumberArray(arr));
}
public static int missingNumberArray(int [] a) {
int result=0;
for(int i=0;i<a.length-1;i++){
if(a[i+1]-a[i]!=1){
result=a[i]+1;
}
}
return result;
}
}
//output:missing element is:3
// missing element is:8

Find all narcissistic (armstrong) numbers faster on Java

Is there more efficient way to do that?
Given number N - find all the narcissistic ( armstrong ) numbers that < N.
Here is my code, but I guess there is more efficient solutions. Also, probably, we could solve it through bit operation?
public static void main(String args[]) throws Exception
{
long a = System.nanoTime();
int t [] = getNumbers(4_483_647L);
long b = System.nanoTime();
System.out.println("Time totally "+(b-a));
for(int k: t)
System.out.print(k+" ");
}
public static int[] getNumbers(long N)
{
int length=1;
int porog=10, r=1, s=1;
double k;
LinkedList<Integer> list = new LinkedList<>();
for(int i=1; i<N; i++)
{
if(i==porog)
{
length++;
porog*=10;
}
s = i;
k=0;
while(s>0)
{
r = s%10;
k+=Math.pow(r, length);
if(k>i)break;
s=s/10;
}
if((int)k==i)
list.add(i);
}
int[] result = new int[list.size()];
int i=0;
for(int n: list)
{
result[i] = n;
i++;
}
return result; } }
Some observations:
If your initial maximum is a long, your results should be long types, too, just in case (int works for you as the narcissistic numbers are far apart)
If you change your return type to be a "big" Long, you can use Collections.toArray() to repack the results to an array...
...although really, you should just return the linked list...
You don't need to keep recalculating powers. For each decade in the outer loop, you only ever need i^j, where i=0..9 and j is the number of digits in the current decade
In fact, you don't need Math.pow() at all, as you can just use multiplication at each decade
Applying my ideas from my comment above and also changing the method signature, you get something that runs about 30 times faster:
public static Long[] getNumbers(long N) {
int porog = 10;
LinkedList<Long> list = new LinkedList<>();
// initial powers for the number 0-9
long[] powers = { 0l, 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l };
for (long i = 1; i < N; i++) {
if (i == porog) {
porog *= 10;
// calculate i^length
for (int pi = 1; pi < 10; pi++) {
powers[pi] *= pi;
}
}
long s = i;
long k = 0;
while (s > 0) {
int r = (int)(s % 10);
k += powers[r];
if (k > i)
break;
s /= 10;
}
if (k == i)
list.add(i);
}
return list.toArray(new Long[]{});
}
From Rosetta Code blog (not my own code)
public static boolean isNarc(long x){
if(x < 0) return false;
String xStr = Long.toString(x);
int m = xStr.length();
long sum = 0;
for(char c : xStr.toCharArray()){
sum += Math.pow(Character.digit(c, 10), m);
}
return sum == x;
}
It's possible to generate Armstrong Numbers quite efficient. For example, all integers can be generated within 10-15 ms.
We may note that for each multi-set of digits, like [1, 1, 2, 4, 5, 7, 7] there is only one sum of powers, which in its turn may either be or be not represented by the digits from set. In the example 1^7 + 1^7 + 2^7 + 4^7 + 5^7 + 7^7 + 7^7 = 1741725, which can be represented by the digits and thus is an Armstrong number.
We may build an algorithm basing on this consideration.
For each number length from 1 to N
Generate all possible multi-sets of N digits
For each multi-set calculate sum of digits^N
Check if it's possible to represent the number we got on step 4 with
the digits from the multi-set
If so - add the number to the result list
The number of cases calculated for each length N is equal to the number of combinations (N + 9, 9) = (N+9)!/(9!N!). Thus for all Ns less than 10 we will generate only 92,377 multi-sets. For N<20: 20,030,009.
Please see GitHub for the description of a few approaches, along with some benchmarking and the Java code. Enjoy! :)
I'm not a professional coder, just self taught with no work experience, so I apologize if my code is bit sloppy.
I took dovetalk's solution and 1) wrote it myself so to better understand it b) made some adjustments that improved the run time considerably for large numbers. I hope this helps anyone else looking for help with this problem:
public static long[] getNumbers(long N) {
long tempII = N;
LinkedHashSet<Long> narcNums = new LinkedHashSet<>();
long tempResult;
long digitLengthTemp = 10;
long tempI;
long[] powers = {0l, 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l};
for (long i = 0; i < N; i++) {
if (i == digitLengthTemp) {
digitLengthTemp *= 10;
for (short x = 2; x < powers.length; x++) powers[x] *= x;
}
//set value of top digits of numbers past first 3 to a remedial value
tempI = i;
long remedialValue = 0;
tempI /= 10; tempI /= 10; tempI /= 10;
while (tempI > 0) {
short index = (short) (tempI % 10);
remedialValue += powers[index];
tempI /= 10;
}
//only passes 1000 at a time to this loop and adds each result to remedial top half
for (int j = 0; j < (tempII > 1000 ? 1000 : tempII); j++) {
//sets digit length and increases the values in array
if (i == 0 && j == digitLengthTemp) {
digitLengthTemp *= 10;
for (short x = 2; x < powers.length; x++) powers[x] *= x;
}
//resets temp results
tempResult = remedialValue;
tempI = j;
//gets the sum of each (digit^numberLength) of number passed to it
while (tempI > 0) {
if (tempResult > i + j) break;
short index = (short) (tempI % 10);
tempResult += powers[index];
tempI /= 10;
}
//checks if sum equals original number
if (i + j == tempResult) narcNums.add(i + j);
}
i += 999; // adds to i in increments of 1000
tempII -= 1000;
}
//converts to long array
long[] results = new long[narcNums.size()];
short i = 0;
for (long x : narcNums) {
results[i++] = x;
}
return results;
}
A major optimisation is to not examine all the numbers in range 1..N . Have a look here.

Calculate factorial of 50 using array only in java

I'm a total beginner of java.
I have a homework to write a complete program that calculates the factorial of 50 using array.
I can't use any method like biginteger.
I can only use array because my professor wants us to understand the logic behind, I guess...
However, he didn't really teach us the detail of array, so I'm really confused here.
Basically, I'm trying to divide the big number and put it into array slot. So if the first array gets 235, I can divide it and extract the number and put it into one array slot. Then, put the remain next array slot. And repeat the process until I get the result (which is factorial of 50, and it's a huge number..)
I tried to understand what's the logic behind, but I really can't figure it out.. So far I have this on my mind.
import java.util.Scanner;
class Factorial
{
public static void main(String[] args)
{
int n;
Scanner kb = new Scanner(System.in);
System.out.println("Enter n");
n = kb.nextInt();
System.out.println(n +"! = " + fact(n));
}
public static int fact(int n)
{
int product = 1;
int[] a = new int[100];
a[0] = 1;
for (int j = 2; j < a.length; j++)
{
for(; n >= 1; n--)
{
product = product * n;
a[j-1] = n;
a[j] = a[j]/10;
a[j+1] = a[j]%10;
}
}
return product;
}
}
But it doesn't show me the factorial of 50.
it shows me 0 as the result, so apparently, it's not working.
I'm trying to use one method (fact()), but I'm not sure that's the right way to do.
My professor mentioned about using operator / and % to assign the number to the next slot of array repeatedly.
So I'm trying to use that for this homework.
Does anyone have an idea for this homework?
Please help me!
And sorry for the confusing instruction... I'm confused also, so please forgive me.
FYI: factorial of 50 is 30414093201713378043612608166064768844377641568960512000000000000
Try this.
static int[] fact(int n) {
int[] r = new int[100];
r[0] = 1;
for (int i = 1; i <= n; ++i) {
int carry = 0;
for (int j = 0; j < r.length; ++j) {
int x = r[j] * i + carry;
r[j] = x % 10;
carry = x / 10;
}
}
return r;
}
and
int[] result = fact(50);
int i = result.length - 1;
while (i > 0 && result[i] == 0)
--i;
while (i >= 0)
System.out.print(result[i--]);
System.out.println();
// -> 30414093201713378043612608166064768844377641568960512000000000000
Her's my result:
50 factorial - 30414093201713378043612608166064768844377641568960512000000000000
And here's the code. I hard coded an array of 100 digits. When printing, I skip the leading zeroes.
public class FactorialArray {
public static void main(String[] args) {
int n = 50;
System.out.print(n + " factorial - ");
int[] result = factorial(n);
boolean firstDigit = false;
for (int digit : result) {
if (digit > 0) {
firstDigit = true;
}
if (firstDigit) {
System.out.print(digit);
}
}
System.out.println();
}
private static int[] factorial(int n) {
int[] r = new int[100];
r[r.length - 1] = 1;
for (int i = 1; i <= n; i++) {
int carry = 0;
for (int j = r.length - 1; j >= 0; j--) {
int x = r[j] * i + carry;
r[j] = x % 10;
carry = x / 10;
}
}
return r;
}
}
How about:
public static BigInteger p(int numOfAllPerson) {
if (numOfAllPerson < 0) {
throw new IllegalArgumentException();
}
if (numOfAllPerson == 0) {
return BigInteger.ONE;
}
BigInteger retBigInt = BigInteger.ONE;
for (; numOfAllPerson > 0; numOfAllPerson--) {
retBigInt = retBigInt.multiply(BigInteger.valueOf(numOfAllPerson));
}
return retBigInt;
}
Please recall basic level of math how multiplication works?
2344
X 34
= (2344*4)*10^0 + (2344*3)*10^1 = ans
2344
X334
= (2344*4)*10^0 + (2344*3)*10^1 + (2344*3)*10^2= ans
So for m digits X n digits you need n list of string array.
Each time you multiply each digits with m. and store it.
After each step you will append 0,1,2,n-1 trailing zero(s) to that string.
Finally, sum all of n listed string. You know how to do that.
So up to this you know m*n
now it is very easy to compute 1*..........*49*50.
how about:
int[] arrayOfFifty = new int[50];
//populate the array with 1 to 50
for(int i = 1; i < 51; i++){
arrayOfFifty[i-1] = i;
}
//perform the factorial
long result = 1;
for(int i = 0; i < arrayOfFifty.length; i++){
result = arrayOfFifty[i] * result;
}
Did not test this. No idea how big the number is and if it would cause error due to the size of the number.
Updated. arrays use ".length" to measure the size.
I now updated result to long data type and it returns the following - which is obviously incorrect. This is a massive number and I'm not sure what your professor is trying to get at.
-3258495067890909184

Calculating the maximum difference between two adjacent numbers in an array

Recently I've been assigned a task which asks to me to "calculate the maximum difference between two adjacent numbers in the array that is passed to it". I'm fairly new to Java (I have only done VB in the past) and since this topic was not well explained to me, I'm not quite sure how to go about it.
Here is some additional information about the task itself:
The function has to pass the following test. The function maxDiff should calculate the maximum difference between two adjacent numbers in the array that is passed to it.
#Test
public void assessmentTest() {
int [] numbers = {12, 8, 34, 10, 59};
assertEquals(49, maxDiff(numbers));
int [] numbers2 = {-50, 100, 20, -40};
assertEquals(150, maxDiff(numbers2));
}
You must assure to take the absolute difference, don't forget it. That's why I used the Math.abs() function.
public static int maxDiff(int[] numbers) {
int diff = Math.abs(numbers[1] - numbers[0]);
for(int i = 1; i < numbers.length-1; i++)
if(Math.abs(numbers[i+1]-numbers[i]) > diff)
diff = Math.abs(numbers[i+1] - numbers[i]);
return diff;
}
Something like this should do the trick:
public static int maxDiff(int[] numbers) {
if (numbers.length < 2) {
return 0;
}
if (numbers.length == 2) {
return Math.abs(numbers[1] - numbers[0]);
}
int max = Math.abs(numbers[1] - numbers[0]);
for (int i = 2; i < numbers.length; i++) {
int diff = Math.abs(numbers[i-1] - numbers[i]);
if (diff > max) {
max = diff;
}
}
return max;
}
For the specific question you asked:
public static int maxDiff(int[] arr) {
if(arr.length < 2)
return -1; // error condition: throw exception?
int maxdiff = Integer.MIN_VALUE;
for(int i = 1; i < arr.length; ++i) {
int diff = Math.abs(arr[i] - arr[i-1]);
if(diff > maxdiff)
maxdiff = diff;
}
return maxdiff;
}
If you want the max difference across all numbers in the array (not just adjacent ones) the most efficient way to do it would be to iterate the array just once to find the minimum and maximum, then return the absolute value of the two values subtracted from each other.
public static int maxDiff(int[] arr) {
if(arr.length < 2)
return -1; // error condition: throw exception?
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i = 0; i < arr.length; ++i) {
if(arr[i] < min)
min = arr[i];
if(arr[i] > max)
max = arr[i];
}
return Math.abs(max - min);
}
This piece of code can help you:
int[] numbers = {12, 8, 34, 10, 59};
int diff = 0;
int previous = 0;
for (int n : numbers) {
diff = Math.max(diff, Math.abs(n - previous));
previous = n;
}
Variable "diff" will contain the value you look for.
You can use this for Java;
int arrayMaximalAdjacentDifference(int[] inputArray) {
int max=0;
for( int i = 1 ; i < inputArray.length ; i++ ){
max = Math.max(max,Math.abs(inputArray[i] - inputArray[i-1]));
}
return max;
}

Largest 5 in array of 10 numbers without sorting

Here's my code to find the max number in an array of numbers, but i can't seem to understand how to get the top 5 numbers and store them in an array and later retrieve them
Here's the code:
public class Max {
public static void main (String[] args)
{
int i;
int large[]=new int[5];
int array[] = {33,55,13,46,87,42,10,34,43,56};
int max = array[0]; // Assume array[0] to be the max for time-being
//Looping n-1 times, O(n)
for( i = 1; i < array.length; i++) // Iterate through the First Index and compare with max
{
// O(1)
if( max < array[i])
{
// O(1)
max = array[i];// Change max if condition is True
large[i] = max;
}
}
for (int j = 0; j<5; j++)
{
System.out.println("Largest 5 : "+large[j]);
}
System.out.println("Largest is: "+ max);
// Time complexity being: O(n) * [O(1) + O(1)] = O(n)
}
}
I'm using an array to store 5 numbers, but when i run it, it is not what i want.
Can anyone help me with the program?
The optimum data structure to retrieve top n items from a larger collection is the min/max heap and the related abstract data structure is called the priority queue. Java has an unbounded PriorityQueue which is based on the heap structure, but there is no version specialized for primitive types. It can used as a bounded queue by adding external logic, see this comment for details..
Apache Lucene has an implementation of the bounded priority queue:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.lucene/lucene-core/5.2.0/org/apache/lucene/util/PriorityQueue.java#PriorityQueue
Here is a simple modification that specializes it for ints:
/*
* Original work Copyright 2014 The Apache Software Foundation
* Modified work Copyright 2015 Marko Topolnik
*
* Licensed under the Apache License, Version 2.0 (the "License");
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** A PriorityQueue maintains a partial ordering of its elements such that the
* worst element can always be found in constant time. Put()'s and pop()'s
* require log(size) time.
*/
class IntPriorityQueue {
private static int NO_ELEMENT = Integer.MIN_VALUE;
private int size;
private final int maxSize;
private final int[] heap;
IntPriorityQueue(int maxSize) {
this.heap = new int[maxSize == 0 ? 2 : maxSize + 1];
this.maxSize = maxSize;
}
private static boolean betterThan(int left, int right) {
return left > right;
}
/**
* Adds an int to a PriorityQueue in log(size) time.
* It returns the object (if any) that was
* dropped off the heap because it was full. This can be
* the given parameter (in case it isn't better than the
* full heap's minimum, and couldn't be added), or another
* object that was previously the worst value in the
* heap and now has been replaced by a better one, or null
* if the queue wasn't yet full with maxSize elements.
*/
public void consider(int element) {
if (size < maxSize) {
size++;
heap[size] = element;
upHeap();
} else if (size > 0 && betterThan(element, heap[1])) {
heap[1] = element;
downHeap();
}
}
public int head() {
return size > 0 ? heap[1] : NO_ELEMENT;
}
/** Removes and returns the least element of the PriorityQueue in log(size)
time. */
public int pop() {
if (size > 0) {
int result = heap[1];
heap[1] = heap[size];
size--;
downHeap();
return result;
} else {
return NO_ELEMENT;
}
}
public int size() {
return size;
}
public void clear() {
size = 0;
}
public boolean isEmpty() {
return size == 0;
}
private void upHeap() {
int i = size;
// save bottom node
int node = heap[i];
int j = i >>> 1;
while (j > 0 && betterThan(heap[j], node)) {
// shift parents down
heap[i] = heap[j];
i = j;
j >>>= 1;
}
// install saved node
heap[i] = node;
}
private void downHeap() {
int i = 1;
// save top node
int node = heap[i];
// find worse child
int j = i << 1;
int k = j + 1;
if (k <= size && betterThan(heap[j], heap[k])) {
j = k;
}
while (j <= size && betterThan(node, heap[j])) {
// shift up child
heap[i] = heap[j];
i = j;
j = i << 1;
k = j + 1;
if (k <= size && betterThan(heap[j], heap[k])) {
j = k;
}
}
// install saved node
heap[i] = node;
}
}
The way you implement betterThan decides whether it will behave as a min or max heap. This is how it's used:
public int[] maxN(int[] input, int n) {
final int[] output = new int[n];
final IntPriorityQueue q = new IntPriorityQueue(output.length);
for (int i : input) {
q.consider(i);
}
// Extract items from heap in sort order
for (int i = output.length - 1; i >= 0; i--) {
output[i] = q.pop();
}
return output;
}
Some interest was expressed in the performance of this approach vs. the simple linear scan from user rakeb.void. These are the results, size pertaining to the input size, always looking for 16 top elements:
Benchmark (size) Mode Cnt Score Error Units
MeasureMinMax.heap 32 avgt 5 270.056 ± 37.948 ns/op
MeasureMinMax.heap 64 avgt 5 379.832 ± 44.703 ns/op
MeasureMinMax.heap 128 avgt 5 543.522 ± 52.970 ns/op
MeasureMinMax.heap 4096 avgt 5 4548.352 ± 208.768 ns/op
MeasureMinMax.linear 32 avgt 5 188.711 ± 27.085 ns/op
MeasureMinMax.linear 64 avgt 5 333.586 ± 18.955 ns/op
MeasureMinMax.linear 128 avgt 5 677.692 ± 163.470 ns/op
MeasureMinMax.linear 4096 avgt 5 18290.981 ± 5783.255 ns/op
Conclusion: constant factors working against the heap approach are quite low. The breakeven point is around 70-80 input elements and from then on the simple approach loses steeply. Note that the constant factor stems from the final operation of extracting items in sort order. If this is not needed (i.e., just a set of the best items is enough), the we can simply retrieve the internal heap array directly and ignore the heap[0] element which is not used by the algorithm. In that case this solution beats one like rakib.void's even for the smallest input size (I tested with 4 top elements out of 32).
Look at the following code:
public static void main(String args[]) {
int i;
int large[] = new int[5];
int array[] = { 33, 55, 13, 46, 87, 42, 10, 34, 43, 56 };
int max = 0, index;
for (int j = 0; j < 5; j++) {
max = array[0];
index = 0;
for (i = 1; i < array.length; i++) {
if (max < array[i]) {
max = array[i];
index = i;
}
}
large[j] = max;
array[index] = Integer.MIN_VALUE;
System.out.println("Largest " + j + " : " + large[j]);
}
}
Note: If you don't want to change the inputted array, then make a copy of it and do the same operation on the copied array.
Take a look at Integer.MIN_VALUE.
I get the following output:
Largest 0 : 87
Largest 1 : 56
Largest 2 : 55
Largest 3 : 46
Largest 4 : 43
Here is a simple solution i quickly knocked up
public class Main {
public static void main(String args[]) {
int i;
int large[] = new int[5];
int array[] = { 33, 55, 13, 46, 87, 42, 10, 34, 43, 56 };
for (int j = 0; j < array.length; j++) {
for (i = 4; i >= 0; i--) {
if (array[j] > large[i]) {
if (i == 4) {
large[i] = array[j];
}
else{
int temp = large[i];
large[i] = array[j];
large[i+1] = temp;
}
}
}
}
for (int j = 0; j<5; j++)
{
System.out.println("Largest "+ j + ":"+ large[j]);
}
}
}
Sorting, regular expressions, complex data structures are fine and make programming easy. However, I constantly see them misused nowadays and no one has to wonder:
Even if computers have become thousands of times faster over the past decades, the perceived performance still continues to not only not grow, but actually slows down. Once in your terminal application, you had instant feedback, even in Windows 3.11 or Windows 98 or Gnome 1, you often had instant feedback from your machine.
But it seems that it becomes increasingly popular to not only crack nuts with a sledgehammer, but even corns of wheat with steam hammers.
You don't need no friggin' sorting or complex datastructures for such a small problem. Don't let me invoke Z̴̲̝̻̹̣̥͎̀A̞̭̞̩̠̝̲͢L̛̤̥̲͟͜G͘҉̯̯̼̺O̦͈͙̗͎͇̳̞̕͡. I cannot take it, and even if I don't have a Java compiler at hands, here's my take in C++ (but will work in Java, too).
Basically, it initializes your 5 maxima to the lowest possible integer values. Then, it goes through your list of numbers, and for each number, it looks up into your maxima to see if it has a place there.
#include <vector>
#include <limits> // for integer minimum
#include <iostream> // for cout
using namespace std; // not my style, I just do so to increase readability
int main () {
// basically, an array of length 5, initialized to the minimum integer
vector<int> maxima(5, numeric_limits<int>::lowest());
// your numbers
vector<int> numbers = {33, 55, 13, 46, 87, 42, 10, 34, 43, 56};
// go through all numbers.
for(auto n : numbers) {
// find smallest in maxima.
auto smallestIndex = 0;
for (auto m=0; m!=maxima.size(); ++m) {
if (maxima[m] < maxima[smallestIndex]) {
smallestIndex = m;
}
}
// check if smallest is smaller than current number
if (maxima[smallestIndex] < n)
maxima[smallestIndex] = n;
}
cout << "maximum values:\n";
for(auto m : maxima) {
cout << " - " << m << '\n';
}
}
It is a similar solution to rakeb.voids' answer, but flips the loops inside out and does not have to modify the input array.
Use steam hammers when appropriate only. Learn algorithms and datastructures. And know when NOT TO USE YOUR KUNG-FU. Otherwise, you are guilty of increasing the society's waste unecessarily and contribute to overall crapness.
(Java translation by Marko, signature adapted to zero allocation)
static int[] phresnel(int[] input, int[] output) {
Arrays.fill(output, Integer.MIN_VALUE);
for (int in : input) {
int indexWithMin = 0;
for (int i = 0; i < output.length; i++) {
if (output[i] < output[indexWithMin]) {
indexWithMin = i;
}
}
if (output[indexWithMin] < in) {
output[indexWithMin] = in;
}
}
Arrays.sort(output);
return output;
}
As an alternative to sorting, here is the logic. You figure out the code.
Keep a list (or array) of the top X values found so far. Will of course start out empty.
For each new value (iteration), check against top X list.
If top X list is shorter than X, add value.
If top X list is full, check if new value is greater than any value. If it is, remove smallest value from top X list and add new value.
Hint: Code will be better if top X list is sorted.
If you don't want to sort you can check lower number and it's position and replace. WORKING DEMO HERE.
public static void main(String[] args) {
int array[] = {33,55,13,46,87,42,10,34,43,56};
int mArray[] = new int[5];
int j = 0;
for(int i = 0; i < array.length; i++) {
if (array[i] > lower(mArray)) {
mArray[lowerPos(mArray)] = array[i];
}
}
System.out.println(Arrays.toString(mArray));
}
public static int lower(int[] array) {
int lower = Integer.MAX_VALUE;
for (int n : array) {
if (n < lower)
lower = n;
}
return lower;
}
public static int lowerPos(int[] array) {
int lower = Integer.MAX_VALUE;
int lowerPos = 0;
for (int n = 0; n < array.length; n++) {
if (array[n] < lower) {
lowerPos = n;
lower = array[n];
}
}
return lowerPos;
}
OUTPUT:
[43, 55, 56, 46, 87]
try :
public static int getMax(int max,int[] arr ){
int pos=0;
//Looping n-1 times, O(n)
for( int i = 0; i < arr.length; i++) // Iterate through the First Index and compare with max
{
// O(1)
if( max < arr[i])
{
// O(1)
max = arr[i];// Change max if condition is True
pos=i;
}
}
arr[pos]=0;
return max;
}
public static void main(String[] args) {
int large[]=new int[10];
int array[] = {33,55,13,46,87,42,10,34,43,56};
int k=0;
for(int i=0;i<array.length;i++){
large[k++]=getMax(0,array);
}
System.out.println("Largest 5 is: "+ Arrays.toString(Arrays.copyOf(large,5)));
}
output:
Largest 5 is: [87, 56, 55, 46, 43]
Here is another approach:
public static void main(String args[]){
int i;
int largestSize = 4;
int array[] = {33,55,13,46,87,42,10,34};
// copy first 4 elemets, they can just be the highest
int large[]= Arrays.copyOf(array, largestSize);
// get the smallest value of the large array before the first start
int smallest = large[0];
int smallestIndex = 0;
for (int j = 1;j<large.length;++j) {
if (smallest > large[j]) {
smallest = large[j];
smallestIndex = j;
}
}
// First Loop start one elemnt after the copy
for(i = large.length; i < array.length; i++)
{
// get the smallest value and index of the large array
if(smallest < array[i])
{
large[smallestIndex] = array[i];
// check the next smallest value
smallest = large[0];
smallestIndex = 0;
for (int j = 1;j<large.length;++j) {
if (smallest > large[j]) {
smallest = large[j];
smallestIndex = j;
}
}
}
}
for (int j = 0; j<large.length; j++)
{
System.out.println("Largest 5 : "+large[j]);
}
System.out.println();
System.out.println("Largest is: "+ getHighest(large));
}
private static int getHighest(int[] array) {
int highest = array[0];
for (int i = 1;i<array.length;++i) {
if (highest < array[i]) {
highest = array[i];
}
}
return highest;
}
First of all, you can't use the i constant with large array. i goes up to 10, while large length is 5.
Use a separate variable for that and increment when you add a new value.
Second, this logic is not retrieving the max values, you need to go over your array fully, retrieve the max value and add it to your array. Then you have to it again. You can write a first loop which use large.length as a condition and the inner loop which will use array.length. Or, you can use recursion.
You could do this properly in an OOp way. This maintains a list of the n largest values of a list of offered values.
class Largest<T extends Comparable<T>> {
// Largest so far - null if we haven't yet seen that many.
List<T> largest;
public Largest(int n) {
// Build my list.
largest = new ArrayList(n);
// Clear it.
for (int i = 0; i < n; i++) {
largest.add(i, null);
}
}
public void offer(T next) {
// Where to put it - or -1 if nowhere.
int place = -1;
// Must replace only the smallest replaceable one.
T smallest = null;
for (int i = 0; i < largest.size(); i++) {
// What's there?
T l = largest.get(i);
if (l == null) {
// Always replace null.
place = i;
break;
}
if (l.compareTo(next) < 0) {
// Only replace the smallest.
if (smallest == null || l.compareTo(smallest) < 0) {
// Remember here but keep looking in case there is a null or a smaller.
smallest = l;
place = i;
}
}
}
if (place != -1) {
// Replace it.
largest.set(place, next);
}
}
public List<T> get() {
return largest;
}
}
public void test() {
Integer array[] = {33, 55, 13, 46, 87, 42, 10, 34, 43, 56};
Largest<Integer> l = new Largest<>(5);
for (int i : array) {
l.offer(i);
}
List<Integer> largest = l.get();
Collections.sort(largest);
System.out.println(largest);
// Check it.
List<Integer> asList = Arrays.asList(array);
Collections.sort(asList);
asList = asList.subList(asList.size() - largest.size(), asList.size());
System.out.println(asList);
}
For larger numbers you can improve the algorithm using binarySearch to find the best place to put the new item instead of blindly walking the whole list. This has the added benefit of returning a sorted list.
class Largest<T extends Comparable<T>> {
// Largest so far - null if we haven't yet seen that many.
List<T> largest;
// Limit.
final int n;
public Largest(int n) {
// Build my list.
largest = new ArrayList(n + 1);
this.n = n;
}
public void offer(T next) {
// Try to find it in the list.
int where = Collections.binarySearch(largest, next, Collections.reverseOrder());
// Positive means found.
if (where < 0) {
// -1 means at start.
int place = -where - 1;
// Discard anything beyond n.
if (place < n) {
// Insert here.
largest.add(place, next);
// Trim if necessary.
if (largest.size() > n) {
largest.remove(n);
}
}
}
}
public List<T> get() {
return largest;
}
}
Simple working solution for this for all condition is as given below. Please refer code below and let me know in case of any issue in comments.
public static void main(String[] args) {
int arr[] = {75, 4, 2, 43, 56, 1,66};
int k = 5;
int result = find5thMaxValueApproach3(arr, k);
System.out.println("\n 5th largest element is : " + result);
}
static int find5thMaxValueApproach3(int arr[], int k){
int newMax = 0;
int len = arr.length;
int lastMax = Integer.MAX_VALUE;
for(int j = 0; j < k; j++){
int i = 0;
while(arr[i] >= lastMax )
i++;
if(i >= len)
break;
newMax = arr[i];
for( ; i < len; i++){
if( arr[i] < lastMax && arr[i] > newMax){
newMax = arr[i];
}
}
System.out.println("newMax =" + newMax+ " lastMax="+ lastMax);
lastMax = newMax;
}
return lastMax;
}

Categories