Java: Assign values to alphabet and determine value of a string - java

So I am trying to solve the problem in Java below. Could someone give me an idea of how to approach this? I can only think of using a bunch of confusing for-loops to split up the arr, go through the alphabet, and go through each string, and even then I am confused about strings versus chars. Any advice would be great.
--
Suppose the letter 'A' is worth 1, 'B' is worth 2, and so forth, with 'Z' worth 26. The value of a word is the sum of all the letter values in it. Given an array arr of words composed of capital letters, return the value of the watch with the largest value. You may assume that arr has length at least 1.
{"AAA","BBB","CCC"} => 9
{"AAAA","B","C"} => 4
{"Z"} => 26
{"",""} => 0
--
Here is what I have tried so far but I'm lost:
public static int largestValue(String[] arr){
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int largest = 0;
int wordTotal=0;
for (int i = 0; i < arr.length; i++){
String[] parts = arr[i].split("");
if (wordTotal < largest){ //I don't think this is in the right place
largest = 0; }
for (int j = 0; j < alphabet.length(); j++){
for(int k = 0; k <parts.length; k++){
if ( alphabet.charAt(j) == parts[k].charAt(0) ){
wordTotal = 0;
wordTotal += alphabet.indexOf(alphabet.charAt(j))+1;
}
}
}
}
return largest;
}

I would start by breaking the problem into parts, the first step is summing one String. To calculate the sum you can iterate the characters, test if the character is between 'A' and 'Z' (although your requirements say your input is guaranteed to be valid), subtract 'A' (a char literal) from the character and add it to your sum. Something like,
static int sumString(final String str) {
int sum = 0;
for (char ch : str.toCharArray()) {
if (ch >= 'A' && ch <= 'Z') { // <-- validate input
sum += 1 + ch - 'A'; // <-- 'A' - 'A' == 0, 'B' - 'A' == 1, etc.
}
}
return sum;
}
Then you can iterate an array of String(s) to get the maximum sum; something like
static int maxString(String[] arr) {
int max = sumString(arr[0]);
for (int i = 1; i < arr.length; i++) {
max = Math.max(max, sumString(arr[i]));
}
return max;
}
or with Java 8+
static int maxString(String[] arr) {
return Stream.of(arr).mapToInt(x -> sumString(x)).max().getAsInt();
}
And, finally, validate the entire operation like
public static void main(String[] args) {
String[][] strings = { { "AAA", "BBB", "CCC" }, { "AAAA", "B", "C" },
{ "Z" }, { "", "" } };
for (String[] arr : strings) {
System.out.printf("%s => %d%n", Arrays.toString(arr), maxString(arr));
}
}
And I get
[AAA, BBB, CCC] => 9
[AAAA, B, C] => 4
[Z] => 26
[, ] => 0

I think it helps to take note of the two key parts here:
1: You need to be able to find the value of a single word, which is the sum of each letter
2: You need to find the value of all words, and find the largest
Since you need to go through each element (letter/character) in a string, and also each element (word) in the array, the problem really is set up for using 2 loops. I think part of the whole problem is making the for loops clear and concise, which is definitely doable. I don't want to give it away, but having a function that, given a word, returns the value of the word, will help. You could find the value of a word, see if its the largest so far, and repeat. Also, to find the value of a word, please do not use 26 if's (look up ASCII table instead!). Hope this gives you a better understanding without giving it away!

Related

Not able to understand the code to Count Duplicates in a string?

This program finds the count of duplicates in a string.
Example 1:
Input:
"abbdde"
Output:
2
Explanation:
"b" and "d" are the two duplicates.
Example 2:
Input:
"eefggghii22"
Output:
3
Explanation:
duplicates are "e", "g", and "2".
Help me with this code.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Write your code here
int c = 0;
str1 = str1.toLowerCase();
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
c = ctr[i];
}
}
return c;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
You need to maintain a count and if the value of that character exceeds 1, you need to increment the count.
Return that count to know the count of duplicates.
Added comments to understand the code better.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Initialised integer to count the duplicates
int count = 0;
// Converting a string to lowercase to count lowerCase and Uppercase as duplicates
str1 = str1.toLowerCase();
// According to ASCII, the Maximum number of characters is 256,
// So, initialized an array of size 256 to maintain the count of those characters.
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
count = count + 1;
}
}
return count;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
In short it is counting the number of characters appearing in the String str and saving it in ctr array.
How? ctr is the array that has a length of 256. So it can have 256 values (0-255 indexed). str1 is the string that contains the String. charAt(i) method returns the character at index i. Because String acts like an array where you can access each char a index values of an array.
Now assuming your input will always ASCII characters, each ASCII chars contain a value of 0-255 (i.e. ASCII value 'a' is 97). ++ after any variable means adding 1 to that. i.e.c++ means c = c+1
Now coming to the loop, ctr[str1.charAt(i)]++;, you can see the loops starts from 0 and ends at the length of the String str where 0 is the first value str. So if value of 0 indexed value (first value) of the String str is a, str.charAt(0) would return 97(well actually it will return 'a' but java takes the ASCII value). so the line actually is (for 0 th index) ctr[97]++; so it's incrementing the value of the 97th index (which is initially 0) by 1. So now the value is 1.
Like this way it will only increment the index values that matches with the ASCII values of the character in the String, thus counting the amount of time the characters occur.

How can we calculate frequency of characters in a string

I was looking into the solution of the problem.
static void printCharWithFreq(String str)
{
// size of the string 'str'
int n = str.length();
// 'freq[]' implemented as hash table
int[] freq = new int[SIZE];
// accumulate freqeuncy of each character
// in 'str'
for (int i = 0; i < n; i++)
freq[str.charAt(i) - 'a']++;
// traverse 'str' from left to right
for (int i = 0; i < n; i++) {
// if frequency of character str.charAt(i)
// is not equal to 0
if (freq[str.charAt(i) - 'a'] != 0) {
// print the character along with its
// frequency
System.out.print(str.charAt(i));
System.out.print(freq[str.charAt(i) - 'a'] + " ");
// update frequency of str.charAt(i) to
// 0 so that the same character is not
// printed again
freq[str.charAt(i) - 'a'] = 0;
}
}
}
I am not able to understand how
for (int i = 0; i < n; i++)
freq[str.charAt(i) - 'a']++;
is able to calculate the frequency of the elements.
and how is it stored back in to the position.
I am confused with it.
Can anyone please help me with it?
The lowercase ASCII letters are occupying a continuous part of the ASCII table, from index 97 to 122. If your input is composed of lowercase ASCII letters the expression str.charAt(i) - 'a' will evaluate to values from range [0, 25]. a will become 0, b will become 1, c will become 2 and so on.
However this approach fails for non lowercase ASCII characters, e.g. uppercase 'A' letter has value 65, 'A' - 'a' will be 65 - 97 thus attempting to access a negative array index.
It seems to me that you could rewrite your solution in a much simpler way. Unless i'm misunderstanding it then that solution is far more complex than it needs to be.
s.chars().mapToObj(c -> (char) c).collect(Collectors.groupingBy(c -> c, Collectors.counting()));
As for the frequency, characters in Java are backed by ASCII codes. So you can subtract chars from each other to obtain ASCII values. Thanks to #BackSlash for the stream implementation.

Generating all words of length N from a given alphabet in Java

The cleanest way to generate all N - length words, with characters from a given alphabet , such that they must have in them a given character c.
If the length is 2, for an alphabet with this characters {a,b} , and the character is 'b' it should return a list like this:
ab , ba , bb
So far I am thinking of using nested loops, but it's not clean, or using similar methods to permutation , to generate them all by increment the least significant bit and wrapping around when reaching last character from alphabet.
EDIT:
ArrayList <String> data = new ArrayList <String>();
int iterations = (int) Math.pow(alfabet.length, N);
int pos [] = new int [N];
pos[N-1] = -1;
for (int i = 0 ; i < iterations;i++)
{
pos[N-1]++;
for (int j = N-1; j >= 0;j--)
{
if (pos[j] == alfabet.length)
{
pos[j] = 0;
pos[j-1] ++;
}
else break;
}
String word = "";
for (int j = 0 ; j < N; j++ )
{
word += alfabet[pos[j]];
}
int val = 0;
for (int j = 0 ; j < lst.length; j++)
{
if (word.contains(lst[j] + "")) val++;
}
if (val == lst.length) data.add(word);
}
return data;
This is the function i built, i made the alphabet static, for easier access through the code, and because i wont change it.
Improved on it a bit, and made it so that it doesnt check just a character, but a certain array of characters.
Would like a review of clarity, complexity or some things that i might have looked over.
Since you didn't provide any Java code, I won't either ;) I don't want to spoil your fun...
A short, somewhat fast, non-recursive solution in pseudocode (aka, Swift) to get you going:
let alphabet = ["a", "b", "c"]
let requiredChar = 2
func printAllWords() {
var word = [0, 0]
for _ in 0 ..< pow(alphabet.count, word.count) {
if word.contains(requiredChar) { print(word) }
for char in 0 ..< word.count {
word[char] = (word[char] + 1) % alphabet.count
if word[char] != 0 { break } // overflow
}
}
}
outputs the desired words:
ca
cb
ac
bc
cc
This should run in O(n.zⁿ) time complexity, where:
n is the word length;
and z the alphabet length.
To play around with this code, try this Swift sandbox.
Getting a working Java version out of this should be straightforward. A Kotlin version should be even easier... ;)

How can I reprint a string starting from the first character till the last?

Given a non-empty string str like "Code" print a string like "CCoCodCode". Where at each index in the string you have to reprint the string up to that index.
I know there is DEFINITELY something wrong with this code that I wrote because the answer should be CCoCodCode, but instead it's giving me the alphabet! I don't know how I should change it.
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String str = scan.next();
int x = str.length();
for(char i = str.charAt(0); i <= str.charAt(x-1); i++)
{
System.out.print(i);
}
}
The char datatype can be treated as a number; you can increment it and manipulate it as a number.
What you really want is successive substrings of str to be printed. Loop over an int that will represent the ending position of the substring to be printed.
for (int i = 0; i < str.length(); i++)
{
System.out.print(str.substring(0, i + 1));
}
The end index argument to substring is exclusive, which is why I added 1.
Let's say that str is "Code". We can perform some mental substitutions to see what happens to your loop.
str is "Code"
x is 4
str.charAt(0) is 'C'
str.charAt(x-1) is 'e'
Making these substitutions, your loop is:
for(char i = 'C'; i <= 'e'; i++)
{
System.out.print(i);
}
Does this help you see the problem? I would think you'd have a loop from 0 to 3, not from 'C' to 'e'...
Many ways to get it done, suppose we have the input from user stored in a string named "c"... then...
String c = "Code";
for (int i = 0; i < c.length(); i++) {
System.out.print(c.substring(0, i));
}
System.out.print(c);
And this will print the sequence you are looking for.
It is outputting the alphabet because you are printing the counter instead of the characters in the string!
As it is, the first iteration of the for loop will set i to the first character, print that, then the operation i++ will increment i by one. Wait, so if the first character is "C", so i = 'C', what is i++?
Well it turns out characters can be represented by numbers. For example, 'C' has a value of 67. So incrementing it makes it 68, which represents 'D'. So if you run the loop on "Code", it will increment your counter 4 times, giving "CDEF". If you run on "Codecodecode", that will make the loop run 12 times, giving "CDEFGHIJKLMN".
What you really want is to loop through the string by its index instead:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.next();
int length = str.length();
for (int i = 0; i < length; i++) {
System.out.print(str.substring(0, i + 1));
}
}

How to go about making this type of combination?

I have a four letter string of letters, such as ASDF and I want to find all 3 (three) letter combinations using these letters and the three letter combination does not need to form a real word.Ex.
AAA AAS AAD AAF
ADA ADS ADD ADF
...............
SSA SSD SSF SSS
I am relatively new to Java, having just learned how to use the String class and using loops and conditional statements. The only way that I know how to do this is by a massive and very tedious set of for loops and if statements that account for every possibility that could arise. This would look like:
public static void main(String[] args)
{
String combo = "";
for(int counter = 1; counter <= 16; counter++){
combo = "A";
if(counter == 1){
combo = combo + "AA";
}
// This would continue on for all the possibilities starting with "A" and
// then move on to "S" as the lead character
}
}
I know that this is one of the worst ways to go about this problem, but I am really stuck as to how to do it another way. It would be easier if I had 3 letters and made the 3 letter combos, as then I could just get each letter from the array and just rearrange them, but as I'm only using 3 of the 4 letters it is more difficult. Any advice on how to get this done in an more efficient manner?
Use a recursive function.
Like this (not tested, don't have a Java compiler on my laptop).
Performance could probably be boosted by using StringBuilder.
static void printAllPossibilities(String charSet, int length) {
printAllPossibilities_(charSet, length, "");
}
static void printAllPossibilities_(String charSet, int length, String temp) {
if (length == 0) {
System.out.println(temp);
return;
}
for (int i = 0; i < charSet.length(); i++)
printAllPossibilities_(charSet, length - 1, temp + charSet.charAt(i));
}
Usage:
printAllPossibilities("ASDF", 4); // Print all 4-letter combinations out of "ASDF"
printAllPossibilities("bar", 2); // Print all 2-letter combinations out of "bar"
For the general case (all combinations of N chars out of M), the solution by #Qntm is exactly what you need... but, use a StringBuilder as he said, and just change the last character instead of constructing strings like 'temp + charSet.charAt(i)'.
If you need exactly 3 chars out of N, it's easier to just do 3 nested loops:
for (int char1 = 0; char1 < charSet.length(); char1++) {
for (int char2 = 0; char2 < charSet.length(); char2++) {
for (int char3 = 0; char3 < charSet.length(); char3++) {
System.out.println(""+charSet.charAt(char1)+charSet.charAt(char2)+charSet.charAt(char3));
}
}
}

Categories