Frequency counter for Strings in Java - java

I have a string that a user will type in representing time. i.e "10:05"
I've been searching for a while, and cannot find a way to search this string to find a specific number. The reason I need this number, is because I need to take each number and use an algorithm to discover how much power it takes to display this number on a digital clock. To do so, I need the frequency of each number. For example, if the time was 10:05, the number 0 would occur 2 times, and I can take that 2 and multiply it by the necessary numbers to discover the power needed.

This worked for me: (Assuming that time is entered always in xx:yy format)
public static void main(String args[])
{
String time = "10:07"; //User Input
time = time.replace(":", "");
char digit[] = {time.charAt(0), time.charAt(1), time.charAt(2), time.charAt(3)};
int[] count = new int[digit.length];
Arrays.sort(digit);
for (int i = 0; i < digit.length; i++)
{
count[i]++;
if (i + 1 < digit.length)
{
if (digit[i] == digit[i + 1])
{
count[i]++;
i++;
}
}
}
for (int i = 0; i < digit.length; i++)
{
if (count[i] > 0)
{
System.out.println(digit[i] + " appears " + count[i]+" time(s)");
}
}
}
Output:
0 appears 2 time(s)
1 appears 1 time(s)
7 appears 1 time(s)

I'm sure there's a more efficient way to do this, but:
String test = "10:05";
char[] array = test.toCharArray();
int counter = 0;
for(char c : array) {
if (c.Equals('0')) {
counter++;
}
}
System.out.println("The number '0' appears " + counter + " times."); //2

Create a map containing the number you want as key and the frequency that each number that appears as value. Iterate through the string, character by character, disregarding non-digit characters increment the digit-frequency mapping as you go.
Example:
HashMap<Integer, Integer> num_freq = new HashMap<>();
String input = "10:05"; // Example input
char[] input_chars = input.toCharArray();
for(char c : input_chars){
// Accept only characters that are digits
if(Character.isDigit(c)){
// Grabs digit from character
int num = Character.digit(c, 10);
// Put 1 into map if no entry exists, else increment existing value
num_freq.compute(num, (k_num, freq) -> freq == null ? 1 : freq + 1);
}
}
// Print result out
num_freq.forEach((num, freq) -> {
System.out.println("Digit " + num + " appears " + freq + " time(s)");
});

If I got your question, then below code will work, I hope -
int[] powerArr = {2,3,2,3,2,3,2,3,2,3};
String input = "10:05";
int powerConsumption = 0;
for(char c : input.replace(":", "").toCharArray()) {
powerConsumption = powerConsumption + powerArr[Integer.parseInt(String.valueOf(c))];
}
powerConsumption : Total power consumption
powerArr : array of power to display 0, then power to display 1 ... power to display 9
If you are interested on number of occurance only then -
int[] counterArr = {0,0,0,0,0,0,0,0,0,0};
String input = "10:05";
int tmpVal = 0;
for(char c : input.replace(":", "").toCharArray()) {
tmpVal = Integer.parseInt(String.valueOf(c));
counterArr[tmpVal] = counterArr[tmpVal]+1;
}
First value of counterArr will represent occurance of 0, second one of 1 and so on..

Related

Java: Sort a list of characters by frequency only using arrays

I'm trying to sort a list of characters and output them by the order of frequency with their associated frequency. For example, if the user puts in "beeeerr", I want it to out put "e freq: 4, r freq: 2, b freq: 1"
Here's what I have so far:
public static void sort(String charInput) {
int frequency = 0;
char [] charArray = charInput.toCharArray();
for (char charValue = ' '; charValue <= '~'; charValue++) {
frequency = 0;
for (int i = 0; i < charInput.length(); i++) {
char compare = charArray[i];
//charInput.charAt(i)
if (compare == charValue) {
frequency += 1;
}
}
if (frequency > 0) {
System.out.println(charValue + " freq: " + frequency);
}
}
}
The problem with this is it outputs the frequencies in alphabetical order. I can't figure out how to sort the outputs by their frequency. I know how to easily do this with Hashmaps or Arraylists, but I'm not allowed to use them. Any help would be much appreciated
//128 is for ascii, change it to 256 for extended ascii
//I assume all characters in the input are in ascii or extended ascii
public void frequencySort(String s) {
int n = s.length();
List<Character>[]res = new ArrayList[n+1];
int []cnt = new int[128];
char []ss = s.toCharArray();
for(int i=0;i<n;++i){
res[i+1]=new ArrayList<>();
cnt[ss[i]]++;
}
for(int i=0;i<128;++i){
if(cnt[i]!=0){
res[cnt[i]].add((char)i);
}
}
for(int i=n;i>0;--i){
if(!res[i].isEmpty()){
for(char c:res[i])
System.out.println("input has "+i+" " +c);
}
}
}
input has 4 e
input has 2 r
input has 1 b
With Java 8 Stream API, you can usually perform such operations with one liners:
str.chars().mapToObj(e->(char)e).collect(Collectors.toSet()).stream()
.collect(Collectors.toMap(ch -> ch, ch -> str.length() - str.replaceAll(ch.toString(), "").length()))
.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.forEach(e -> System.out.println(e.getKey() + " freq: " + e.getValue()));

Efficient way to get average string in list

Having a List that could contain an undefined number of "A", "B", "C" or "D", I have to calculate the average letter in the list.
For example, having [A, C] the average is B.
This is my approach:
public static String calculateAverage(final List<String> letters) {
int numberOfA = 0;
int numberOfB = 0;
int numberOfC = 0;
int numberOfD = 0;
for (String letter : letters) {
if (letter.equalsIgnoreCase("A")) {
numberOfA++;
}
if (letter.equalsIgnoreCase("B")) {
numberOfB++;
}
if (letter.equalsIgnoreCase("C")) {
numberOfC++;
}
numberOfD++;
}
int average =
(numberOfA * 1 + numberOfB * 2
+ numberOfC * 3 + numberOfD * 4)
/ letters.size();
if (average>=1 && average<2) return "A";
if (average>=2 && average<3) return "B";
if (average>=3 && average<4) return "C";
return "D";
}
Is there a more efficient way to do this?
If they are single characters, just sum them and divide by the count:
char averageCharacter(List<String> cs) {
int sum = 0;
for (String c : cs) {
sum += c.charAt(0);
}
return (char) (sum / cs.size()); // Potentially with different rounding.
}
You might want to round the integer division differently:
Floor is just sum / cs.size()
Ceil is (sum + cs.size() - 1) / cs.size()
Round is (sum + cs.size() / 2) / cs.size()
First:
You have an error in your code:
numberOfD++; is always called, because you don't use an if clause.
My approach would be (without writing it, this looks like a Homework you should do yourself):
Assign a int for A-D (lets say 65-68, what would be their char value)...
Loop through your String, add the value of the current Character to an counter
Afterwards divide the counter by the number of characters in your string
Result would be the ascii value of the "avarage" character, which you can cast to char.
Assuming you have validated your input (ie, all entries in the list are a valid 1-character letter):
int count = 0;
int total;
for(String s : letters) {
total += (int) s.charAt(0);
count++;
}
int average = total / count; //Watch out here, this is integer division.
//convert back to char:
return (char) average;
First, your code is incorrect. You are incrementing numberOfD each time, no matter what the letter is. At least make this correction:
for (String letter : letters) {
if (letter.equalsIgnoreCase("A")) {
numberOfA++;
} else if (letter.equalsIgnoreCase("B")) {
numberOfB++;
} else if (letter.equalsIgnoreCase("C")) {
numberOfC++;
} else
numberOfD++;
}
How about just averaging the unicode values:
char[] letters = {'A','B','C','D'};
int sum = 0;
for (char c : letters) {
sum += (int)c;
}
System.out.println((char)(sum/letters.length));

How to add numbers(integers) that are stored inside a string

I have to create a program that uses Luhn's algorithm to check to see if a credit card is valid.
The algorithm is this:
Form a sum of every other digit, including the right-most digit; so
5490123456789128 sums to 8+1+8+6+4+2+0+4 = 33
Form double each remaining digit, then sum all the digits that creates it; the remaining digits in our example (5 9 1 3 5 7 9 2) double to 10 18 2 6 10 14 18 4, which sums to 1+0+1+8+2+6+1+0+1+4+1+8+4 = 37
Add the two sums above (33+37 = 70)
If the result is a multiple of 10 (i.e., its last digit is 0) then it was a valid credit card number.
I made a Scanner and saved the credit card number into String card number
Then I created a while loop to save every other character starting from the right into a string. So now, I have a string filled with every other digit of the credit card number, starting from the right. However, I need to add up all of the digits within that string, which I can't figure out.
For example, if the user entered 1234 as the card number, the string everyotherdigit = 42. How can I add up 4 and 2 within the string?
There are numerous ways to do that. You can actually find your own solution by doing a bit of googling.
Anyway, this is what you can do:
Get individual characters from your string, and convert them to int.
String cardNumber = "5490123456789128";
int value = cardNumber.charAt(0) - '0';
Using a for loop and changing 0 to x(loop counter) will solve everything.
Get single String and convert to int.
String cardNumber = "5490123456789128";
int value = Integer.parseInt(cardNumber.substring(0,1));
I'd treat the string as an array of chars, and use Character.digit(int, int) to convert each character to the corresponsing int:
public static boolean isValidCreditCard (String s);
char[] arr = s.toCharArray();
int everyOtherSum = 0;
for (int i = arr.length - 1; i >= 0; i -= 2) {
everyOtherSum += Character.digit(arr[i], 10);
}
int doubleSum = 0;
for (for (int i = arr.length - 2; i >= 0; i -= 2) {
int currDigit = Character.digit(arr[i], 10);
int doubleDigit = currDigit * 2;
while (doubleDigit > 0) {
doubleSum += (doubleDigit % 10);
doubleDigit /= 10;
}
}
int total = everyOtherSum + doubleSum;
return total % 10 == 0;
}
So something like this would work for you:
public static void main(String[] args)
{
String cardNum = "5490123456789128";
String others = null;
int evenDigitSum = 0;
int oddDigitTransformSum = 0;
for (int pos = 0; pos < cardNum.length(); pos++)
{
if ((pos%2) != 0)
{
evenDigitSum += (cardNum.charAt(pos) - '0');
}
else
{
others = Integer.toString((cardNum.charAt(pos)-'0')*2);
for (char c : others.toCharArray())
{
oddDigitTransformSum += (c-'0');
}
}
}
System.out.println("Odds: " + oddDigitTransformSum);
System.out.println("Evens: " + evenDigitSum);
System.out.println("Total: " + (evenDigitSum+oddDigitTransformSum));
System.out.println("Valid Card: " + ((evenDigitSum+oddDigitTransformSum)%10==0));
}
public int cardCount(String numbers){
Stack<Integer> stack = new Stack<>();
int count = 0;
for(char c : numbers.toCharArray()){
stack.push(Character.getNumericValue(c));
}
int size = stack.size();
for(int i=1;i <= size; i++){
if(i%2 != 0){
count = count + stack.pop();
}else{
stack.pop();
}
}
return count;
}
This just does what you asked, not the entire algorithm

Accessing single letters in String / digits in numbers - Java

I have numeric input (11 digits), and I need to perform some operations on each digit (example: multiply 1st by 5, 2nd by 3, etc.). How can I do so in Java? Is there a simple way to access single letter / digit? Is there another way to do it?
If you don't want to convert the number to a string, then there is a simple trick.
digit = number % 10
will give you the right most digit.
number = number / 10
Will remove the right most digit from the number.
So you can run in a loop until the number reaches 0.
while(0 < number)
{
int digit = number % 10;
number = number / 10;
// do here an operation on the digits
}
You can use a for loop to help you count. For example
for(int index = 0; 0 < number; ++index, number /= 10)
{
int digit = number % 10;
// do an operation on the number according to the 'index' variable
}
Here is a similar StackOverFlow question on a similar question
Well there are many ways you can do it like :
int a = 12345;
int b;
while(a>0)
{
b = a%10;
System.out.print(b + " ");
a = a/10;
}
Here it gives you the digits in reverse order like you will get b=5 then b=4....
You can just manipulate them
Other way
int d = 12345;
String str = String.valueOf(d);
for(int i=0;i<str.length();i++)
{
char c = str.charAt(i);
System.out.print(Character.getNumericValue(c) * 10 + " ");
}
Or
char c[] = str.toCharArray();
for(Character ch : c)
{
System.out.print(Character.getNumericValue(ch) * 2 + " ");
}
You can use .charAt() to get a character from a string. Then using Character.getNumericValue() you can convert the character to an integer.
Like this:
String string = "1434347633";
int digit1 = Character.getNumericValue(string.charAt(1));
Convert that number input to String data type so that you can interpret it as a String.
int numbers = 1122334455; // integer won't be able to save this much data,
// just for example ok,
String numberString = numbers.toString();
foreach (char number in numberString) {
// do work on each of the single character in the string.
}
You should work them out, depending on the some condition.
If you want to access the digits by index without converting to a string, you can use these two functions length and digitAt:
public class DigitAt {
public static int length(long v) {
return (int) Math.ceil(Math.log10(v));
}
public static int digitAt(long v, int digit) {
return (int) ((v / (long) Math.pow(10, length(v) - digit - 1)) % 10);
}
public static void main(String[] args) {
System.out.println("Digits: " + length(1234567));
System.out.println(digitAt(1234567, 0));
System.out.println(digitAt(1234567, 1));
System.out.println(digitAt(1234567, 6));
}
}
public String stringAfterOperations(String digits) {
ArrayList<Integer> z = new ArrayList<Integer>();
for(Character c: digits.toCharArray()) {
z.add(Character.getNumericValue(c));
}
//TODO Set your own operations inside this "for"
for(int i=0; i<z.size(); i++){
if(i == 1){
z.set(i, z.get(i)*4);
}
else if(i == 7){
z.set(i, z.get(i)/3);
}
else {
z.set(i, z.get(i)+2);
}
}
String newString = "";
for(Integer i: z){
newString += i;
}
return newString;
}

corresponding permutation number

I have a given word, for wich I need to find its number of permutation on its corresponding sorted word .
Say I have word BABA , its corresponding sorted word would be, AABB, if I start permuting this sorted word, would come to AABB as a second "word", regardless of letter repetition, then ABAB, ABBA , BABA .. so the permute number for word BABA is 5 .
The easy way would be start doing all possible combinations, and then compared with the initial word .
so far , ive done..
import java.util.Arrays;
public class Permutation {
int location =1;
public static char[] warray;
void printArray(char []a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
System.out.println("location " + location );
}
void permute(char []a,int k ) {
if(k==a.length) {
location++;
// Check if the permuted word is the one looking for.
if (Arrays.equals(a, warray))
{ System.out.println("final iteration k" + k);
printArray(a);
System.exit(0);}
}
else
for (int i = k; i < a.length; i++) {
char temp=a[k];
a[k]=a[i];
a[i]=temp;
permute(a,k+1);
}
}
public static void main(String[] args) {
if (args[0].length() > 25 ) {
System.out.println(" Word not in permited range " );
System.exit(0);
}
else {
Permutation p=new Permutation();
warray = new char[args[0].length()];
char [] wpermute = new char[args[0].length()];
for (int i = 0; i < args[0].length(); i++) {
warray[i] = new Character(args[0].charAt(i));
wpermute[i] = new Character(args[0].charAt(i));
}
Arrays.sort(wpermute);
System.out.print("sorted word : " );
for (int i = 0; i < wpermute.length; i++) {
System.out.print(wpermute[i]);
}
p.permute(wpermute,0);
}
}
But this could be very slow performance.
My second guess, would be , starting like a binary search startting with first letter of unsorted word, calculate possibble permutations to have this letter as the first letter on permutations, and then second letter..and so ... would that sound good ?
If you only have 2 letters and if the length of the word is N and the number of A's is n then the number of permutations is N choose n.
If you have N letters total and n_a, n_b, ..., n_z describe the number of each letter then the total number of permutations is
N!/(n_a! n_b! n_c! ... n_z!)
Check out Multinomials, scroll down to the bit on permutations.
Another word would be QUESTION , its sorted word is EINOQSTU .
for question , q is in position 1 , and in postion 5 in the new word, how many permutations need to do to put is in postion 1 = 20161 .
Now I take second letter in question, is U, which is in position 8 in sorted word , how many permutations need to do, is 24481
I think, I could calculate , not perform, the number permutations needed to put a letter in y position, to be in X position. and then , the sum of all , would be the permutations needed for the whold word.
Now, how to calculate those numbers, I know has to be with factorial plus something else ..is not ?
So I finally completed the code, and yes, needed to check the multinomials.
also got part of the idea from a related post here.
But here my code.
package WordPuzzle;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/** Rafael G. */
public class WordPuzzle {
static String sortWord (String[] wordinput){
char [] wsorted = new char[wordinput[0].length()];
wsorted = wordinput[0].toCharArray();
Arrays.sort(wsorted);
String aux="";
for (int i = 0; i < wsorted.length; i++) {
aux = aux + wsorted[i];
}
return aux;
}
static void calculatePerm(String wordtofind,String wordsorted)
{
int sum = 0;
int numberpermutations;
char nextchar;
int charlocremainder =0;
String lowerLetters;
String greaterLetters;
Map<Character, Integer> characterCounts = new HashMap<Character, Integer> ();
int count ;
char letter;
int factorial;
int [] factorials = new int [wordsorted.length()+1];
factorial =1;
numberpermutations = 1;
int nMinusI;
int nextcharcount;
// set a mapping of repeated letters and its number
// and store factorial calculation.
for (int i = 0; i < wordsorted.length(); i++) {
letter = wordsorted.charAt(i);
factorial = factorial * (i+1);
factorials[i+1]= factorial;
count = characterCounts.containsKey(letter) ? characterCounts.get(letter) + 1 : 1;
characterCounts.put(letter, count);
}
String trimWord = new String(wordsorted);
for (int i = 0; i < wordtofind.length() ; i++){
nMinusI = wordtofind.length()-(i+1);
nextchar = wordtofind.charAt(i);
charlocremainder = trimWord.indexOf(nextchar);
lowerLetters = trimWord.substring(0, charlocremainder);
// Calculate the denominator which is the number of repeated letters
// of the formula (N-i)! * (Na+Nb) /Na!Nb!..
nextcharcount = characterCounts.get(nextchar);
characterCounts.put(nextchar, nextcharcount-1);
int denomfact = factorials[nextcharcount];
if (lowerLetters.length() > 1){
char x = lowerLetters.charAt(0);
char y = x;
for (int k = 1 ; k < lowerLetters.length(); k++){
y = lowerLetters.charAt(k);
if (x != y) {
denomfact = denomfact * factorials[characterCounts.get(x)];
x = y;
}
}
denomfact = denomfact * factorials[characterCounts.get(y)];
}
numberpermutations = factorials[nMinusI] * lowerLetters.length() / denomfact;
sum = sum + numberpermutations;
greaterLetters= trimWord.substring(charlocremainder+1);
trimWord = lowerLetters.concat(greaterLetters);
}
System.out.println(" Rank of permutation " + (sum+1));
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
long startTime = System.nanoTime();
String wordsorted;
String wordentered;
if (args[0].length() > 25 ) {
System.out.println("Word not in permited range " );
System.exit(0);
}
else {
wordentered = args[0].toUpperCase();
wordsorted = sortWord(args).toUpperCase();
calculatePerm(wordentered,wordsorted);
}
long endTime = System.nanoTime();
System.out.println("Took "+(endTime - startTime)/1000000000.0 + " seconds");
System.out.println("Took "+(endTime - startTime)* 0.000001 + " milliseconds");
}
}

Categories

Resources