How to count happy numbers - java

As an assignment I need to count the amount of happy numbers* in a given range. I did most of that already:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String inputLowerRange = scan.nextLine().trim();
String inputUpperRange = scan.nextLine().trim();
int lowerRange = Integer.parseInt(inputLowerRange);
int upperRange = Integer.parseInt(inputUpperRange);
Set<Integer> numbers = new HashSet<Integer>();
for (int i = lowerRange; i <= upperRange; i++)
while(lowerRange>0) {
upperRange += (lowerRange % 10)*(lowerRange % 10);
lowerRange /=10;
}
int counter = 0;
for (int i = lowerRange; i <= upperRange; i++) {
}
System.out.println(counter);
}
}
Now the code just needs to count the happy numbers* present within that range. I understand it is best done with:
if ............... counter++
but how exactly would I need to do it?
*A happy number is a number which eventually reaches 1 when replaced by the sum of the square of each digit. 13 is a happy number because 1^2 + 3^2 = 10
And 1^2 + 0^2 = 1, thus 13 is a happy number.

int counter = 0;
for(int i=lowerRange;i<=upperRange;i++)
{
int num=i,sum=0,rem;
while(sum!=1 && sum!=4)
{
sum=0;
while(num!=0)
{
rem=num%10;
sum+=(rem*rem);
num/=10;
}
num=sum;
}
if(sum==1)
counter++
}
System.out.println(counter);
the issue with your code is you are making direct changes to lowerRange and upperRange which will result in not iterating properly. You need to use temp variables for those. Also you forgot this condition while(sum!=1 && sum!=4){}
Set<Integer> numbers = new HashSet<Integer>(); //what's this for?
for (int i = lowerRange; i <= upperRange; i++)
while(lowerRange>0) { // missed one outer while loop
upperRange += (lowerRange % 10)*(lowerRange % 10); // changes to upperRange
lowerRange /=10; // changes to lowerRange
}

Try this.
static boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while (n > 1 && !set.contains(n)) {
set.add(n);
n = String.valueOf(n).chars()
.map(c -> c - '0')
.reduce(0, (sum, i) -> sum + i * i);
}
return n == 1;
}
public static void main(String args[]) throws IOException {
Scanner scan = new Scanner(System.in);
System.out.println(IntStream.rangeClosed(scan.nextInt(), scan.nextInt())
.filter(i -> isHappy(i))
.count());
}

import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
System.out.println(isHappy(null, 11));
}
public static boolean isHappy(Set<Integer> previousNumbers, int number) {
if (previousNumbers == null) previousNumbers = new HashSet<>();
else if (previousNumbers.contains(number)) return false;
if (number == 4) return true;
int length = getNumberLength(number);
int subNumber = 0;
for (int i = 0; i < length; i++) {
int digit = getNumberDigit(number, i);
subNumber += digit * digit;
}
previousNumbers.add(number);
return isHappy(previousNumbers, subNumber);
}
public static int getNumberDigit(int number, int index) {
int pow = (int) Math.pow(10, index);
return (number % (pow * 10)) / pow;
}
public static int getNumberLength(int number) {
int length = 0;
for (long temp = 1; temp <= number; temp *= 10)
length++;
return length;
}
}

Related

least Valuable Digit

This is my code and I do not know why the answer after 12 are incorrect.
First i calculate the Factorial of input number then I have to show the least valuable digit.
public class q3411 {
public static int leastValuableDigit(int n) {
for(int i = 0; i < String.valueOf(n).length(); i++) {
int x = (int) Math.floor((n % Math.pow(10, i + 1)) / Math.pow(10, i));
if(x != 0) return x;
}
return -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int fon = 1;
for(int i = 1; i <= n; i++) fon *= i;
System.out.println((leastValuableDigit(fon)));
}
}
First, I changed the algorithm of finding the factorial for more numbers.
The algorithm of finding the required number can be changed by removing all 0 from the factorial and taking the last of its bytes.
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static byte leastValuableDigit(BigInteger n) {
String num = String.valueOf(n).replaceAll("0", "");
return Byte.parseByte(String.valueOf(num.charAt(num.length() - 1)));
}
public static BigInteger getFactorial(int f) {
if (f <= 1) {
return BigInteger.valueOf(1);
}
else {
return BigInteger.valueOf(f).multiply(getFactorial(f - 1));
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
BigInteger fon = getFactorial(n);
System.out.println((leastValuableDigit(fon)));
}
}
Your algorithm is incorrect, cause you do a lot of unnecessary calculations and roundings

Generating vampire numbers in free range

I am writing program which generates Vampire numbers https://en.wikipedia.org/wiki/Vampire_number.
I have main function with numberOfDigits argument, which must be even. If numberOfDigits is equal 4, then we are searching Vampire Numbers in range 1000 to 9999 - four digits. If numberOfDigits is equal 6, then we are searching Vampire Numbers from 100000 to 999999 - which is six digits.
In following file, when I want to search Vampire numbers in range of 10 digits, Java heap space is screaming. Note that I have default settings for memory. But for, numberOfDigits == 4, 6 or 8, code is working correctly. (compared output to https://oeis.org/A014575/b014575.txt , https://oeis.org/A014575 ). So I want to ask,
What I can do to optimize this code? I have thought about using String with digits inside, instead of long/BigInteger. I want to "omit" that heap problem. Saving big numbers to file would be too slow, am I right?
My mate wrote (bigNum.cpp) http://pastebin.com/0HHdE848 - class in C++, to operate on big numbers. Maybe with help from community I could implement that in my a.java? More important - would it be useful for my problem?
edit: My goal is to generate free range of Vampire Numbers, like 4,6,8 - a.java it can do it, even more (if I can bypass heap space problem). And that is when my questions to help comes.
a.java (permutation code from johk95, https://stackoverflow.com/a/20906510 )
import java.util.ArrayList;
import java.util.Arrays;
/**
*
* #author re
*/
public class a {
/**
*
* #param numberOfDigits {int}
* #return ArrayList of Integer
*/
public ArrayList<Integer> vdf(int numberOfDigits) {
if ((numberOfDigits % 2) == 1) {
//or throw Exception of unrecognised format/variable?
System.out.println("cant operate on odd argument");
return new ArrayList<>();
}
long maxRange = 9;
for (int i = 1; i < numberOfDigits; i++) {
maxRange *= 10;
maxRange += 9;
}//numberOfDigits==4 then maxRange==9999, nOD==5 then maxRange==99999,..
long minRange = 1;
for (int i = 1; i < numberOfDigits; i++) {
minRange *= 10;
}//nOD==4 then minRange==1000, nOD==5 then minRange==10000, ..
ArrayList<Integer> ret = new ArrayList<>();
for (long i = minRange; i < maxRange; i++) {
long a = i;
long[] b = new long[numberOfDigits];
for (int j = numberOfDigits-1; j >= 0 ; j--) {
long c = a % 10;
a = a / 10;
b[j] = c;
}
int x = 0;
int y = 0;
ArrayList<long[]> list = permutations(b);
b = null; //dont need now
for(long[] s : list) {
for (int j = 0; j < numberOfDigits/2; j++) {
x += s[(numberOfDigits/2)-j-1] * Math.pow(10, j);
y += s[numberOfDigits-j-1] * Math.pow(10, j);
}
StringBuilder builder = new StringBuilder();
for (long t : s) {
builder.append(t);
}
String v = builder.toString();
if ((v.charAt((v.length()/2)-1) != '0'||
v.charAt(v.length()-1) != '0') &&
x * y == i) {
ret.add(x);
ret.add(y);
System.out.println(x*y+" "+x+" "+y);
break;
}
x = y = 0;
}
}
System.out.printf("%d vampire numbers found\n", ret.size()/2);
return ret;
}
/**
*
*#return vdf(4)
*/
public ArrayList<Integer> vdf() {
return vdf(4);//without trailing zeros
}
/* permutation code copied from
* johk95
* https://stackoverflow.com/a/20906510
*/
private static ArrayList<long[]> permutations(long[] lol) {
ArrayList<long[]> ret = new ArrayList<>();
permutation(lol, 0, ret);
return ret;
}
private static void permutation(long[] arr, int pos, ArrayList<long[]> list){
if(arr.length - pos == 1)
list.add(arr.clone());
else
for(int i = pos; i < arr.length; i++){
swap(arr, pos, i);
permutation(arr, pos+1, list);
swap(arr, pos, i);
}
}
private static void swap(long[] arr, int pos1, int pos2){
long h = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = h;
}
public static void main(String[] args) {
a a = new a();
try{
a.vdf(10); //TRY IT WITH 4, 6 or 8. <<<<
}catch (java.lang.OutOfMemoryError e){
System.err.println(e.getMessage());
}
}
}
EDIT: http://ideone.com/3rHhep - working code above with numberOfDigits == 4.
package testing;
import java.util.Arrays;
public class Testing
{
final static int START = 11, END = 1000;
public static void main(String[] args)
{
char[] kChar, checkChar;
String kStr, checkStr;
int k;
for(int i=START; i<END; i++) {
for(int i1=i; i1<100; i1++) {
k = i * i1;
kStr = Integer.toString(k);
checkStr = Integer.toString(i) + Integer.toString(i1);
//if(kStr.length() != 4) break;
kChar = kStr.toCharArray();
checkChar = checkStr.toCharArray();
Arrays.sort(kChar);
Arrays.sort(checkChar);
if(Arrays.equals(kChar, checkChar)) {
System.out.println(i + " * " + i1 + " = " + k);
}
}
}
}
}
This will generate vampire numbers, just modify the start and end integers.

4 Digit Java Counter

Hello I am coding something and I need a four digit counter, that when the method is called increases by one each time until I hit 9999. For example, before I call the method, the counter's value will be 0000. After I call the method it will increase to 0001, then 0002, and so on.
I will also like to be able to individually call each digit. I have no idea how this could be done, if someone can help me that'd be great.
What I tried doing:
private int[] count = new int[4];
private int counter;
private void countUp() {
count[counter++];
if (counter > count.length -1) {
counter = 0;
}
}
Try this simple solution:
private int[] count = new int[4];
private int counter;
private void countUp() {
counter++;
count[0] = counter %10;
count[1] = counter /10 % 10;
count[2] = counter /100 % 10;
count[3] = counter /1000 % 10;
}
Ngygens wont have a single digit per array. This has a single digit per array bit
private int[] count = new int[4];
private int counter;
private void countUp() {
counter++;
count[3] = counter /1000;
count[2] = (counter /100) % 10;
count[1] = (counter /10) % 10;
count[0] = counter %10;
}
If you want a solution that doesn't need heavy computation every time you increment. Furthermore it is fully scalable if you want a different maximum than 9999.
private int counter;
private int max = 9999;
private void countUp() {
if (counter < max)
counter++;
}
private int getDigit(int n) {
String counterAsString = String.valueOf(counter);
if (n < counterAsString.length())
return Integer.parseInt(String.valueOf(counterAsString.charAt(n)));
return 0;
}
I would go with an object-oriented approach. This would allow you to access methods to easily increment digits, peek at a particular digit, etc. While meter is an integer, the bind variable will keep the meter to four digits.
public class Counter {
private int meter = 0;
private boolean bind = true;
public static final int DIGIT_1 = 1000;
public static final int DIGIT_2 = 100;
public static final int DIGIT_3 = 10;
public static final int DIGIT_4 = 1;
/*
* Look at a particular digit's value
*/
public int peek(int digit) {
return (meter / digit) % 10;
}
/*
* By default, increments by 1.
*/
public void increment() {
this.increment(Counter.DIGIT_4);
}
/*
* Increments one of the digits
*/
public void increment(int digit) {
if(digit != Counter.DIGIT_1
&& digit != Counter.DIGIT_2
&& digit != Counter.DIGIT_3
&& digit != Counter.DIGIT_4) {
return;
}
this.meter += digit;
if(bind) {
this.meter = Math.abs(this.meter % 10000);
}
}
/*
* By default, adds the number to the right-most digit.
*/
public void add(int number) {
this.add(number, Counter.DIGIT_4);
}
public void add(int number, int digit) {
if(digit != Counter.DIGIT_1
&& digit != Counter.DIGIT_2
&& digit != Counter.DIGIT_3
&& digit != Counter.DIGIT_4) {
return;
}
this.meter += (digit * number);
if(bind) {
this.meter = Math.abs(this.meter % 10000);
}
}
/*
* Prints out the counter as four numbers
*/
#Override
public String toString() {
return String.format("%04d", this.meter);
}
/*
* An example
*/
public static void main(String[] arg) {
Counter c = new Counter();
c.add(-15000);
c.increment(Counter.DIGIT_2);
System.out.println(c + ": " + c.peek(Counter.DIGIT_4));
}
}
You don't need array:
private String count = "0000";
private int counter;
private void countUp() {
if (9999 < counter) {
return;
}
counter ++;
count = String.format("%04d", counter);
}
Try this:
Integer numwithoutzero;
char[] things = new char[4];
int zerocount = 4;
private void countUp() {
char[]c = String.valueOf(numwithoutzero).toCharArray();
for(int i = 0;i<=zerocount;i++)things[i]='0';
for(int i = 0;i<=String.valueOf(numwithoutzero).length();i++){
for(int b = c.length;b>=0;b--){
things[b] = c[i];
}
}
numwithoutzero++;
zerocount = 4 - c.length
}
didn't get you well but if you want a sequence of 0000,0001,0002,0003,...9999 just try this:
String[] counter=new String[10000];
for (int i=0;i<=9999;i++){
counter[i]=String.format("%04d", i);
}
import java.util.Scanner;
public class count0001to0002{
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("Enter number: ");
int num = sc.nextInt();
int[] count = new int[4];
for(int x=0; x<=num; x++){
int counter = x;
count[3] = counter %10;
count[2] = counter /10 % 10;
count[1] = counter /100 % 10;
count[0] = counter /1000 % 10;
for(int y=0; y<4; y++){
System.out.print(count[y]);
}
System.out.println();
}
for(int x=0; x<4; x++){
System.out.print(count[x]);
}
}
}

Optimization of a Java code

This is a code in an online contest I've been trying. The time limit set at the online judge is 1 sec and the order of test cases is 10^5.
import java.util.Scanner;
class My_Number {
int primeNo;
boolean divisible[] = new boolean [60];
My_Number(int primeNo) {
this.primeNo = primeNo;
}
void setDivisible() {
for (int i=0; i<60; i++) {
if(i%primeNo == 0) {
divisible[i] = true;
}
}
}
}
class BestWorse {
My_Number gb [] = {
new My_Number(2), new My_Number(3), new My_Number(5), new My_Number(7), new My_Number(11),
new My_Number(13), new My_Number(17), new My_Number(19), new My_Number(23), new My_Number(29),
new My_Number(31), new My_Number(37), new My_Number(41), new My_Number(43), new My_Number(47),
new My_Number(53), new My_Number(59)
};
boolean master_list [] = new boolean [86400];
void initialize() {
for (My_Number gb1 : gb) {
gb1.setDivisible();
}
}
private boolean isBad(int hh, int mm, int ss) {
for(My_Number gb1: gb) {
if(gb1.divisible[hh] && gb1.divisible[mm] && gb1.divisible[ss]) {
return true;
}
}
return false;
}
private int findGCD(int a, int b) {
int r, i;
while(b!=0){
r = a % b;
a = b;
b = r;
}
return a;
}
void fillUpTheMasterList() {
int hh =0, mm = 0, ss = 1;
while( !(hh==0 && ss==0 && mm==0)) {
if (isBad(hh, mm, ss)) {
master_list[hh*60*60+mm*60+ss] = true;
}
ss++;
if(ss == 60) {
ss = 0;
mm++;
if(mm == 60) {
mm = 0;
hh++;
if(hh == 24) {
hh = 0;
}
}
}
}
}
String countBestAndWorse(int hh, int mm, int ss) {
int good = 0, bad = 0;
for(int i=hh*60*60+mm*60+ss; i<86400; i++) {
if(master_list[i]) {
bad++;
}
else {
good++;
}
}
if(good != 0 && bad != 0)
{
int gcd = findGCD(good, bad);
good /= gcd;
bad /= gcd;
}
return bad + ":" +good;
}
public static void main(String[]args) {
int n;
Scanner scn = new Scanner(System.in);
BestWorse best_worse = new BestWorse();
best_worse.initialize();
best_worse.fillUpTheMasterList();
n = scn.nextInt();
for(int i=0; i<n;i++) {
int hh = scn.nextInt();
int mm = scn.nextInt();
int ss = scn.nextInt();
System.out.println(best_worse.countBestAndWorse(hh, mm, ss));
}
}
}
For some reason, I am continuously getting the error as 'Time limit exceeded'.
Things I tried:
Using BufferedReader instead of Scanner
Maintaining a master_list of the answer(already implemented in my solution).
I tried the Netbeans profiler and it's output for input of 5000 (hh=0 mm=0 ss=1) numbers is pasted here. Also, the question is posted here.
From the profiler, it seems like findGCD is taking up majority of the time. But I googled around and found out that this is indeed the fastest algorithm to calculate GCD. I also tried to maintain a lookup table for GCD; perhaps the same GCD is calculated again and again. Still no luck!
I've reached my limit for this question and need help. Can anyone please help me out here?
Its all about using the correct algorithm.
Check out this approach:
import java.util.Scanner;
public class GoodBadTime
{
private int goodTimeCounter[][][];
private int badTimeCounter[][][];
private static final int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
public GoodBadTime ()
{
initializeGoodBadTimes ();
try (Scanner scanner = new Scanner (System.in))
{
int testCases = scanner.nextInt ();
for (int i = 0; i < testCases; ++i)
{
int h = scanner.nextInt ();
int m = scanner.nextInt ();
int s = scanner.nextInt ();
System.out.println (badTimeCounter[h][m][s] + ":" + goodTimeCounter[h][m][s]);
}
}
}
private void initializeGoodBadTimes ()
{
goodTimeCounter = new int[24][60][60];
badTimeCounter = new int[24][60][60];
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
boolean isBadTime = false;
int prime;
for (int p = 0; p < primes.length && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = true;
break;
}
}
if (isBadTime)
{
++cumulativeBadCounter;
}
else
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
goodTimeCounter[h][m][s] = cumulativeGoodCounter / gcd;
badTimeCounter[h][m][s] = cumulativeBadCounter / gcd;
}
}
}
}
private int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
public static void main (String[] args)
{
new GoodBadTime ();
}
}
Let me know if there's something I need to explain in my code that isn't obvious, so that I can edit my answer and explain it to you.
This was just my first attempt to solve it, there can be better ways to do it as well.
But this approach should give out the output within 1 second, so I guess, I don't cross the threshold limit with this approach.
Update
Here's an update to the answer:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GoodBadTime
{
private int goodTimeCounter[];
private int badTimeCounter[];
private static final int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
public GoodBadTime ()
{
initializeGoodBadTimes ();
try (BufferedReader reader = new BufferedReader (new InputStreamReader (System.in)))
{
int testCases = Integer.parseInt (reader.readLine ());
for (int i = testCases; i > 0; --i)
{
String[] hms = reader.readLine ().split ("\\s+");
int h = Integer.parseInt (hms[0]);
int m = Integer.parseInt (hms[1]);
int s = Integer.parseInt (hms[2]);
int index = h + 24 * (m + 60 * s);
System.out.printf ("%d:%d\n", badTimeCounter[index], goodTimeCounter[index]);
}
}
catch (IOException e)
{
e.printStackTrace ();
}
}
private void initializeGoodBadTimes ()
{
goodTimeCounter = new int[24 * 60 * 60];
badTimeCounter = new int[24 * 60 * 60];
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
boolean isBadTime = false;
int prime;
for (int p = 0; p < primes.length && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = true;
++cumulativeBadCounter;
break;
}
}
if (!isBadTime)
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
// Original[h, m, s] = Flat[h + 24 * (m + 60 * s)]
int index = h + 24 * (m + 60 * s);
goodTimeCounter[index] = cumulativeGoodCounter / gcd;
badTimeCounter[index] = cumulativeBadCounter / gcd;
}
}
}
}
private int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
public static void main (String[] args)
{
new GoodBadTime ();
}
}
This should be faster than the previous one, since I'm using 1D array and BufferedReader this time.
Here's a C equivalent:
#include <stdio.h>
int goodTimeCounter[24 * 60 * 60];
int badTimeCounter[24 * 60 * 60];
const int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
void initializeGoodBadTimes ()
{
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
int isBadTime = 0;
int prime;
for (int p = 0; p < 9 && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = 1;
++cumulativeBadCounter;
break;
}
}
if (!isBadTime)
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
// Original[h, m, s] = Flat[h + 24 * (m + 60 * s)]
int index = h + 24 * (m + 60 * s);
goodTimeCounter[index] = cumulativeGoodCounter / gcd;
badTimeCounter[index] = cumulativeBadCounter / gcd;
}
}
}
}
int main (int argc, const char * argv[])
{
initializeGoodBadTimes();
int testCases;
scanf("%d", &testCases);
for(int i = testCases; i > 0; --i)
{
int h, m, s;
scanf("%d %d %d", &h, &m, &s);
int index = h + 24 * (m + 60 * s);
printf("%d:%d\n", badTimeCounter[index], goodTimeCounter[index]);
}
return 0;
}
Note: GCD is calculated constant number of times, irrespective of the input size.
Also, int is sufficient for this program, since no counter ever exceeds 86400 since that's the maximum number of good or bad times that can happen.
Its equally strange for me that Online Judge is calling it as "Wrong Answer", since I think I am following every constraint set by the question.
Also, while testing for the two inputs, the program gave the correct answer despite the input being far apart in time. Induction would say that it should keep giving correct answers. Do you happen to know which output is wrong?
Also, can you put a link to this question which is present on the Online Judge site, so that I can check it out myself, and provide a correct answer to you?
The contest is rather unclear; at least to me. It says "none of them was divisible by the same prime number" which makes no sense, and if it did, I'd interpret it as that all the numbers must be co-prime. The next sentence sounds more like gcd(h, gcd(m, s)) <= 1 for good days.
I'm offering some untested potential improvements to Aman Agnihotri's algorithms. By creating the cumulative table, the biggest optimization is already done.
There is a faster GDC algorithm, but I wouldn't bother as all you need is to fill a 60x60 table. This could be done even without GCD by something like
int[] gcdTable = new int[60*60];
Arrays.fill(gcdTable, 1);
for (int p=2; p<60; ++p)
for (int i=0; i<60; i+=p)
for (int j=0; j<60; j+=p)
gcdTable[60*i+j] = Math.max(gcdTable[60*i+j], p);
Then use it as
int gcd(int a, int b) {
return gcdTable[60*a+b];
}
in
boolean isGood(int h, int m, int s) {
return gcd(h, gcd(m, s)) <= 1;
}
to fill the cumulative table. I guess, using a 1D array via
int secondOfDay(int h, int m, int s) {
return 3600*h + 60*m + s;
}
should be a bit faster than a 3D array. You don't need to store both remaining good and bad seconds, as their sum equals to 24*3600 - secondOfDay. My above table is too small for use for the expressing of the B:G ratio in smallest common terms, so you'll need one proper GCD per sample.

Difference of Opinion for Counts

I made 2 small scripts in physics today, but now it is starting to bug me.
The first script, is 100% accurate: It is used to calculate the number of bill and coins required for the desired amount of cash.
First Script:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Change {
static Money[] coins;
static int[] counts;
public static void main(String[] args) throws IOException {
coins = new Money[11];
counts = new int[11];
coins[0] = new Money(100);
coins[1] = new Money(50);
coins[2] = new Money(20);
coins[3] = new Money(10);
coins[4] = new Money(5);
coins[5] = new Money(2);
coins[6] = new Money(1);
coins[7] = new Money(25, true);
coins[8] = new Money(10, true);
coins[9] = new Money(5, true);
coins[10] = new Money(1, true);
System.out.println("Please type the change:\n");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String values = br.readLine();
String[] split = values.split("\\.");
System.out.println();
int whole = Integer.parseInt(split[0]);
int small = Integer.parseInt(split[1]);
for (int i = 0; i < 7; i++) {
while (whole >= coins[i].getValue()) {
whole -= coins[i].getValue();
counts[i]++;
}
}
for (int i = 7; i < 11; i++) {
while (small >= coins[i].getValue()) {
small -= coins[i].getValue();
counts[i]++;
}
}
for (int i = 0; i < 11; i++) {
if (counts[i] > 0)
System.out
.println((coins[i].getValue() == 100 ? "" : " ")
+ (coins[i].isDecimal() ? (" 0."
+ (coins[i].getValue() < 10 ? "0" : "") + coins[i]
.getValue()) + ": " + counts[i]
: ((coins[i].getValue() <= 5 ? " " : "") + coins[i]
.getValue())
+ ".00: "
+ counts[i]));
}
}
public static class Money {
int value;
boolean decimal;
Money(int value) {
this(value, false);
}
Money(int value, boolean decimal) {
this.value = value;
this.decimal = decimal;
}
boolean isDecimal() {
return decimal;
}
int getValue() {
return value;
}
}
}
Second script:
import java.io.IOException;
public class ChangeMax {
static Money[] coins;
static int[] nums = new int[2];
static int max = -2147483648;
public static void main(String[] args) throws IOException{
coins = new Money[11];
coins[0] = new Money(100);
coins[1] = new Money(50);
coins[2] = new Money(20);
coins[3] = new Money(10);
coins[4] = new Money(5);
coins[5] = new Money(2);
coins[6] = new Money(1);
coins[7] = new Money(25, true);
coins[8] = new Money(10, true);
coins[9] = new Money(5, true);
coins[10] = new Money(1, true);
for(int i = 0; i < 100; i++){
int temp1 = i;
for(int h = 1; h < 100; h++){
int temp2 = h;
int[] counts = new int[100];
for (int j = 0; j < 7; j++) {
while (temp1 >= coins[j].getValue()) {
temp1 -= coins[j].getValue();
counts[j]++;
}
}
for (int k = 7; k < 11; k++) {
while (temp2 >= coins[k].getValue()) {
temp2 -= coins[k].getValue();
counts[k]++;
}
}
int sum = 0;
for(int p : counts){
sum += p;
}
if(sum > max){
max = sum;
nums[0] = i;
nums[1] = h;
}
}
}
System.out.println("\nMax coins and bills required at: $"+nums[0]+"."+(nums[1] > 9 ? nums[1] : "0" + nums[1]) + ": "+max+"\n");
}
public static class Money {
int value;
boolean decimal;
Money(int value) {
this(value, false);
}
Money(int value, boolean decimal) {
this.value = value;
this.decimal = decimal;
}
boolean isDecimal() {
return decimal;
}
int getValue() {
return value;
}
}
}
The second script, does the same thing, but runs through all the values under $100.
The problem is, is that the second script says the max amount is 9, and achieved at $0.94.
The first, script, when you type something like $1.94, does not register that 10 is the new highest number, instead of 9.
What seems to be the problem?
Since I am not planning on doing your homework I am not going to provide you with working code, but both scripts can be easily improved
1) Your money objects know whether a value of e.g. 10 represents 10 whole dollars, or 10 cents (or whatever you use in America, I would use Euro's and cents). But still you use an hard-coded index of your array where you switch from dollars to cents
2) The first script will fail when somebody uses a nice rounded number as input, without decimal part
3) If you would convert your input first to cents, and all your values in your coin array as well, your code will end up much cleaner and easier to understand. Something in the form of
int startAmount = ... ;//in cents
int remainder = startAmount;
int coinCounter = new int[coins.length];
for ( int i = 0; i < coins.length; i++ ){
int currentCoin = coins[i];//in cents
coinCointer[i] = 0;
while( remainder >= currentCoin ){
coinCointer[i] = coinCointer[i] + 1;
remainder = remainder - currentCoin;
}
}
//print out by looping over coinCounter,
//and use the info contained in the Money class

Categories

Resources