The value of length when replacing space with %20 - java

I am working on a problem of replacing spaces with %20 from Cracking the Coding Interview 5th edition:
Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space at the end of the string to hold the additional characters, and that you are given the "true" length of the string. (Note: if implementing in Java, please use a character array so that you can perform this operation in place)
The algorithm I have is:
public static void replaceSpaces(String input, int length) {
char[] str = input.toCharArray();
int spaceCount = 0;
for(int i = length - 1; i >= 0; i--){
if(str[i] == ' ') {
spaceCount++;
}
}
int newLength = length + spaceCount * 2;
str[newLength] = '\0';
for(int i = length - 1; i >= 0; i--) {
if(str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
System.out.println(str);
} else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
System.out.println(str);
}
}
}
Printing out each step of the function, here are my outputs:
Mr John Smith h
Mr John Smith th
Mr John Smith ith
Mr John Smithmith
Mr John SmitSmith
Mr John S%20Smith
Mr John n%20Smith
Mr Johnhn%20Smith
Mr Johohn%20Smith
Mr JoJohn%20Smith
Mr%20John%20Smith
Mr%20John%20Smith
Mr%20John%20Smith
I have two questions:
We know the new length of the string is 17. What I do not understand is, why we need to have [newLength - 1] instead of [newLength]. We are interested in replacing the current index, no? Or is it because the new length is 17, but when converted to indices, it's actually 16 (0th index).
What is the purpose of: str[newLength] = '\0';

We don't all have that book, but from a pending edit, I see that the exact question is:
Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space at the end of the string to hold the additional characters, and that you are given the "true" length of the string. (Note: if implementing in Java, please use a character array so that you can perform this operation in place)
From Cracking the Coding Interview 5th edition
So, it says that your input argument should be a char[].
Since you're changing the length of the text, your method would need to return the new length.
Question 1:
We know the new length of the string is 17. What I do not understand is, why we need to have [newLength - 1] instead of [newLength]. We are interested in replacing the current index, no? Or is it because the new length is 17, but when converted to indices, it's actually 16 (0th index).
You answered it yourself. With a length of 17, the indices are 0 to 16. If the array is only 17 long, accessing index 17 with throw an IndexOutOfBoundsException.
Question 2:
What is the purpose of: str[newLength] = '\0';
None whatsoever. It's is invalid and has no purpose in Java. Remove it.
Java Strings have a length(). In C, strings are zero-terminated, but not in Java.
To test the code, try running it with this:
char[] buffer = { 'M','r',' ','J','o','h','n',' ','S','m','i','t','h','*','*','*','*' };
int inLen = 13;
System.out.println("buffer: '" + new String(buffer) + "'");
System.out.println("inLen : " + inLen);
System.out.println("input : '" + new String(buffer, 0, inLen) + "'");
int outLen = replaceSpaces(buffer, inLen);
System.out.println("outLen: " + outLen);
System.out.println("result: '" + new String(buffer, 0, outLen) + "'");
Output should be:
buffer: 'Mr John Smith****'
inLen : 13
input : 'Mr John Smith'
outLen: 17
result: 'Mr%20John%20Smith'
Accessing input[17] in the method would throw IndexOutOfBoundsException.
Here is one possible implementation based on the shown code, that follows the quoted text, and stop processing once all spaces are replaced.
public static int replaceSpaces(char[] str, int length) {
int spaceCount = 0;
for (int i = length - 1; i >= 0; i--)
if (str[i] == ' ')
spaceCount++;
int shift = spaceCount * 2;
int newLength = length + shift;
for (int i = newLength - 1; shift > 0; i--) {
char c = str[i - shift];
if (c != ' ') {
str[i] = c;
} else {
str[i] = '0';
str[--i] = '2';
str[--i] = '%';
shift -= 2;
}
}
return newLength;
}
This produces the expected output from the test code above.

Code posted below works good. Cheers.
Sample Output
package StringAndArray;
public class Question_Four_Replace_Spaces {
public static void main(String[] args) {
String string = "Mr Shubham Dilip Yeole";
char[] array = string.toCharArray();
System.out.println("\n\nInput : " +string);
System.out.println("\n\nResult: "+method_1(array,string.length()));
method_1(array,string.length());
}
private static String method_1(char[] array, int length) {
int spaceCount = 0;
for(int i=0; i<array.length; i++){
if(array[i]==' ') spaceCount++;
}
int count = 0;
int newLength = length + spaceCount*2;
char[] newArray = new char[newLength];
for(int i= 0; i<array.length; i++){
if(array[i]==' '){
newArray[count++] = '%';
newArray[count++] = '2';
newArray[count++] = '0';
}else{
newArray[count] = array[i];
count++;
}
}
String newString1 = new String(newArray);
return newString1;
}
}

I believe that your direct questions have been answered in the comments, so here instead I will focus on issues with the method as written.
Ignoring the fact that this functionality already exists in the base String class (and many other 3rd party string utility classes), we can still write a basic string replacement function. The function as written in the question does not appear to be written for Java, and does not return any value, which since Strings are immutable means that the function cannot possibly be fulfilling its name.
Instead, we need to create a new array which we copy the existing characters to while replacing any spaces we encounter with %20. We then return this array as a new String. Conveniently, Java has a class which encapsulates a variable size array of characters that we can use to assemble our new String called StringBuilder.
So a simpler and working (but not optimized) replacement function in Java may look like:
public static String replaceSpaces(String input)
{
if (input == null) return null;
// New string builder with some padding to account for replacements...
// Padding was chosen pretty arbitrarily, there are certainly better values.
StringBuilder builder = new StringBuilder(input.length() + 128);
for (int i = 0; i < input.length(); i++)
{
char c = input.chatAt(i);
if (c == ' ') {
builder.append("%20");
} else {
builder.append(c);
}
}
return builder.toString();
}
It may be more optimal to convert the entire String to a char[] at the beginning, and iterate over the array instead of using String.charAt(i). And we could probably choose a more appropriate padding for the StringBuilder by multiplying the length of the existing string by some constant based on the expected number of spaces. For very large strings it could even make sense to first count the number of spaces before declaring our array, but those optimizations are left as an exercise for the reader.

#Test public void replaceTest() {
String s = "Mr John Smith ";
char[] chars = s.toCharArray();
int length = 13;
char[] chars1 = subString(chars, length);
//actualString = actualString.replace(" ", "%20");
Assert.assertEquals(replace(chars1, "%20"), "Mr%20John%20Smith");
}
private char[] subString(char[] chars, int length) {
char[] newChar = new char[length];
for (int i = 0; i < length; i++) {
newChar[i] = chars[i];
}
return newChar;
}
private String replace(char[] chars, String s) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ' ') {
builder.append(s);
} else {
builder.append(chars[i]);
}
}
return builder.toString();
}

public static String urlify(String s1, int truelength) {
int countspaces = 0;
char[] charobj = s1.toCharArray();
for (int i = truelength - 1; i < charobj.length; i++) {
if (charobj[i] == ' ') {
countspaces++;
}
}
for (int i = truelength - 1; i >= 0; i--) {
if (charobj[i] == ' ' && countspaces != 0) {
for (int j = truelength - 1; j > i; j--) {
char temp = charobj[j];
charobj[j + 2] = temp;
}
countspaces = countspaces - 2;
charobj[i] = '%';
charobj[i + 1] = '2';
charobj[i + 2] = '0';
truelength = truelength + 2;
}
}
return String.valueOf(charobj);
}

Related

How to compare without getting negative value when char is a space

Beginner here, We were assigned an assignment to find common consonants in two different strings. This code works perfectly if there is no space in the input but in this assignment we are taking inputs from our user and they are first and last names. If there is no space I get correct value of common characters but when there is a space in between first and last names it will give me an index out of bounds error because the space makes it a negative number. Any help would be nice thank you.
public static int commonCharacters(String string1, String string2) {
final int alphabetLength = 26;
int count = 0;
int[] counting1 = new int[alphabetLength];
int[] counting2 = new int[alphabetLength];
Arrays.fill(counting1, 0);
Arrays.fill(counting2, 0);
for (char c : string1.toCharArray()) {
c = Character.toLowerCase(c);
counting1[c - 'a']++;
}
for (char c : string2.toCharArray()) {
c = Character.toLowerCase(c);
counting2[c - 'a']++;
}
for(int i = 0; i < alphabetLength; i++) {
System.out.printf(String.valueOf(counting1[i]),counting2[i]);
count += Math.min(counting1[i], counting2[i]);
}
return count == 0 ? 1 :count;
}
}
you can trim space at the end of string string1 = string1.trim();
Here is some changes to your code. You just need if statement to check if the character is an alphabet. You do not need Arrays.fill because in Java array values are initialized to zero.
You wrote the assignment is about calculating consonants but your code calculates all common alphabets.
public static int commonCharacters(String string1, String string2) {
final int alphabetLength = 26;
int count = 0;
string1 = string1.toLowerCase();
string2 = string2.toLowerCase();
int[] counting1 = new int[alphabetLength];
int[] counting2 = new int[alphabetLength];
for (char c : string1.toCharArray()) {
if (c < 'a' || c > 'z') {
continue;
}
counting1[c - 'a']++;
}
for (char c : string2.toCharArray()) {
if (c < 'a' || c > 'z') {
continue;
}
counting2[c - 'a']++;
}
for(int i = 0; i < alphabetLength; i++) {
System.out.printf("%c %d %d%n", 'a' + i, counting1[i], counting2[i]);
count += Math.min(counting1[i], counting2[i]);
}
return count;
}

Efficient way to find longest streak of characters in string

This code works fine but I'm looking for a way to optimize it. If you look at the long string, you can see 'l' appears five times consecutively. No other character appears this many times consecutively. So, the output is 5. Now, the problem is this method checks each and every character and even after the max is found, it continues to check the remaining characters. Is there a more efficient way?
public class Main {
public static void main(String[] args) {
System.out.println(longestStreak("KDDiiigllllldddfnnlleeezzeddd"));
}
private static int longestStreak(String str) {
int max = 0;
for (int i = 0; i < str.length(); i++) {
int count = 0;
for (int j = i; j < str.length(); j++) {
if (str.charAt(i) == str.charAt(j)) {
count++;
} else break;
}
if (count > max) max = count;
}
return max;
}
}
We could add variable for previous char count in single iteration. Also as an additional optimisation we stop iteration if i + max - currentLenght < str.length(). It means that max can not be changed:
private static int longestStreak(String str) {
int maxLenght = 0;
int currentLenght = 1;
char prev = str.charAt(0);
for (int index = 1; index < str.length() && isMaxCanBeChanged(str, maxLenght, currentLenght, index); index++) {
char currentChar = str.charAt(index);
if (currentChar == prev) {
currentLenght++;
} else {
maxLenght = Math.max(maxLenght, currentLenght);
currentLenght = 1;
}
prev = currentChar;
}
return Math.max(maxLenght, currentLenght);
}
private static boolean isMaxCanBeChanged(String str, int max, int currentLenght, int index) {
return index + max - currentLenght < str.length();
}
Here is a regex magic solution, which although a bit brute force perhaps gets some brownie points. We can iterate starting with the number of characters in the original input, decreasing by one at a time, trying to do a regex replacement of continuous characters of that length. If the replacement works, then we know we found the longest streak.
String input = "KDDiiigllllldddfnnlleeezzeddd";
for (int i=input.length(); i > 0; --i) {
String replace = input.replaceAll(".*?(.)(\\1{" + (i-1) + "}).*", "$1");
if (replace.length() != input.length()) {
System.out.println("longest streak is: " + replace);
}
}
This prints:
longest streak is: lllll
Yes there is. C++ code:
string str = "KDDiiigllllldddfnnlleeezzeddd";
int longest_streak = 1, current_streak = 1; char longest_letter = str[0];
for (int i = 1; i < str.size(); ++i) {
if (str[i] == str[i - 1])
current_streak++;
else current_streak = 1;
if (current_streak > longest_streak) {
longest_streak = current_streak;
longest_letter = str[i];
}
}
cout << "The longest streak is: " << longest_streak << " and the character is: " << longest_letter << "\n";
LE: If needed, I can provide the Java code for it, but I think you get the idea.
public class Main {
public static void main(String[] args) {
System.out.println(longestStreak("KDDiiigllllldddfnnlleeezzeddd"));
}
private static int longestStreak(String str) {
int longest_streak = 1, current_streak = 1; char longest_letter = str.charAt(0);
for (int i = 1; i < str.length(); ++i) {
if (str.charAt(i) == str.charAt(i - 1))
current_streak++;
else current_streak = 1;
if (current_streak > longest_streak) {
longest_streak = current_streak;
longest_letter = str.charAt(i);
}
}
return longest_streak;
}
}
The loop could be rewritten a bit smaller, but mainly the condition can be optimized:
i < str.length() - max
Using Stream and collector. It should give all highest repeated elements.
Code:
String lineString = "KDDiiiiiiigllllldddfnnlleeezzeddd";
String[] lineSplit = lineString.split("");
Map<String, Integer> collect = Arrays.stream(lineSplit)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
int maxValueInMap = (Collections.max(collect.values()));
for (Entry<String, Integer> entry : collect.entrySet()) {
if (entry.getValue() == maxValueInMap) {
System.out.printf("Character: %s, Repetition: %d\n", entry.getKey(), entry.getValue());
}
}
Output:
Character: i, Repetition: 7
Character: l, Repetition: 7
P.S I am not sure how efficient this code it. I just learned Streams.

Most efficient way to search for unknown patterns in a string?

I am trying to find patterns that:
occur more than once
are more than 1 character long
are not substrings of any other known pattern
without knowing any of the patterns that might occur.
For example:
The string "the boy fell by the bell" would return 'ell', 'the b', 'y '.
The string "the boy fell by the bell, the boy fell by the bell" would return 'the boy fell by the bell'.
Using double for-loops, it can be brute forced very inefficiently:
ArrayList<String> patternsList = new ArrayList<>();
int length = string.length();
for (int i = 0; i < length; i++) {
int limit = (length - i) / 2;
for (int j = limit; j >= 1; j--) {
int candidateEndIndex = i + j;
String candidate = string.substring(i, candidateEndIndex);
if(candidate.length() <= 1) {
continue;
}
if (string.substring(candidateEndIndex).contains(candidate)) {
boolean notASubpattern = true;
for (String pattern : patternsList) {
if (pattern.contains(candidate)) {
notASubpattern = false;
break;
}
}
if (notASubpattern) {
patternsList.add(candidate);
}
}
}
}
However, this is incredibly slow when searching large strings with tons of patterns.
You can build a suffix tree for your string in linear time:
https://en.wikipedia.org/wiki/Suffix_tree
The patterns you are looking for are the strings corresponding to internal nodes that have only leaf children.
You could use n-grams to find patterns in a string. It would take O(n) time to scan the string for n-grams. When you find a substring by using a n-gram, put it into a hash table with a count of how many times that substring was found in the string. When you're done searching for n-grams in the string, search the hash table for counts greater than 1 to find recurring patterns in the string.
For example, in the string "the boy fell by the bell, the boy fell by the bell" using a 6-gram will find the substring "the boy fell by the bell". A hash table entry with that substring will have a count of 2 because it occurred twice in the string. Varying the number of words in the n-gram will help you discover different patterns in the string.
Dictionary<string, int>dict = new Dictionary<string, int>();
int count = 0;
int ngramcount = 6;
string substring = "";
// Add entries to the hash table
while (count < str.length) {
// copy the words into the substring
int i = 0;
substring = "";
while (ngramcount > 0 && count < str.length) {
substring[i] = str[count];
if (str[i] == ' ')
ngramcount--;
i++;
count++;
}
ngramcount = 6;
substring.Trim(); // get rid of the last blank in the substring
// Update the dictionary (hash table) with the substring
if (dict.Contains(substring)) { // substring is already in hash table so increment the count
int hashCount = dict[substring];
hashCount++;
dict[substring] = hashCount;
}
else
dict[substring] = 1;
}
// Find the most commonly occurrring pattern in the string
// by searching the hash table for the greatest count.
int maxCount = 0;
string mostCommonPattern = "";
foreach (KeyValuePair<string, int> pair in dict) {
if (pair.Value > maxCount) {
maxCount = pair.Value;
mostCommonPattern = pair.Key;
}
}
I've written this just for fun. I hope I have understood the problem correctly, this is valid and fast enough; if not, please be easy on me :) I might optimize it a little more I guess, if someone finds it useful.
private static IEnumerable<string> getPatterns(string txt)
{
char[] arr = txt.ToArray();
BitArray ba = new BitArray(arr.Length);
for (int shingle = getMaxShingleSize(arr); shingle >= 2; shingle--)
{
char[] arr1 = new char[shingle];
int[] indexes = new int[shingle];
HashSet<int> hs = new HashSet<int>();
Dictionary<int, int[]> dic = new Dictionary<int, int[]>();
for (int i = 0, count = arr.Length - shingle; i <= count; i++)
{
for (int j = 0; j < shingle; j++)
{
int index = i + j;
arr1[j] = arr[index];
indexes[j] = index;
}
int h = getHashCode(arr1);
if (hs.Add(h))
{
int[] indexes1 = new int[indexes.Length];
Buffer.BlockCopy(indexes, 0, indexes1, 0, indexes.Length * sizeof(int));
dic.Add(h, indexes1);
}
else
{
bool exists = false;
foreach (int index in indexes)
if (ba.Get(index))
{
exists = true;
break;
}
if (!exists)
{
int[] indexes1 = dic[h];
if (indexes1 != null)
foreach (int index in indexes1)
if (ba.Get(index))
{
exists = true;
break;
}
}
if (!exists)
{
foreach (int index in indexes)
ba.Set(index, true);
int[] indexes1 = dic[h];
if (indexes1 != null)
foreach (int index in indexes1)
ba.Set(index, true);
dic[h] = null;
yield return new string(arr1);
}
}
}
}
}
private static int getMaxShingleSize(char[] arr)
{
for (int shingle = 2; shingle <= arr.Length / 2 + 1; shingle++)
{
char[] arr1 = new char[shingle];
HashSet<int> hs = new HashSet<int>();
bool noPattern = true;
for (int i = 0, count = arr.Length - shingle; i <= count; i++)
{
for (int j = 0; j < shingle; j++)
arr1[j] = arr[i + j];
int h = getHashCode(arr1);
if (!hs.Add(h))
{
noPattern = false;
break;
}
}
if (noPattern)
return shingle - 1;
}
return -1;
}
private static int getHashCode(char[] arr)
{
unchecked
{
int hash = (int)2166136261;
foreach (char c in arr)
hash = (hash * 16777619) ^ c.GetHashCode();
return hash;
}
}
Edit
My previous code has serious problems. This one is better:
private static IEnumerable<string> getPatterns(string txt)
{
Dictionary<int, int> dicIndexSize = new Dictionary<int, int>();
for (int shingle = 2, count0 = txt.Length / 2 + 1; shingle <= count0; shingle++)
{
Dictionary<string, int> dic = new Dictionary<string, int>();
bool patternExists = false;
for (int i = 0, count = txt.Length - shingle; i <= count; i++)
{
string sub = txt.Substring(i, shingle);
if (!dic.ContainsKey(sub))
dic.Add(sub, i);
else
{
patternExists = true;
int index0 = dic[sub];
if (index0 >= 0)
{
dicIndexSize[index0] = shingle;
dic[sub] = -1;
}
}
}
if (!patternExists)
break;
}
List<int> lst = dicIndexSize.Keys.ToList();
lst.Sort((a, b) => dicIndexSize[b].CompareTo(dicIndexSize[a]));
BitArray ba = new BitArray(txt.Length);
foreach (int i in lst)
{
bool ok = true;
int len = dicIndexSize[i];
for (int j = i, max = i + len; j < max; j++)
{
if (ok) ok = !ba.Get(j);
ba.Set(j, true);
}
if (ok)
yield return txt.Substring(i, len);
}
}
Text in this book took 3.4sec in my computer.
Suffix arrays are the right idea, but there's a non-trivial piece missing, namely, identifying what are known in the literature as "supermaximal repeats". Here's a GitHub repo with working code: https://github.com/eisenstatdavid/commonsub . Suffix array construction uses the SAIS library, vendored in as a submodule. The supermaximal repeats are found using a corrected version of the pseudocode from findsmaxr in Efficient repeat finding via suffix arrays
(Becher–Deymonnaz–Heiber).
static void FindRepeatedStrings(void) {
// findsmaxr from https://arxiv.org/pdf/1304.0528.pdf
printf("[");
bool needComma = false;
int up = -1;
for (int i = 1; i < Len; i++) {
if (LongCommPre[i - 1] < LongCommPre[i]) {
up = i;
continue;
}
if (LongCommPre[i - 1] == LongCommPre[i] || up < 0) continue;
for (int k = up - 1; k < i; k++) {
if (SufArr[k] == 0) continue;
unsigned char c = Buf[SufArr[k] - 1];
if (Set[c] == i) goto skip;
Set[c] = i;
}
if (needComma) {
printf("\n,");
}
printf("\"");
for (int j = 0; j < LongCommPre[up]; j++) {
unsigned char c = Buf[SufArr[up] + j];
if (iscntrl(c)) {
printf("\\u%.4x", c);
} else if (c == '\"' || c == '\\') {
printf("\\%c", c);
} else {
printf("%c", c);
}
}
printf("\"");
needComma = true;
skip:
up = -1;
}
printf("\n]\n");
}
Here's a sample output on the text of the first paragraph:
Davids-MBP:commonsub eisen$ ./repsub input
["\u000a"
," S"
," as "
," co"
," ide"
," in "
," li"
," n"
," p"
," the "
," us"
," ve"
," w"
,"\""
,"–"
,"("
,")"
,". "
,"0"
,"He"
,"Suffix array"
,"`"
,"a su"
,"at "
,"code"
,"com"
,"ct"
,"do"
,"e f"
,"ec"
,"ed "
,"ei"
,"ent"
,"ere's a "
,"find"
,"her"
,"https://"
,"ib"
,"ie"
,"ing "
,"ion "
,"is"
,"ith"
,"iv"
,"k"
,"mon"
,"na"
,"no"
,"nst"
,"ons"
,"or"
,"pdf"
,"ri"
,"s are "
,"se"
,"sing"
,"sub"
,"supermaximal repeats"
,"te"
,"ti"
,"tr"
,"ub "
,"uffix arrays"
,"via"
,"y, "
]
I would use Knuth–Morris–Pratt algorithm (linear time complexity O(n)) to find substrings. I would try to find the largest substring pattern, remove it from the input string and try to find the second largest and so on. I would do something like this:
string pattern = input.substring(0,lenght/2);
string toMatchString = input.substring(pattern.length, input.lenght - 1);
List<string> matches = new List<string>();
while(pattern.lenght > 0)
{
int index = KMP(pattern, toMatchString);
if(index > 0)
{
matches.Add(pattern);
// remove the matched pattern occurences from the input string
// I would do something like this:
// 0 to pattern.lenght gets removed
// check for all occurences of pattern in toMatchString and remove them
// get the remaing shrinked input, reassign values for pattern & toMatchString
// keep looking for the next largest substring
}
else
{
pattern = input.substring(0, pattern.lenght - 1);
toMatchString = input.substring(pattern.length, input.lenght - 1);
}
}
Where KMP implements Knuth–Morris–Pratt algorithm. You can find the Java implementations of it at Github or Princeton or write it yourself.
PS: I don't code in Java and it is quick try to my first bounty about to close soon. So please don't give me the stick if I missed something trivial or made a +/-1 error.

Counting number of times a letter occurs in a string without using libraries

My professor says I can't use libraries and stuff. I have my code with libraries:
String phrase = keyboard.nextLine(); //Input.
int addr = phrase.length();
Map<Character, Integer> numChars = new HashMap<Character, Integer>(Math.min(addr, 26)); //there are 26 character in our alphabet. It makes a map and maps our the characters.
for (int i = 0; i < addr; ++i)//this area reads the string then, tells how many times each character appeared. Loops for each chracter.
{
char charAt = phrase.charAt(i);
if (!numChars.containsKey(charAt))
{
numChars.put(charAt, 1);
}
else if (numChars.containsKey(charAt))
{
numChars.put(charAt, 0);
}
else
{
numChars.put(charAt, numChars.get(charAt) + 1);
}
}
System.out.println(phrase);//outputs phrase written by user.
System.out.println(numChars);//outputs results of the code above
// this code reads which one appeared the most.
int FreqChar = 0;
char frequentCh = ' ';
for (int f = 0; f < phrase.length(); f++)
{
char poop = phrase.charAt(f);
int banana = 0;
for (int j = phrase.indexOf(poop); j != -1; j = phrase.indexOf(poop, j + 1))
{
frequentCh++;
}
if (banana > FreqChar)
{
FreqChar = banana;*/
Here is my program without the libraries so far. I need help translating this into arrays.
import java.util.*;
public class LetCount
{
public static final int NUMCHARS = 26; //26 chars in alphabet.
// int addr(char ch) returns the equivalent integer address for the letter
// given in ch, 'A' returns 1, 'Z' returns 26 and all other letters return
// their corresponding position as well. felt this is important.
public static int addr(char ch)
{
return (int) ch - (int) 'A' + 1;
}
// Required method definitions for (1) analyzing each character in an input
// line to update the appropriate count; (2) determining most frequent letter;
// (3) determining least frequent letter; and (4) printing final results
// should be defined here.
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in); // for reading input
int[] count = new int [NUMCHARS]; // count of characters
String phrase = keyboard.nextLine(); //Input.
int addr = phrase.length();
for(char ch = 'A'; ch <= 'Z'; ch++)
{
}
}
This is easier to put here than in comments, but it's not really an answer :)
You've got a great start - rather than going through the letters and finding matches, go through the string and increment your letter counter each time you encounter a letter (yeah, that sounds weird in my head too).
Convert the string to lower or upper case first, you only need to count the letter, not whether it's lower or upper based upon your existing code.
If you just have to count all the alphabets in a given String and store it in an array, try this:
String str = phrase.toUpperCase();
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int charPositionInArray = c - 'A';
if(charPositionInArray < 26){
count[charPositionInArray] += 1;
}
}
Also, the index of an array starts from 0, so I assume you want the count for 'A' to be stored in count[0], i.e., the first position in the array.
Also, this code does nothing for any character that is not an alphabet.

I'm curious how i would grab a char that is the smallest/biggest out of the rest in said string without using ARRAYS

I'm just having a hard time grasping this concept.
each char has a different ASCII value, so how do i grab the lowest value or the highest value?
and if i passed an empty string to my method for all of this min() would just get thrown an error or would it return a 0?
i wrote a test driver that should pass if my min method returns w as the minimum, which is just a stub method right now, character in that string.
final String PASS = "Pass";
final String FAIL = "Fail";
L05A lab5 = new L05A();
int testNum = 1;
String tst = ""; // test empty string
String result = FAIL;
System.out.println("\nTesting min\n");
tst = "";
char ch = lab5.min(tst);
result = (ch == '!') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
tst = "zyxw"; //would return w?
ch = lab5.min(tst);
result = (ch == 'w') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
So how would i scan that string i pass to return the smallest char?
At first i thought i could use str.charAt(0); but silly me, that just returns the first index of the string, so i'm very confused! Any help would be great to develop this min method
I SHOULD SPECIFY THAT WE ARE NOT USING ANY FORM OF ARRAYS[] ON THIS ASSIGNMENT
UNFORTUNATELY.. :(
It's pretty simple:
Convert the string to a char array using String.toCharArray
Convert the array to a Collection<Character>
Pass the collection to Collections.min and max from java.util.Collections
For example:
String test = "test";
List<Character> strArr = new ArrayList<Character>(test.length());
for (char c : test.toCharArray()) strArr.add(c);
System.out.println(Collections.min(strArr)); // prints "e"
EDIT Ok, so now you say you can't use Arrays, so you just do this instead:
String test = "test";
char[] chars = test.toCharArray();
char max = Character.MIN_VALUE;
char min = Character.MAX_VALUE;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
max = max > c ? max : c;
min = min < c ? min : c;
}
System.out.println(min);
And, finally, if you can't use an array (like char[]) then you just drop the toCharArray call, and start the loop like this:
for (int i = 0; i < test.length(); i++) {
char c = test.charAt(i);
get char array out of string
iterate over it
define temp int variable assign to 0
compare ASCII of char to temp var and assign temp var to ascii if temp var is smaller/bigger(based on min max value you need from that function)
once the loop is over, you have what you want in that temp var
You should sort the array first:
Arrays.sort(arr);
Then your minimum value will be its first element:
int minimum = arr[0];
Do note that Arrays.sort does sorting in-place and returns nothing.
I expect there is a utility class which will do this for you, but what you could do is call toCharArray on the string, iterate over the array it returns and look for the smallest char (char is effectively a number so comparisons like < > <= >= etc will work on it)
edit:
String foo = "ksbvs";
final char[] chars = foo.toCharArray();
// create a variable to bung the smallest char in
// iterate over the array chars
// compare the current char to the smallest char you have seen so far, update if it's smaller
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts"; // The String under test
int maxASCII = 0; // As minimum value for a character in ASCII is 0.
int minACSII = 255; // As maximum value for a character in ASCII is 255
int stringLength = slogan.length();
for(int i =0; i < stringLength; i++) {
int tempASCII = slogan.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
else if (tempASCII < minACSII)
minACSII = tempASCII;
}
System.out.println("Max : " + maxASCII + " MIN : " + minACSII);
char maxChar = (char)maxASCII;
char minChar = (char) minACSII;
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
}
OUTPUT :
Max : 118 MIN : 32
MaxChar : v MinChar : (blank space)
EDIT : As per your Query, If you want to test only for max or min valued char then you can use this.
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts";
char maxChar = (char)getMaxChar(slogan);
char minChar = (char)getMinChar(slogan);
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
private static int getMaxChar(String testString) {
int maxASCII = 0;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
}
return maxASCII;
}
private static int getMinChar(String testString) {
int minASCII = 255;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII < minASCII)
minASCII = tempASCII;
}
return minASCII;
}
}

Categories

Resources