I have two values. One is static and equals 24
int A = 24;
and I have entries list :
[0, 21, 45, 76, 98]
All of occurences comes in loop and I want to get closest value which divides on A :
0 - 24
21 - 24
45 - 48
76 - 72
98 - 96
How to calculate this?
Using java8 you can stream the array or list and map that
public static void main(String[] args) {
int a = 24;
List<Integer> mL = Arrays.asList(0, 21, 45, 76, 98);
Map<Integer, Integer> m = mL.stream().collect(Collectors.toMap(Integer::intValue, x -> {
int r = a * (int) Math.round(x / (double) a);
return r == 0 ? a : r;
}));
System.out.println(m);
}
the output will be a map where the key is the values to analyse and the values are the closest delta to it
{0=24, 98=96, 21=24, 76=72, 45=48}
You could divide each value by a using floating point division, round it to the closest int and then multiply it back again by a:
int a = 24;
int[] values = new int[]{0, 21, 45, 76, 98};
int[] result =
Arrays.stream(values).map(v -> a * (int) Math.round(v / (double) a)).toArray();
To find the largest multiple x of a number n which is less than a given number a, you can use some arithmetic:
int x = n - n % a;
Now if you want to get the nearest multiple, whether larger or smaller than a, you can use an if statement:
if (a - x > (x + n) - a)
x = x + a
For a list of numbers, just loop over them or use the Stream API.
Assuming that the arrays are also integers, the correct approach for rounding an integer a to the nearest multiple of integer n is as follows:1
(a + n/2) / n * n
How this works
Hopefully the a / n * n approach should be familiar as an approach to get floor-like behaviour, due to the way integer maths works. The n/2 is a bias to give you round-like behaviour instead.2
Things to be aware of
Exact ties are rounded upward.
Inputs within n / 2 of the maximum representable value will cause this to fail.
Comparison with other answers
The floating-point approaches aren't guaranteed to give the right answer for all input values, due to the limitations of floating-point arithmetic.
Using double may work if the inputs are ints (although I'm not sure what the proof is). But it certainly won't be sufficient for longs.
This integer approach may be equivalent to #CodeApprentice's answer, I'm not sure. But this approach avoids the conditional.
1. The boilerplate stream/loop code to get this to work for multiple input values is left as an exercise for the reader.
2. And for completeness, if you use a bias of n-1, you get ceil-like behaviour!
One approach is to take the remainder and see if you need to add or substract from the given number to get closest number that divides. If remainder is less then half of A then substract remainder from the number otherwise add to it the difference between remainder and A. Also as a quick exit check if number is less then A the closest one is A itself.
public static int[] closest(int a, int[] b){
int[] result = new int[ b.length ];
int halfOfA = a/2;
for (int i = 0; i < b.length; i++){
if ( b[i] <= a ){
result[i] = a;
}else{
int rem = b[i] % a;
if (rem < halfOfA) result[i] = b[i] - rem;
else result[i] = b[i] + (a - rem);
}
}
return result;
}
You can do like this :
iterate until your are as near as possible of the value (when distance is less than A/2
private static int closestTo(int a, int i) {
int res = a;
while (Math.abs(res - i) > (a / 2.0) && res< i + a) {
res += a;
}
return res;
}
And use like
public static void main(String[] args) {
int A = 24;
int[] tab = new int[]{0, 21, 45, 76, 98};
for (int i : tab) {
System.out.println(i + " - " + closestTo(A, i));
}
}
Related
Can somebody help me with this problem?
Statement: - What is the maximum possible n digit number starting from 0 we can make in K steps
using only 2 operations:-
multiplying by 3 or incrementing by 2.
EXAMPLE :
N =2 K = 5;
-> (0->2->6->8->24->72) 72 IS THE ANSWER
N = 2 , K = 51 -> (0->2->6->8->10->30->32->96->98). 98 is the maximum we can get so need to check for rest of the moves.
My 2 state-recursive solution:-
public static void largestNDigitNumber(long[] highest, long maxValue, long k, long currentValue) {
if (highest[0] == (maxValue - 2)) return; //no need to do anything as we get 98 as highest.
if (k < 0) return; //checking for steps
if (highest[0] < currentValue && currentValue <= (maxValue - 2)) {
highest[0] = currentValue;
}
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue * 3));
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue + 2));
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long maxValue = (long) Math.pow(10, n);
long[] highest = new long[1];
largestNDigitNumber(highest, maxValue, (k - 1), 2);
if (highest[0] < (long) Math.pow(10, (n - 1))) {
System.out.println("-1"); // if it is not possible to make n digit in given steps
} else System.out.println(highest[0]);
}
when "k" is small it is giving the correct answer but for bigger values of "k", it does not show any input. for n=2 and k = 51, it does not show anything.
please help me to improve this code
The question is equivalent to asking what is the largest base 3 number that is less than 10^n/2, and has digit sum plus length less than or equal to k+1. (The answer is then double the base 3 number).
For example, N=2 K=5. What's the largest base 3 number that's less than 50, with length plus digit sum less than or equal to 6. Answer: 1100 (36 decimal), so the answer to the original question is 36*2=72.
For N=2, K=51, the largest base-3 number that's less than 50 is 2001 (49 decimal) and has length sum plus digit sum = 7, which is way less than K+1.
Given this representation, it's easy to solve the problem in O(n) time (in fact, you can solve it using pencil and paper). The length d of the base-3 number is as large as possible such that 3^d < 10^n/2 and d<=K. Then fill in the digits of the number greedily from the most-significant first until you have digit sum K+1-d (or you run out of digits).
Equivalence
First note that without loss of generality you can assume you never have three +2 operations in a row, since that can be done more efficiently by inserting a single +2 operation to before the most recent *3 (or simply replacing it by +2 * 3 if there's no *3 operation). Suppose you have represented the current number as a doubled base-3 number. A +2 operation corresponds to adding 1 to the bottom digit (this never overflows into the next column thanks to the observation above). A *3 operation moves all the digits up one column, introducing a 0 as the bottom digit. Note that because the number is doubled, the +2 operation adds just 1 to the base-3 number!
From this, you can see that you can count the number of operations from observation of the doubled base-3 number. Because *3 introduces a new digit, and +2 increases the digit sum by 1, so the number of operations is equal to the number of digits plus 1, plus the digit sum.
As an example. Suppose you have the doubled base-3 number 2 * 2101, then this is equivalent to 2 * (1+3*3*(1+3*(1+1)))) = (2 + 3*3*(2+3*(2+2))).
I tried something like this. it seems to work fine.
getMaxNumber(2, 5) ==> 72
getMaxNumber(2, 51) ==> 98
private int getMaxNumber(int n, int k){
int N = 0;
for (int i = 0; i < n; i++) {
N = N * 10 + 9;
}
int[] result = new int[1];
helper(N, k, 0, 0, result);
return result[0];
}
private void helper(int N, int K, int n, int k, int[] result){
if(n > N) return;
if(k <= K){
result[0] = Math.max(result[0], n);
}
if(n > 0)
helper(N, K, n * 3, k + 1, result);
helper(N, K, n + 2, k + 1, result);
}
Keeping with the style of your original recursive method. I modified it a bit to produce a working solution:
public static long largestNDigitNumber(int n, long currentK, long maxK, long currentValue) {
if (currentK > maxK || n < 1 || maxK < 1) return 0;
if (currentValue >= Math.pow(10, n))
return 0;
long c1 = largestNDigitNumber(n, currentK + 1, maxK, currentValue * 3);
long c2 = largestNDigitNumber(n, currentK + 1, maxK, currentValue + 2);
if (c1 == 0 && c2 == 0)
return currentValue;
return c1 > c2 ? c1 : c2;
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long largest = largestNDigitNumber(n, 0, k, 0);
System.out.println(largest); //98
}
This recursive method returns values here instead of using an array. Hence the check if one returned value is bigger than the other or they are both 0 before returning.
Both the +2 and *3 operations preserve odd/even parity, so starting from 0 we can only reach even numbers. We could start our search at the highest even number: 8, 98, 998, 9998 etc. and see what the shortest distance to 0 is.
If we are looking for the shortest distance, then there are less choices to make. If the current number is a multiple of 3 then there are two choices, either we divide by 3 or subtract 2. Otherwise the only choice is to subtract 2. I suspect that in the majority of cases, dividing by 3 is the better option, so that might be the first to try to keep the tree smaller.
If the minimum number of steps is less than K then as many divide by 3 operations as needed can be used to make the correct K
If the minimum number of steps is equal to K then the problem is solved.
If the minimum number of steps is more than K then you need to pick a lower starting number. Some even numbers will already have been covered as part of the initial calculation. You get those 'for free', provide you include a small amount of record keeping. You only need to examine large even numbers that were missed earlier due to a 'divide by 3' step.
I have a problem which is to find the 2 powers of any number (numbers that don't have any powers such as 5 will return null), powers being and 2 integer numbers that when added power to return the said number. Here are some examples:
4 -> {2, 2}
5 -> null
6 -> null
7 -> null
8 -> {2, 3}
10 -> null
etc...
Although my code below works, however its too slow, when passed through the problem (about 100 integer.max values) it takes over the set time (16 seconds), anything I could to optimize this code?
public static int[] isPerfectPower(int n) {
int limit = (int)Math.round((n/((double)5/2)));
for (int i = 2; i <= limit; i++) {
double result = Math.pow(n, (double)1/i);
result = (double)Math.round(result * Math.pow(10, 10)) / Math.pow(10, 10);
if((result == Math.floor(result))) return new int[] {(int)result, i};
}
return null;
}
Your input is no more than 2147483647, which means there are only so many possible answers. Here is an ordered list of all 108 perfect powers with a power of 5 or more.
2**5, 2**7, 3**5, 4**5, 2**11, 3**7, 5**5, 6**5, 2**13, 4**7, 7**5, 8**5, 9**5, 5**7, 10**5, 2**17, 11**5, 3**11, 12**5, 6**7, 13**5, 2**19, 14**5, 15**5, 7**7, 16**5, 17**5, 3**13, 18**5, 8**7, 19**5, 20**5, 21**5, 4**11, 9**7, 22**5, 23**5, 24**5, 2**23, 25**5, 10**7, 26**5, 27**5, 28**5, 11**7, 29**5, 30**5, 31**5, 32**5, 12**7, 33**5, 34**5, 5**11, 35**5, 36**5, 13**7, 4**13, 37**5, 38**5, 39**5, 40**5, 14**7, 41**5, 3**17, 42**5, 43**5, 44**5, 15**7, 45**5, 46**5, 47**5, 48**5, 16**7, 49**5, 50**5, 51**5, 6**11, 52**5, 17**7, 53**5, 54**5, 55**5, 2**29, 56**5, 57**5, 18**7, 58**5, 59**5, 60**5, 61**5, 19**7, 62**5, 63**5, 64**5, 65**5, 3**19, 5**13, 66**5, 20**7, 67**5, 68**5, 69**5, 70**5, 21**7, 71**5, 72**5, 7**11, 73**5
Therefore you only have to check for squares, cubes, and entrees of the list above.
A slightly more naïve method would be to check all ten powers 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. You do not need to check any other powers, as they are either non-prime or too large to ever work.
You can do it by factoring a number.
Lets n = p1^k1 * p2^k2 * p3^k3 where p1,p2,p3 = prime number.
Then a number will be perfect power if gcd(k1, k2, k3) != 1 (They need to have common divisor)..
Example:
2500 = 2^2 * 5^4
= 2^2 * (5^2)^2
= 2^2 * 25^2
= 50^2
This way you can calculate power of perfect powers.
Way 2:
Lets n = a^b ... you need to find a & b where b < log(n)...
Now u need to find a.. you can find a using binary search. this complexity log(a)...to calculate a^b1..... u need log(n) operation.
So complexity for all binary operation: (log(n) * log log(n))
Total complexiy : log(n) * (log(n) * log log(n))
As #Mark Dickinson suggested, the most efficient change to my code ( without completely changing it ) would be to cap my limit at 30 instead of 2/3 of n, as any number >2 with a power greater then 30 would exceed the Integer.max limit, therefore but adding an extra expression ( i < 30 ) would immensely speed up the code, the code will be displayed below.
public static int[] isPerfectPower(int n) {
for(int i = 2; i <= ((n < 30) ? n : 30) && i < 30; i++) {
double result = (double)Math.round(Math.pow(n, (double)1/i) * Math.pow(10, 10)) / Math.pow(10, 10);
if((result == Math.floor(result))) return new int[] {(int)result, i};
}
return null;
}
I have a below method which iterates a distance array and divide each element by a number starting with 1 and get the sum. If sum is greater than value points which is passed to the method then start again in the for loop and divide by 2 and keep going until you find a sum which is less than value points.
Below code works but is there any way to write this better?
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
while (true) {
for (Integer dist : distance) {
sum = (int) (sum + Math.ceil(dist / c));
}
if (sum <= points) {
break;
}
c++;
sum = 0;
}
return c;
}
If there is no specific reason to do Math.ceil to each ratio rather than to the final sum, you can just get the sum of all elements first and then find the value of c
sum / c <= points
sum / points <= c
if 0 < (sum / points) < 1, c = 1
else c = Math.ceil(sum / points)
public static int findMin(List<Integer> distance, int points) {
AtomicInteger c = new AtomicInteger(1);
while (distance.stream().mapToInt(d -> d / c.get()).sum() > points) c.incrementAndGet();
return c.get();
}
Correct me if I'm wrong but assuming the set of distances is [1, 2, 3] right? Then you start with 1/1 + 2/1 + 3/1 which (let's leave them as fractions here) equals 6/1, since they all have the same "denominator" here, it doesn't change. So that means that the first iteration, dividing by one, is literally the sum of the values. (1 + 2 + 3) / 1 divided by one. And anything divided by 1 is itself. So it's just the sum.
Now. On the second pass, if I assume correctly, 1/2 + 2/2 + 3/2 -- again leaving them as fractions -- (1 + 2 + 3) / 2 = 6/2. By now you should see a pattern, right? First pass was 6/1 second is 6/2 next will be 6/3...
So how about:
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
for (Integer i : distance) {
sum += i;
}
int min = 1;
while (sum / min > points) {
min += 1;
}
return min;
}
Perhaps a solution like this would work?
edit So as it turns out this solution is assuming (at least partially) some mathematical accuracy, however it appears that the division per-element is required to be integer division which skews some of the results if we approach it strictly mathematically. So while not being a direct answer to the problem I feel like it's correct enough to leave here as a solution.
I think,we can do two things to improve the performance,but the method is not the best and it depend on the number of your list:
reduce the times of iterate
use greedy algorithm priority reduction the max value. In order to do this we first need to sort the list it cost may cost O(nlog(n)) time.
code like this
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
// sort the list for implement greedy algorithm
Collections.sort(distance, Comparator.reverseOrder());
while (true) {
for (Integer dist : distance) {
sum += dist / c;
// reduce the times of iterate
if (sum <= points) {
return c;
}
}
c++;
sum = 0;
}
}
sorry for that title but I wanted to pack as much information about my problem in as little space as possible without being too confusing.
So, I have a loop which runs n times and each time it uses a = r.nextInt(int y); to generate an int and if all n integers generated are even numbers, then the program "returns true".
The weird thing is: if I chose n to be 18 or higher while y is and even number which is not a power of 2, then the programm will not "termintate successfully".
I love to help you help me, and can take a heavy dose of criticism.
(I know I'm asking about the Random/nextInt(int) topic but I will also take tips for better coding)
EDIT: I looked into the Documentation for Java8 befor I posted here and for powers of two the method uses a different way of producing the random number.
What I don't understand is why is 18 the breakpoint for consecutive even numbers and why does it work with odd numbers for nextInt(int)?
So the following code will work with howManyInts = 16 or 17 but not 18 (or higher) when nextIntValue is an even number which is not a power of two (6,10,12...)
It works with howManyInts = 25 and nextIntValue = 8 in less than 20 seconds
import java.util.*;
class test{
public static void main(String[] args) {
boolean win = false;
int areEven = 0;
long loopCounter = 0; // The loopCounter is used to control the maximum number of loops should be run incase the loop is endless
int howManyInts = 18;
int nextIntValue = 6; // nextIntValue = 6 or 10 won't work while all powers of 2 work fine
// also, I don't want an odd value as that would change to odds towards odd values...
while(win == false){
loopCounter += 1;
areEven = 0;
Random r = new Random();
int[] num = new int[howManyInts];
for(int a = 0; a < num.length; a++){
num[a] = r.nextInt(nextIntValue);
if(num[a] % 2 == 0){
areEven += 1;
}
}
if(areEven == num.length || loopCounter >= 10000000){
win = true;
System.out.println("It took " + loopCounter + " loops to get " + num.length + " random values which are all even.");
}
}
}
}
If you use SecureRandom instead of Random, your program will finish fairly quickly.
Another way would be to use nextDouble instead
num[a] = (int) (r.nextDouble() * nextIntValue);
The problem with Random.nextInt(int n) is I believe hidden within its implementation and you can read about it in its javadoc.
The algorithm is slightly tricky. It rejects values that would result
in an uneven distribution (due to the fact that 2^31 is not divisible
by n). The probability of a value being rejected depends on n. The
worst case is n=2^30+1, for which the probability of a reject is 1/2,
and the expected number of iterations before the loop terminates is 2.
The algorithm treats the case where n is a power of two specially: it
returns the correct number of high-order bits from the underlying
pseudo-random number generator. In the absence of special treatment,
the correct number of low-order bits would be returned. Linear
congruential pseudo-random number generators such as the one
implemented by this class are known to have short periods in the
sequence of values of their low-order bits. Thus, this special case
greatly increases the length of the sequence of values returned by
successive calls to this method if n is a small power of two.
The implementation looks like this:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
While the next method looks like this (I've replaced the constants with literals)
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
(I suppose that 48-31 == 17 is purely coincidental)
Interesting question!
I have added some statistic-gathering to the code:
import java.util.*;
public class J {
static Random r = new Random();
private static class Stats {
long s[];
public Stats(int n) { this.s = new long[n]; }
public String toString() {
return Arrays.toString(s);
}
}
public static void test(int target, int options) {
boolean win = false;
Stats s = new Stats(target);
for (long iterations = 0; !win; iterations ++) {
int even = 0;
for (int i = 0; i < target; i++) {
if ((r.nextInt(options) % 2) != 0) {
s.s[i] ++;
break;
} else {
even ++;
}
}
if (even == target) {
win = true;
System.out.println(
"It took " + iterations + " loops to get " + target
+ " random values which are all even. Stats: " + s);
} else if (iterations >= 1E8) {
win = true;
System.out.println(iterations + ": " + s);
}
}
}
public static void main(String args[]) {
test(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
The code now ends if no sequence is found after 100M tries; and always stores how far it managed to get before failing (= drawing an odd number).
These are some runs:
18 9: It took 57235 loops to get 18 random values which are all even. Stats: [25401, 14081, 7864, 4328, 2508, 1366, 747, 390, 263, 126, 76, 38, 28, 4, 8, 4, 2, 1]
18 8: It took 48612 loops to get 18 random values which are all even. Stats: [24285, 12336, 6066, 2981, 1436, 738, 385, 197, 95, 43, 23, 10, 8, 7, 1, 0, 0, 1]
18 7: It took 23302 loops to get 18 random values which are all even. Stats: [10062, 5712, 3174, 1877, 1101, 590, 331, 190, 98, 59, 44, 31, 18, 8, 5, 2, 0, 0]
18 6: Aborted after 100000000 tries: [49997688, 24993911, 12503043, 6272129, 3113557, 1544194, 788879, 393680, 205236, 89264, 45016, 35858, 5340, 9155, 763, 1525, 0, 763]
So, for those particular values (100M attempts at runs of 18 even numbers, throwing 6-sided dice), there were 0 cases where the run bailed out because of the 17th number, but 763(!) where it bailed out because of the last number!
It definitely looks like a higher-quality PRNG is needed, such as the one mentioned by #radoh.
Probabilistically speaking, you would expect to find runs of N even throws of a fair coin with probability 1/(2^N); and you would expect to collect stats where each entry would be 1/2 the previous one. Encountering 0, 763 indicates a strong bias.
The issue is almost certainly with r.nextInt(nextIntValue);. Here you are requesting a random integer between 0 and 5. I cannot understand specifically why 18 is the break point but the chances a sequence of random positive integers less than a small number to be all even must reduce as the limit reduces.
I note that increasing that value from 6 to 100 still does not find length-18 even sequences. Perhaps the algorithm behind the scenes somehow influences the statistics.
Seems like the random generator doesn't allow 18 consecutive even numbers, when your maxRandom is even, starting at 6.
I changed the code a bit to demonstrate how the 18th random is always odd:
class NextIntWeirdness {
public static void main(String[] args) {
int maxRandom = 6;
Random r = new Random();
for (int i = 0; i < 100; i++) {
int evenNumbers = 17;
int evenResults;
do {
evenResults = 0;
for (int j = 0; j < evenNumbers; j++) {
int num = r.nextInt(maxRandom);
if (num % 2 != 0) {
break;
} else {
evenResults++;
}
}
} while (evenResults < evenNumbers);
System.out.println(r.nextInt(maxRandom));
}
}
}
I need to implement a function which decomposes a value into powers of two using java.
e.g: 14= 8 + 4 + 2
I need to find the powers of two which the value gets decomposed. For the above example I need 2,3,1 as outputs. How could I implement that?
Take advantage of the binary representation that Java uses. I don't know what form you want the powers of 2 to take, but you can loop through the bits one at a time by shifting and bit-wise & with 1 to test each bit. Each 1 bit represents a power of 2 in the sum.
For instance:
List<Integer> powers = new ArrayList<Integer>();
n = . . .; // something > 0
int power = 0;
while (n != 0) {
if ((n & 1) != 0) {
powers.add(1 << power);
// or, if you just need the exponents:
// powers.add(power);
}
++power;
n >>>= 1;
}
As integers are already represented as powers of two and Java has a collections for a set of bits I would use these two.
public static void main(String[] args) {
System.out.println(bitsSet(14));
}
public static BitSet bitsSet(long num) {
BitSet bitSet = new BitSet();
for (int i = 0; i < 64; i++)
if (((num >>> i) & 1) != 0)
bitSet.set(i);
return bitSet;
}
prints
{1, 2, 3}
For this, you usually use bit-wise operations, namely the shift (<<,>>,>>>) and the bit-wise and (&) operator, because the internal representation of integers in computers already is binary, which is what you need.
In binary representation each integer value is a composition of powers of 2: 1, 2, 4, 8, 16, 32, ...
So, 14 in decimal is in binary 1110: 8 + 4 + 2 + 0.
If you're after some nice, generic algorithm, you may want to start decomposing decimal numbers into their powers of 10 and from there on extend your solution to other bases, like 2.
You could simply subtract 2 from the value and keep subtracting subsequent higher powers.
int x = 0;
int value = args[0];
for (i=0, (value - Math.pow(2, i)) >= 0, i++) {
value = value - Math.pow(2, i);
x++;
}
for (i=0, i<x, i++) {
System.out.println("addent: " + Math.pow(2, i);
}