Finding all valid iterations ranges that produce constants in multiple locations - java

I need an algorithm to produce valid iteration ranges for p^l with constants in multiple places.
I have it working but it is very inefficient. I believe there is math that can solve this but I am not sure what it is. Currently I have to find each valid set of iteration ranges for each constant I want. Then I must overlap all the ranges to find iterations where all constants are present.
This is the code for doing so:
public ArrayList<Range> findRangesForSingleSearch(int searchPos, int value) {
ArrayList<Range> iterationRanges = new ArrayList<Range>();
BigInteger p = new BigInteger(""+possibilities);
BigInteger interationMax = p.pow(length-1);
BigInteger pMinus1 = new BigInteger(""+(possibilities - 1));
BigInteger totalIterationsBeforeTarget = p.pow(searchPos);
BigInteger skipIterations =
totalIterationsBeforeTarget.multiply(pMinus1).add(BigInteger.ONE);
totalIterationsBeforeTarget = totalIterationsBeforeTarget.subtract(BigInteger.ONE);
int[] startData = new int[length];
for(int i = 0; i < length; i++) {
if(i==searchPos) {
startData[i] = value;
}else {
startData[i]=0;
}
}
BigInteger startIteration = getPosition(startData);
BigInteger currentIteration = startIteration;
for(BigInteger i = new BigInteger(""+0); i.compareTo(interationMax.divide(totalIterationsBeforeTarget.add(BigInteger.ONE))) < 0;
i = i.add(BigInteger.ONE)) {
BigInteger lowerBound = currentIteration;
currentIteration = currentIteration.add(totalIterationsBeforeTarget);
BigInteger upperBound = currentIteration;
iterationRanges.add(new Range(lowerBound, upperBound));
currentIteration = currentIteration.add(skipIterations);
}
return iterationRanges;
}
This is the code for overlapping the ranges:
public ArrayList<Range> condenseRanges(ArrayList<Range> r1, ArrayList<Range> r2){
ArrayList<Range> newRanges = new ArrayList<Range>();
int ai = 0, bi = 0, alength = r1.size(), blength = r2.size();
BigInteger ax,ay,bx,by;
while(ai < alength && bi < blength) {
ax = r1.get(ai).getLowerBound();
ay = r1.get(ai).getUpperBound();
bx = r2.get(bi).getLowerBound();
by = r2.get(bi).getUpperBound();
if (ay.compareTo(bx) < 0) {
ai++;
} else if (by.compareTo(ax) < 0) {
bi++;
} else {
newRanges.add(condenseRange(r1.get(ai), r2.get(bi)));
if (ay.compareTo(by) < 0) {
ai++;
} else {
bi++;
}
}
}
return newRanges;
}
The meat of my question boils down to if there is a way to combine or tweak the following so that it generates the pre-combined ranges:
totalIterationsBeforeTarget
skipIterations
startIteration
Examples of ranges and iteration correlation + execution of code:
Possibilities:2
Length:8
Total Iterations Possible: 2^8 = 256
Search: position 1,2,3 must equal 1
Found Ranges:
14 -> 15
30 -> 31
46 -> 47
62 -> 63
78 -> 79
94 -> 95
110 -> 111
126 -> 127
142 -> 143
158 -> 159
174 -> 175
190 -> 191
206 -> 207
222 -> 223
238 -> 239
254 -> 255
Example Correlation:
Note the iteration/binary elements are indexed right to left
example: 3rd position, 2nd position, 1st position, zed position
The first range is 14 -> 15:
14 converted to binary is 1110 which matches the search of elements 1,2,3 having a
value of 1
15 converted to binary is 1111 which matches the search of elements 1,2,3 having a
value of 1
13 and 16 are omitted because their binary values are 1101,10000 which do not meet
the requirement of elements 1,2,3 having a value of 1
Then the algorithm jumps to the next valid range 30 -> 31:
30 converted to binary is 11110
31 converted to binary is 11111
If anything is unclear, ask and I can explain in further detail.

Related

How can I print the number of combination and not the actual combination? Java

I'd like to print the number of combination and not the actual combination of bits. How can I code that? I'm looking forward for some solution. Thank you!
The Task:
Write a program that accepts a number. This number corresponds to the number of bits to be taken into account. The program should then display on the screen how many binary combinations there are that do not consist of two adjacent 1s. For example, given a 3-bit number, there are 5 out of 8 possible combinations.
import java.util.Scanner;
public class BinaryS {
public static String toString(char[] a) {
String string = new String(a);
return string;
}
static void generate(int k, char[] ch, int n) {
if (n == k) {
for (int i = 0; i < ch.length; i++) {}
System.out.print(toString(ch) + " ");
return;
}
// If the first Character is
//Zero then adding**
if (ch[n - 1] == '0') {
ch[n] = '0';
generate(k, ch, n + 1);
ch[n] = '1';
generate(k, ch, n + 1);
}
// If the Character is One
// then add Zero to next**
if (ch[n - 1] == '1') {
ch[n] = '0';
// Calling Recursively for the
// next value of Array
generate(k, ch, n + 1);
}
}
static void fun(int k) {
if (k <= 0) {
return;
}
char[] ch = new char[k];
// Initializing first character to Zero
ch[0] = '0';
// Generating Strings starting with Zero--
generate(k, ch, 1);
// Initialized first Character to one--
ch[0] = '1';
generate(k, ch, 1);
}
public static void main(String args[]) {
System.out.print("Number: ");
Scanner scanner = new Scanner(System.in);
int k = scanner.nextInt();
//Calling function fun with argument k
fun(k);
}
}
The program actually works fine , my only problem is I would like to print the number of combinations and not the actual combination. For example for the input 3 we get 000 001 010 100 101 which is 5.
Unfortunately, your code has some problems. For one you have an empty forloop in the generate method. However, I can help you get the count by doing it a different way and printing the results. Forgetting about the loop that goes from 2 to 20, here is what is going on. And this may not be most efficient way of finding the matches but for short runs it exposes the counts as a recognizable pattern (which could also be determined by mathematical analysis).
first, create an IntPredicate that checks for adjacent one bits by masking the lower order two bits.
Generate an IntStream from 0 to 2n where n is the number of bits.
then using aforementioned predicate with a filter count every value that does not contain two adjacent 1 bits.
IntPredicate NoAdjacentOneBits = (n)-> {
while (n > 0) {
if ((n & 3) == 3) {
return false;
}
n>>=1;
}
return true;
};
for (int n = 1; n <= 20; n++) {
long count = IntStream.range(0, (int) Math.pow(2, n))
.filter(NoAdjacentOneBits).count();
System.out.println("For n = " + n + " -> " + count);
}
prints (with annotated comments on first three lines)
For n = 1 -> 2 // not printed but would be 0 and 1
For n = 2 -> 3 // 00, 01, 10
For n = 3 -> 5 // 000, 001, 010, 100, 101
For n = 4 -> 8
For n = 5 -> 13
For n = 6 -> 21
For n = 7 -> 34
For n = 8 -> 55
For n = 9 -> 89
For n = 10 -> 144
For n = 11 -> 233
For n = 12 -> 377
For n = 13 -> 610
For n = 14 -> 987
For n = 15 -> 1597
For n = 16 -> 2584
For n = 17 -> 4181
For n = 18 -> 6765
For n = 19 -> 10946
For n = 20 -> 17711
The counts are directly related to the nth term of the Fibonacci Series that starts with 2 3 5 8 . . .
So you really don't even need to inspect the values for adjacent bits. Just compute the related term of the series.

Last 3 non zero digits from factorial

Can someone help me with the sample code in java how to find last 3 non zero digits from big factorial?
Eg 12! :- 479001600 = 16
10! :- 3628800 =288
The following function calculates the factorial:
private static BigInteger factorial(int n) {
return IntStream.rangeClosed(1, n)
.mapToObj(BigInteger::valueOf)
.collect(Collectors.reducing(BigInteger.ONE, BigInteger::multiply));
}
And this function calculates the last 3 non-zero digits:
private static BigInteger last3NonzeroDigits(BigInteger n) {
while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) {
n = n.divide(BigInteger.TEN);
}
return n.mod(BigInteger.valueOf(1000));
}
delete trailing zeroes: while the last digit is 0 (dividable by 10, hence i % 10 = 0), divide by 10
from the resulting number, extract the (at most) last 3 digits (i % 1000)
Test:
for (int i = 1; i <= 15; i++) {
BigInteger f = factorial(i);
System.out.println(i+"! = "+f + " -> " + last3NonzeroDigits(f));
}
Output:
1! = 1 -> 1
2! = 2 -> 2
3! = 6 -> 6
4! = 24 -> 24
5! = 120 -> 12
6! = 720 -> 72
7! = 5040 -> 504
8! = 40320 -> 32
9! = 362880 -> 288
10! = 3628800 -> 288
11! = 39916800 -> 168
12! = 479001600 -> 16
13! = 6227020800 -> 208
14! = 87178291200 -> 912
15! = 1307674368000 -> 368
You can map the number to a string, loop over the digits, find the last index where maximum three non-zero digits can be found and at the end you can return the index and print the last digits as your result. I have coded a little bit and write the method findLastIndex to get the index:
fun findLastIndex(num: String): Int {
var zero = true
var counter = 0
val reversedNum = num.reversed()
for(i in 0 until num.length){
if(!reversedNum[i].equals('0')){
counter++
zero = false;
}
if((reversedNum[i].equals('0') || counter >= 3) && !zero){
return num.length - i - 1
}
}
return 0
}
Now you can call the method and print the last non-zero digits:
val num = 479001600
val numString = num.toString()
val index = findLastIndex(numString)
println(numString.substring(index).replace("0", ""))
You can test it in the kotlin playground. Mapping in Java should be easy to do. For the reverse method you can have a look at the following article. Or you can inverse the for loop. Hope it helps.

3D multidimensional array output not matching initialization data

I've been working on a code segment that flattens a 3D dimensional array, however I've encountered a rather baffling situation with the following code.
The array used is initialized as follows:
int array[][][] = {
{
{000, 001, 002},
{010, 011, 012},
{020, 021, 022},
},
{
{100, 101, 102},
{110, 111, 112},
{120, 121, 122},
},
{
{200, 201, 202},
{210, 211, 212},
{220, 221, 222},
}
};
And then outputting the array through a basic nested for loop.
The output is formatted through a custom DecimalFormat that allows me to print the floating 0's.
DecimalFormat xFormat = new DecimalFormat("000");
for(int z = 0; z < array[0].length; z++) {
for(int y = 0; y < array[1].length; y++) {
for(int x = 0; x < array[2].length; x++) {
System.out.println("I = "+ i + " Element at i = " + xFormat.format(array[z][y][x]));
}
}
}
This loop is used immediately after the initialization of the array, yet the output is what completely baffles me
I = 0 Element at i = 000
I = 1 Element at i = 001
I = 2 Element at i = 002
I = 3 Element at i = 008 <------- =/= 010
I = 4 Element at i = 009 <------- =/= 011
I = 5 Element at i = 010 <------- =/= 012
I = 6 Element at i = 016 <------- =/= 020
I = 7 Element at i = 017 <------- =/= 021
I = 8 Element at i = 018 <------- =/= 022
I = 9 Element at i = 100
I = 10 Element at i = 101
I = 11 Element at i = 102
I = 12 Element at i = 110
I = 13 Element at i = 111
I = 14 Element at i = 112
I = 15 Element at i = 120
I = 16 Element at i = 121
I = 17 Element at i = 122
I = 18 Element at i = 200
I = 19 Element at i = 201
I = 20 Element at i = 202
I = 21 Element at i = 210
I = 22 Element at i = 211
I = 23 Element at i = 212
I = 24 Element at i = 220
I = 25 Element at i = 221
I = 26 Element at i = 222
This seems rather elementary to me, yet I'm not sure what I'm missing at this point. The majority of the loop prints out right, yet it's this part in the middle that's not outputting correctly, and searches on multidimensional array issues haven't yielded much in the way of solutions
Its because 0* (0 prefix) is used to store octal numbers (base8)
{000, 001, 002}, //0,1,2
{010, 011, 012}, //8,9,10
{020, 021, 022}, //16,17,18
That swhy 010 translates to 8 decimal, 11 to 9 etc etc. Just like 0x*is used to store hexadecimals, aod ***b to store binaries. DecimalFormat gets value of octal 010, that equals to 9, and this is what you are getting in the output.
Rest of the values are decimals, because they do not start with 0. You can prefix every other walue with 0 and see what will happen.

Optimal and efficient solution for the heavy number calculation?

I need to find the number of heavy integers between two integers A and B, where A <= B at all times.
An integer is considered heavy whenever the average of it's digit is larger than 7.
For example: 9878 is considered heavy, because (9 + 8 + 7 + 8)/4 = 8
, while 1111 is not, since (1 + 1 + 1 + 1)/4 = 1.
I have the solution below, but it's absolutely terrible and it times out when run with large inputs. What can I do to make it more efficient?
int countHeavy(int A, int B) {
int countHeavy = 0;
while(A <= B){
if(averageOfDigits(A) > 7){
countHeavy++;
}
A++;
}
return countHeavy;
}
float averageOfDigits(int a) {
float result = 0;
int count = 0;
while (a > 0) {
result += (a % 10);
count++;
a = a / 10;
}
return result / count;
}
Counting the numbers with a look-up table
You can generate a table that stores how many integers with d digits have a sum of their digits that is greater than a number x. Then, you can quickly look up how many heavy numbers there are in any range of 10, 100, 1000 ... integers. These tables hold only 9×d values, so they take up very little space and can be quickly generated.
Then, to check a range A-B where B has d digits, you build the tables for 1 to d-1 digits, and then you split the range A-B into chunks of 10, 100, 1000 ... and look up the values in the tables, e.g. for the range A = 782, B = 4321:
RANGE DIGITS TARGET LOOKUP VALUE
782 - 789 78x > 6 table[1][ 6] 3 <- incomplete range: 2-9
790 - 799 79x > 5 table[1][ 5] 4
800 - 899 8xx >13 table[2][13] 15
900 - 999 9xx >12 table[2][12] 21
1000 - 1999 1xxx >27 table[3][27] 0
2000 - 2999 2xxx >26 table[3][26] 1
3000 - 3999 3xxx >25 table[3][25] 4
4000 - 4099 40xx >24 impossible 0
4100 - 4199 41xx >23 impossible 0
4200 - 4299 42xx >22 impossible 0
4300 - 4309 430x >21 impossible 0
4310 - 4319 431x >20 impossible 0
4320 - 4321 432x >19 impossible 0 <- incomplete range: 0-1
--
48
If the first and last range are incomplete (not *0 - *9), check the starting value or the end value against the target. (In the example, 2 is not greater than 6, so all 3 heavy numbers are included in the range.)
Generating the look-up table
For 1-digit decimal integers, the number of integers n that is greater than value x is:
x: 0 1 2 3 4 5 6 7 8 9
n: 9 8 7 6 5 4 3 2 1 0
As you can see, this is easily calculated by taking n = 9-x.
For 2-digit decimal integers, the number of integers n whose sum of digits is greater than value x is:
x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
n: 99 97 94 90 85 79 72 64 55 45 36 28 21 15 10 6 3 1 0
For 3-digit decimal integers, the number of integers n whose sum of digits is greater than value x is:
x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
n: 999 996 990 980 965 944 916 880 835 780 717 648 575 500 425 352 283 220 165 120 84 56 35 20 10 4 1 0
Each of these sequences can be generated from the previous one: start with value 10d and then subtract from this value the previous sequence in reverse (skipping the first zero). E.g. to generate the sequence for 3 digits from the sequence for 2 digits, start with 103 = 1000, and then:
0. 1000 - 1 = 999
1. 999 - 3 = 996
2. 996 - 6 = 990
3. 990 - 10 = 980
4. 980 - 15 = 965
5. 965 - 21 = 944
6. 944 - 28 = 916
7. 916 - 36 = 880
8. 880 - 45 = 835
9. 835 - 55 = 780
10. 780 - 64 + 1 = 717 <- after 10 steps, start adding the previous sequence again
11. 717 - 72 + 3 = 648
12. 648 - 79 + 6 = 575
13. 575 - 85 + 10 = 500
14. 500 - 90 + 15 = 425
15. 425 - 94 + 21 = 352
16. 352 - 97 + 28 = 283
17. 283 - 99 + 36 = 220
18. 220 - 100 + 45 = 165 <- at the end of the sequence, keep subtracting 10^(d-1)
19. 165 - 100 + 55 = 120
20. 120 - 100 + 64 = 84
21. 84 - 100 + 72 = 56
22. 56 - 100 + 79 = 35
23. 35 - 100 + 85 = 20
24. 20 - 100 + 90 = 10
25. 10 - 100 + 94 = 4
26. 4 - 100 + 97 = 1
27. 1 - 100 + 99 = 0
By the way, you can use the same tables if "heavy" numbers are defined with a value other than 7.
Code example
Below is a Javascript code snippet (I don't speak Java) that demonstrates the method. It is very much unoptimised, but it does the 0→100,000,000 example in less than 0.07ms. It also works for weights other than 7. Translated to Java, it should easily beat any algorithm that actually runs through the numbers and checks their weight.
function countHeavy(A, B, weight) {
var a = decimalDigits(A), b = decimalDigits(B); // create arrays
while (a.length < b.length) a.push(0); // add leading zeros
var digits = b.length, table = weightTable(); // create table
var count = 0, diff = B - A + 1, d = 0; // calculate range
for (var i = digits - 1; i >= 0; i--) if (a[i]) d = i; // lowest non-0 digit
while (diff) { // increment a until a=b
while (a[d] == 10) { // move to higher digit
a[d++] = 0;
++a[d]; // carry 1
}
var step = Math.pow(10, d); // value of digit d
if (step <= diff) {
diff -= step;
count += increment(d); // increment digit d
}
else --d; // move to lower digit
}
return count;
function weightTable() { // see above for details
var t = [[],[9,8,7,6,5,4,3,2,1,0]];
for (var i = 2; i < digits; i++) {
var total = Math.pow(10, i), final = total / 10;
t[i] = [];
for (var j = 9 * i; total > 0; --j) {
if (j > 9) total -= t[i - 1][j - 10]; else total -= final;
if (j < 9 * (i - 1)) total += t[i - 1][j];
t[i].push(total);
}
}
return t;
}
function increment(d) {
var sum = 0, size = digits;
for (var i = digits - 1; i >= d; i--) {
if (a[i] == 0 && i == size - 1) size = i; // count used digits
sum += a[i]; // sum of digits
}
++a[d];
var target = weight * size - sum;
if (d == 0) return (target < 0) ? 1 : 0; // if d is lowest digit
if (target < 0) return table[d][0] + 1; // whole range is heavy
return (target > 9 * d) ? 0 : table[d][target]; // use look-up table
}
function decimalDigits(n) {
var array = [];
do {array.push(n % 10);
n = Math.floor(n / 10);
} while (n);
return array;
}
}
document.write("0 → 100,000,000 = " + countHeavy(0, 100000000, 7) + "<br>");
document.write("782 → 4321 = " + countHeavy(782, 4321, 7) + "<br>");
document.write("782 → 4321 = " + countHeavy(782, 4321, 5) + " (weight: 5)");
I really liked the post of #m69 so I wrote implementation inspired by it. The table creation is not that elegant, but works. For n+1 digits long integer I sum (at most) 10 values from n digits long integer, one for every digit 0-9.
I use this simplification to avoid arbitrary range calculation:
countHeavy(A, B) = countHeavy(0, B) - countHeavy(0, A-1)
The result is calculated in two loops. One for numbers shorter than the given number and one for the rest. I was not able to merge them easily. getResultis just lookup into the tablewith range checking, the rest of the code should be quite obvious.
public class HeavyNumbers {
private static int maxDigits = String.valueOf(Long.MAX_VALUE).length();
private int[][] table = null;
public HeavyNumbers(){
table = new int[maxDigits + 1][];
table[0] = new int[]{1};
for (int s = 1; s < maxDigits + 1; ++s) {
table[s] = new int[s * 9 + 1];
for (int k = 0; k < table[s].length; ++k) {
for (int d = 0; d < 10; ++d) {
if (table[s - 1].length > k - d) {
table[s][k] += table[s - 1][Math.max(0, k - d)];
}
}
}
}
}
private int[] getNumberAsArray(long number) {
int[] tmp = new int[maxDigits];
int cnt = 0;
while (number != 0) {
int remainder = (int) (number % 10);
tmp[cnt++] = remainder;
number = number / 10;
}
int[] ret = new int[cnt];
for (int i = 0; i < cnt; ++i) {
ret[i] = tmp[i];
}
return ret;
}
private int getResult(int[] sum, int digits, int fixDigitSum, int heavyThreshold) {
int target = heavyThreshold * digits - fixDigitSum + 1;
if (target < sum.length) {
return sum[Math.max(0, target)];
}
return 0;
}
public int getHeavyNumbersCount(long toNumberIncl, int heavyThreshold) {
if (toNumberIncl <= 0) return 0;
int[] numberAsArray = getNumberAsArray(toNumberIncl);
int res = 0;
for (int i = 0; i < numberAsArray.length - 1; ++i) {
for (int d = 1; d < 10; ++d) {
res += getResult(table[i], i + 1, d, heavyThreshold);
}
}
int fixDigitSum = 0;
int fromDigit = 1;
for (int i = numberAsArray.length - 1; i >= 0; --i) {
int toDigit = numberAsArray[i];
if (i == 0) {
toDigit++;
}
for (int d = fromDigit; d < toDigit; ++d) {
res += getResult(table[i], numberAsArray.length, fixDigitSum + d, heavyThreshold);
}
fixDigitSum += numberAsArray[i];
fromDigit = 0;
}
return res;
}
public int getHeavyNumbersCount(long fromIncl, long toIncl, int heavyThreshold) {
return getHeavyNumbersCount(toIncl, heavyThreshold) -
getHeavyNumbersCount(fromIncl - 1, heavyThreshold);
}
}
It is used like this:
HeavyNumbers h = new HeavyNumbers();
System.out.println( h.getHeavyNumbersCount(100000000,7));
prints out 569484, the repeated calculation time without initialization of the table is under 1us
I looked at the problem differently than you did. My perception is that the problem is based on the base-10 representation of a number, so the first thing you should do is to put the number into a base-10 representation. There may be a nicer way of doing it, but Java Strings represent Integers in base-10, so I used those. It's actually pretty fast to turn a single character into an integer, so this doesn't really cost much time.
Most importantly, your calculations in this matter never need to use division or floats. The problem is, at its core, about integers only. Do all the digits (integers) in the number (integer) add up to a value greater than or equal to seven (integer) times the number of digits (integer)?
Caveat - I don't claim that this is the fastest possible way of doing it, but this is probably faster than your original approach.
Here is my code:
package heavyNum;
public class HeavyNum
{
public static void main(String[] args)
{
HeavyNum hn = new HeavyNum();
long startTime = System.currentTimeMillis();
hn.countHeavy(100000000, 1);
long endTime = System.currentTimeMillis();
System.out.println("Time elapsed: "+(endTime- startTime));
}
private void countHeavy(int A, int B)
{
int heavyFound = 0;
for(int i = B+1; i < A; i++)
{
if(isHeavy(i))
heavyFound++;
}
System.out.println("Found "+heavyFound+" heavy numbers");
}
private boolean isHeavy(int i)
{
String asString = Integer.valueOf(i).toString();
int length = asString.length();
int dividingLine = length * 7, currTotal = 0, counter = 0;
while(counter < length)
{
currTotal += Character.getNumericValue(asString.charAt(counter++));
}
return currTotal > dividingLine;
}
}
Credit goes to this SO Question for how I get the number of digits in an integer and this SO Question for how to quickly convert characters to integers in java
Running on a powerful computer with no debugger for numbers between one and 100,000,000 resulted in this output:
Found 569484 heavy numbers
Time elapsed: 6985
EDIT: I initially was looking for numbers whose digits were greater than or equal to 7x the number of digits. I previously had results of 843,453 numbers in 7025 milliseconds.
Here's a pretty barebones recursion with memoization that enumerates the digit possibilities one by one for a fixed-digit number. You may be able to set A and B by controlling the range of i when calculating the corresponding number of digits.
Seems pretty fast (see the result for 20 digits).
JavaScript code:
var hash = {}
function f(k,soFar,count){
if (k == 0){
return 1;
}
var key = [k,soFar].join(",");
if (hash[key]){
return hash[key];
}
var res = 0;
for (var i=Math.max(count==0?1:0,7*(k+count)+1-soFar-9*(k-1)); i<=9; i++){
res += f(k-1,soFar+i,count+1);
}
return hash[key] = res;
}
// Output:
console.log(f(3,0,0)); // 56
hash = {};
console.log(f(6,0,0)); // 12313
hash = {};
console.log(f(20,0,0)); // 2224550892070475
You can indeed use strings to get the number of digits and then add the values of the individual digits to see if their sum > 7 * length, as Jeutnarg seems to do. I took his code and added my own, simple isHeavyRV(int):
private boolean isHeavyRV(int i)
{
int sum = 0, count = 0;
while (i > 0)
{
sum += i % 10;
count++;
i = i / 10;
}
return sum >= count * 7;
}
Now, instead of
if(isHeavy(i))
I tried
if(isHeavyRV(i))
I actually first tested his implementation of isHeavy(), using strings, and that ran in 12388 milliseconds on my machine (an older iMac), and it found 843453 heavy numbers.
Using my implementation, I found exactly the same number of heavy numbers, but in a time of a mere 5416 milliseconds.
Strings may be fast, but they can't beat a simple loop doing basically what Integer.toString(i, 10) does as well, but without the string detour.
When you add 1 to a number, you are incrementing one digit, and changing all the smaller digits to zero. If incrementing changes from a heavy to a non-heavy number, its because too many low-order digits were zeroed. In this case, it's pretty easy to find the next heavy number without checking all the numbers in between:
public class CountHeavy
{
public static void main(String[] args)
{
long startTime = System.currentTimeMillis();
int numHeavy = countHeavy(1, 100000000);
long endTime = System.currentTimeMillis();
System.out.printf("Found %d heavy numbers between 1 and 100000000\n", numHeavy);
System.out.println("Time elapsed: "+(endTime- startTime)+" ms");
}
static int countHeavy(int from, int to)
{
int numdigits=1;
int maxatdigits=9;
int numFound = 0;
if (from<1)
{
from=1;
}
for(int i = from; i < to;)
{
//keep track of number of digits in i
while (i > maxatdigits)
{
long newmax = 10L*maxatdigits+9;
maxatdigits = (int)Math.min(Integer.MAX_VALUE, newmax);
++numdigits;
}
//get sum of digits
int digitsum=0;
for(int digits=i;digits>0;digits/=10)
{
digitsum+=(digits%10);
}
//calculate a step size that increments the first non-zero digit
int step=1;
int stepzeros=0;
while(step <= (Integer.MAX_VALUE/10) && to-i >= step*10 && i%(step*10) == 0)
{
step*=10;
stepzeros+=1;
}
//step is a 1 followed stepzeros zeros
//how much is our sum too small by?
int need = numdigits*7+1 - digitsum;
if (need <= 0)
{
//already have enough. All the numbers between i and i+step are heavy
numFound+=step;
}
else if (need <= stepzeros*9)
{
//increment to the smallest possible heavy number. This puts all the
//needed sum in the lowest-order digits
step = need%9;
for(;need >= 9;need-=9)
{
step = step*10+9;
}
}
//else there are no heavy numbers between i and i+step
i+=step;
}
return numFound;
}
}
Found 569484 heavy numbers between 1 and 100000000
Time elapsed: 31 ms
Note that the answer is different from #JeutNarg's, because you asked for average > 7, not average >= 7.

How to check duplicate numbers and print out the read input numbers in the same order that they were read (excluding all duplicates.)

I'm trying to write a code. There I'll get max 1000 (int)inputs from an user (it has to be array[1000]) and it'll print out the ints in the same order as they were written.
Reading can be stopped by ctrl+z if the user wants that. The program will not write out duplicate numbers.
Example;
Input: 45 77 -22 3 45 0 21 -1 3
Output: 45 77 -22 3 0 21 -1
So far I've coded(within 2 days):
static int i = 0;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[] array = new int[1000];
int[] arrayCopy = new int[1000];
int k=0,j=0;
System.out.println("enter your integer numbers");
while(input.hasNext())
{
array[i] = input.nextInt();
for(j =0 ; j< array.length; j++)
{
arrayCopy[j] = array[j];
}
for( k =1; k<arrayCopy.length; k++)
{
int aV = arrayCopy[k];
}
i++;
}
input.close();
}
}
Use a HashMap to keep track of numbers already seen. Only add to your output string if it is a new number. You can modify your code with the following:
int[] array = new int[1000];
Scanner input = new Scanner(System.in);
int index = 0;
while(input.hasNext()) {
array[index] = input.nextInt();
index++;
}
HashMap<Integer, Boolean> seenNumbers = new HashMap<Integer, Boolean>();
String result = "";
for (int i = 0; i < index; i++) {
int value = array[i];
if (!seenNumbers.containsKey(value)) {
result += " " + value;
seenNumbers.put(value, true);
}
}
System.out.println(result);
The simplest solution is for me to use LinkedHashSet - will not allow duplicates and preserves insertion order
Set <Integer> set = new LinkedHashSet<>(1000);
while (input.hasNext()) {
int next = input.nextInt();
set.add(next);
}
input.close();
for (Integer number : set) {
System.out.print(number+" ");}
Should work
Provided you can resolve a sort order, and use arrays:
Below pseudocode and data. It's written as arrays, but you can ofc always loop where required. I also write the data without commas, as that's what my language Dyalog APL outputs ;-), but the data below are simply 9-element 1-dimensional arrays. The result seems to hold 7 elements.
You have
A = 45 77 -22 3 45 0 21 -1 3
Resolve the ascending sort order for A:
order = 3 8 6 4 9 7 1 5 2 // A[3] is smallest, then A[8], A[6], etc.
Write:
B = A[order] // B now holds: -22 -1 0 3 3 21 45 45 77
Loop through all but first element of B, check if next element is same as current. Write the result to C, which is a same-length vector of zeroes, however first element of C must be 1:
C = 1 0 0 0 0 0 0 0 0
s = 2
:While (s <= [length of C])
C[s] = (B[s-1] == B[s]) // C[s] is 0 or 1
s += 1
:End
Now C holds:
1 1 1 1 0 1 1 1 0
Create an empty variable D (or just copy from A or B - you will overwrite it):
D = A
Assign the elements of D as follows:
D[order] = C // D now holds: 1 1 1 1 0 1 1 1 0
Take only D elements of A (you pick elements of A and append them to a Result, which is initially empty - ie. has zero length):
s = 1
:While (s <= [lenght of A])
:if D[s] // Means: If (D[s] == 1)
[append A[s] to Result]
s += 1
:End
:End
Result now contains
45 77 -22 3 0 21 -1
Use Set instead of array. Set wont add duplicates.

Categories