Having trouble with for loops - java

So, I need to write a program using loops that takes a string and counts what and how many letters appear in that string. (string "better butter" would print "b appears 2 times, e appears 3 times, ' '(space) appears 1 time, and so on). While I understand the idea and concept behind this assignment, actually pulling it off has been rough.
My nested for loop is where the problems are coming from, I assume. What I've written only loops once (i think) and just shows the first character and says there's only one of that character.
Edit: Preferably without using Map or arrays. I'm fine with using them if it's the only way, but they've not been covered in my class so I'm trying to avoid them. Every other similar question to this (that I've found) uses Map or array.
import java.util.Scanner;
class myString{
String s;
myString() {
s = "";
}
void setMyString(String s) {
this.s = s;
}
String getMyString() {
return s;
}
String countChar(String s){
s = s.toUpperCase();
int cnt = 0;
char c = s.charAt(cnt);
for (int i = 0; i <= s.length(); i++)
for (int j = 0; j <= s.length(); j++) //problem child here
c = s.charAt(cnt);
cnt++;
if (cnt == 1)
System.out.println(c+" appears "+cnt+" time in "+s);
else
System.out.println(c+" appears "+cnt+" times in "+s);
return "for"; //this is here to prevent complaint from the below end bracket.
}
}
public class RepeatedCharacters {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s;
System.out.println("Enter a sentence: ");
s = in.nextLine();
myString myS = new myString();
// System.out.println(myS.getMyString());
// System.out.println(myS.countChar());
myS.countChar(s);
}
}

First you will need to scan the entire string and store the
counts of each characters. Later you can just print the counts.
Algorithm 1:
Use a HashMap to store the character as key and its count as value. (If you are new to Java, you might want to read up on
HashMaps.)
Every time you read a character in your for loop, check if it present in the HashMap. If yes, then increment the count by 1. Else
add a new characters to the map with count 1.
Printing:
Just iterate on your HashMap and print out the character and
their respective counts.
Issue with your code: You are trying to print the count as soon as you
read a character. But the character might appear again later in the
string. So you need to keep track of the characters you have already
read.
Algorithm 2:
String countChar(String s){
has_processed = []
for i = 0 to n
cnt = 0
if s.charAt(i) has been processed
continue;
for j = i+1 to n
if (s.charAt(i) == s.charAt(j))
cnt++
add s.charAt(i) to has_processed array
print the count of s.charAt(i)
}

Use a frequency array to get an answer in linear time.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "better butter";
int freq[] = new int[26];
int i;
for (i = 0; i < s.length(); i++) {
if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z')
freq[s.charAt(i)-'a']++;
}
for (i = 0; i < freq.length; i++) {
if (freq[i] == 0) continue;
System.out.println((char)(i+'a') + " appears " + freq[i] + " times" );
}
}
}
Ideone Link
Note that this can be expanded to include uppercase letters, but for demonstrative purposes, only lowercase letters are handled in the above code.
EDIT: While the OP did ask if it was possible to do this without an array, I would recommend against such. That solution would have terrible time complexity and repeat character counts (unless an array is used to keep track of seen characters, which is counter to the aim). Thus, the above solution is the best way to do it in a reasonable amount of time (linear) with limited space consumption.

I would do the following. Create a HashMap which keeps track of which unique characters are in the string and the count for each character.
You only need to iterate over the string once, and put each character into the HashMap. if the characer is in the map, icrement the integer count in the map, else add 1 to the map for that character. Print out the map with toString() to get the result. The whole thing can be done in about 4 lines of code.

The only thing being done in your nested for loop with the following
c = s.charAt(cnt)
is setting the c char to the value of the first letter (i.e. index 0 of the string) over and over and over until you've looped through the string n^2 times. In other words, you're not incrementing your cnt counter within the for loops at all.

Suggestion: try to use meaningful names for your variables; it will help you a lot in your career. Also class names should always start with a capital letter.
Although it is not the quickest solution in terms of performance, the most simple solution should be:
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
Source: Most efficient way to increment a Map value in Java
Please next time use the search function before posting a new question.

Here is my version of countChar(String s)
boolean countChar(String s) {
if(s==null) return false;
s = s.toUpperCase();
//view[x] will means that the characted in position x has been just read
boolean[] view = new boolean[s.length()];
/*
The main idea is:
foreach character c = s.charAt(x) in the string s, I have a boolean value view[x] which say if I have already examinated c.
If c has not been examinated yet, I search for other characters equals to c in the rest of the string.
When I found other characters equals to c, I mark it as view and I increment count with count++.
*/
for (int i = 0; i < s.length(); i++) {
if (!view[i]) {
char tmp = s.charAt(i);
int count = 0;
for (int j = i; j < s.length(); j++) {
if (!view[j] && s.charAt(j) == tmp) {
count++;
view[j] = true;
}
}
System.out.println("There were " + count + " " + tmp);
}
}
return true;
}
It should work, excuse me for my English because I'm italian

Related

Count the numbers of numeric value in a given string

Java program to accept a string and count total numeric values.
public class Test2{
public static void main(String[] args){
String str = "I was 2 years old in 2002";
int count = 0, i;
for(i = 0; i < str.length(); i++){
if(str.charAt(i) >= 48 && str.charAt(i) <= 57){
count++;
// while(str.charAt(i) >= 48 && str.charAt(i) <= 57)
// i++;
}
}
System.out.println("Output: " +count);
}
}
Output = 5
After uncommenting the two lines written inside while loop -
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 25
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:712)
at Test2.main(Test2.java:9)
The output should be 2, because there are two numeric values - 2 and 2002
I have commented on the two lines in the above code, after uncommenting the code, the same logic works perfectly in C++.
An alternative to #DarkMatterĀ“s answer using Pattern:
public static void main(String[] args) {
String str = "I was 2 years old in 2002";
long count = Pattern.compile("\\d+").matcher(str).results().count();
System.out.println(count);
}
You are checking individual charters so it counts every digit (as you probably realize). Java String has some nice tools to help you here. You could split the line into words and check each against a regular expression using String.matches():
String str = "I was 2 years old in 2002";
int count = 0;
for(String s : str.split(" ")) {
if(s.matches("[0-9]*")) {
count++;
}
}
System.out.println(count);
You can do the same thing (almost) with a stream:
String str = "I was 2 years old in 2002";
long count = Arrays.stream(str.split(" "))
.filter(s -> s.matches("[0-9]*")).count();
System.out.println(count);
In C, strings end in an ASCII NUL character (well, in basic C, strings don't exist, it's a library bolt-on, but most bolt-ons have NUL terminated strings). In java, that's not how it works.
The reason that your code is not working in java, but it is in C, is that you just keep going until you hit a non-digit character in that inner while loop. That means if the string ends in a digit (which yours does), your code asks the string: Give me the character at (one position beyond its length). In C that works; that's ASCII NUL, and thus your inner loop ends, as that's not a digit.
In java it doesn't, because you can't ask for a character beyond the end of a string.
You can 'fix' your code as pasted by also adding a check that i is still below length: if (i < str.length() && str.charAt(i).... ).
As the other answers showed you, there are more java idiomatic ways to solve this problem too, and probably the strategies shown in the other answers is what your average java coder would most likely do if faced with this problem. But there's nothing particularly wrong with your C-esque solution, once you add the 'check length' fix.
below code will input String from user and return the number of occurrences of numeric values as count.
import java.util.Scanner;
public class NumberCountingString
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String str = in.nextLine();
int count = 0, i;
int size = str.length(); // will only get size once instead of using in loop which will always get size before comparing
for(i = 0; i < size; i++)
{
if(Character.isDigit(str.charAt(i))) //if char is digit count++
{
count++;
for (int j = i; j < size; ) //inner loop to check if next characters are also digits
{
if(Character.isDigit(str.charAt(j))) // if yes skip next char
{
i++;
j=i;
}
else{ //break inner loop
break;
}
}
}
}
System.out.println("Output: " +count);
}
}
There are many options in Java as already shared by others. Below is very similar to your existing code and gives your desired output:
public static void main(String[] args) {
String str = "I was 2 years old in 2002";
String[] splittedString = str.split(" ");
int count = 0, i;
for (i = 0; i < splittedString.length; i++) {
if (StringUtils.isNumeric(splittedString[i])) {
count++;
}
}
System.out.println("Output: " + count);
}
You can split this string into an array of words, then filter those words where codePoints of the characters match digits, i. e. allMatch (Character::isDigit), and count these words:
String str = "I was 2 years old in 2002";
long count = Arrays
// split string into an array of words
.stream(str.split("\\s+"))
// for each word check the code points of the
// characters, whether they are digits or not.
.filter(w -> w.codePoints()
.mapToObj(ch -> (char) ch)
.allMatch(Character::isDigit))
.count();
System.out.println(count); // 2
See also: Transform String to byte then to int

letter change, what am I doing wrong?

So im trying the following challenge:
Using the Java language, have the function LetterChanges(str) take the str parameter being passed andmodify it using the following algorithm. Replace every letter in the string with the letter following it in thealphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
This is my code
class LetterChange {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char currentChar,letter;
int i = 0;
while (i < str.length())
{
currentChar = str.charAt(i);
for(int x = 0; x < alphabet.length(); x++)
{
letter = alphabet.charAt(x);
if (currentChar == letter){
str = str.replace(currentChar,alphabet.charAt(x+1));
i++;
}
}
}
when I run it it is returning the last char in string +1 letter in alphabet. for example if i was to run "bcd" it returns "EEE". I dont understand why its replacing all chars with the result of the loop for the last char.
When you go through the loop the first time you get
"bcd"--> "ccd"
Now, str.replace will turn this into "ddd" on next turn, then "EEE".
I.e., replace replaces every occurrence on each turn.
It is true that debugging it in the IDE will help you in the future!
Also, what if you had a lowercase vowel in your string?
public class Alphabet {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char[] string = str.toLowerCase().toCharArray();
for (int i=0; i < string.length; i++) {
char d = alphabet.charAt(((alphabet.toLowerCase().indexOf(string[i]))+1) % 26);
string[i]=d;
}
return new String(string);
}
public static void main(String[] args) {
System.out.println(Alphabet.LetterChanges("aabb"));
}
}
alphabet.charAt(
((alphabet.toLowerCase().indexOf(string[i]))
+1) % 26)
1) use toLowerCase on the input and your string map to eliminate case problems
2) find character at index+1 in string map 'alphabet', treating it as a circular buffer using a modulus that takes z to a.
index 25 (z) + 1 == 26 --> 0 (A) because 26 is 0 mod 26 while index 0(A) + 1 = 1 --> 1 mod 26. It is only necessary to wrap the z to A while not changing the other 25 indices and is more efficient than branching with an "if" statement.
Does this solution help?
public static String letterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
StringBuilder stringBuilder = new StringBuilder();
for (char letter : str.toCharArray()) {
if (alphabet.contains(Character.toString(letter))) {
int index = alphabet.indexOf(letter) + 1;
if (index >= 26) {
index = 0;
}
stringBuilder.append(alphabet.charAt(index));
}
}
return stringBuilder.toString();
}
The previous solution was hard to follow, so it's difficult to explain why it wasn't working without debugging through it to see where it goes wrong. It was easier to use a for-each loop to go through the str parameter and find matches using Java's provided methods like .indexOf and .charAt.
Also, Java uses lower camel case method naming, letterChanges instead of LetterChanges :)
Let me know if you have any questions.
You are getting that result because on every replacing you are re-setting the input string. I recommend you:
Better try with two different variables: Let the input variable be unmodified, and work on the output one.
Since strings are unmodifiable -as you already know- better declare them as arrays of char.
For the shake of optimization, base your algorithm on one single loop, which will iterate over the characters of the input string. For each character, decide if it is alphabetic or not, and in case it is, what character should it be replaced with.

How to count if a specific string matches while iterating through a loop in java?

This is for a past homework assignment that I wasn't able to complete in time. I am a new programmer struggling with this method of the program CharacterSearch. I'm stuck on which boolean logic to use for my if statement, as well as how to find matches in the phrase using the pre-defined character variable. And example test is: character = "x" , phrase = "Xerox". Whereas X and x are different. The expected output should be count = 1.
Edit: This problem should be answered without using arrays or lists.
/**
* Counts and returns the number of times the letter for this class
* occurs in the phrase. The class is case sensitive.
*/
public int letterCount(String phrase)
{
Scanner jf = new Scanner(phrase);
count = 0;
for (int i = phrase.length(); i > 0; i--)
{
jf.findInLine(character);
if(jf.hasNext())
{
count++;
jf.next();
}
}
return count;
}
There you go:
/**
* Counts and returns the number of times the letter for this class
* occurs in the phrase. The class is case sensitive.
*/
public int letterCount(String phrase)
{
int count = 0;
// for every character in phrase ...
for (int i = 0; i < phrase.length(); i++)
{
// ... if it is the right one ...
if(phrase.charAt(i) == character)
{
// ... increment the counter
count++;
}
}
return count;
}
You don't need any Scanner, and the code is fairly easy, readable and comprehensible.
Pretty much a duplicate of Simple way to count character occurrences in a string
I can't leave a comment yet because my rep is too low but I wanted to give you a solution you could use.
public int letterCount(String phrase)
{
count = 0;
for (int i = 0 ; i < phrase.length(); i++)
{
String myLetter = phrase.substring(i, i + 1);
if (myLetter.equals(character))
{
count++;
}
}
return count;
}
I figured out that I was iterating in the wrong direction, but more importantly I was not declaring a sub-string to check if my character matched the individual letters within the phrase.
Use String's substring with a compare().
public int letterCount(String phrase, String match)
{
int count = 0;
for(int i=0;i<phrase.length()-1;i++){ //-1 avoid out-of-bound exception
String letter = phrase.substring(i, i+1);
if(letter.compareTo(match) == 0){
count++;
}
}
return count;
}

Replace '1' with 'Q' and 'Q' with '1'. Char replacement in string. Java

Hi I need some help with my internship test task. I've read it a couple of times and I can't even say that I'm surely know what I need to do. So the task is:
You must generate a string of random length consisting of random ASCII characters. After that you need to replace all entries of '1' with 'Q' and 'Q' with '1' in it. To complete the task you are allowed to change one substring with another as many times as you want. For example as a result of changing "ww" -> "wert" the string "wwwwwQ" will become "wertwertwQ". Write a program which does required changes in the most optimal way (doing minimum amount of replacements).
I've already implemented string generation and i simply don't know what to do next. As said in the header, i need to do this using Java. Could you please offer me some way to solve this task?
As i said what i've already done is genString() which generates a char array for me and a replace() method which does what intended but it not uses substrings so it seems that this task should be done another way.
public static char[] genString()
{
int n = rand.nextInt(50) + 1;
char[] arr = new char[n];
for (int i = 0; i<n; i++)
{
arr[i] = (char)(rand.nextInt(95) + 33);
}
return arr;
}
public static void replace(char[] arr)
{
for (int i = 0; i < arr.length; i++)
{
arr[i] = (arr[i] == 'Q') ? '1'
: (arr[i] == '1' ) ? 'Q'
: arr[i];
}
}
What i actually don't understand is that how the substrings could be used there. I don't understand how going from "wwwwwQ" to "wertwertwQ" -like replacements will help me replace the 'Q' in it
To make the fewest replacements, I would use a stream-based approach:
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == 'Q') {
sb.setCharAt(i, '1');
} else if (str.charAt(i) == '1') {
sb.setCharAt(i, 'Q');
}
}
return sb.toString();
Using a StringBuilder make manipulating the string a lot more efficient, because a new string doesn't have to be created every time you change a letter.
well, try this code:
public String Replace(String theString, String first, String Second)
{
String result ="";
result=theString.replace(first, Second);
return result;
}
Example of using:
System.out.println(Replace("wwwwwQ", "ww", "wert"));// result will be: wertwertwQ
I hope it will help you, best regards

Efficient way to find Frequency of a character in a String in java : O(n)

In a recent interview I was asked to write the below program.
Find out the character whose frequency is minimum in the given String ?
So I tried by iterating through the string by using charAt and storing the character as key in a HashMap and the number of occurences as its value.
Now Again I have to iterate on the Map to find the lowest element.
Is there a more efficient way to do it as obviously the above one is too intensive i guess.
Update and Another Solution
After some thought process and answers I think the best time that this can be is O(n).
In the first iteration we will have to iterate through the String character by character and then store their frequency in an Array at the specific position(character is an int) and same time have two temporary variables which maintain the least count and the corresponding character.So when I go to the next character and store its frequency in arr[char] = arr[char]+1;At the same time I will check if the temp varible has a value greater than this value,if yes then the temp varible will be this value and also the char will be this one.In this way i suppose we dont need a second iteration to find the smallest and also no sorting is required I guess
.... Wat say ? Or any more solutions
I'd use an array rather than a hash map. If we're limited to ascii, that's just 256 entries; if we're using Unicode, 64k. Either way not an impossible size. Besides that, I don't see how you could improve on your approach. I'm trying to think of some clever trick to make it more efficient but I can't come up with any.
Seems to me the answer is almost always going to be a whole list of characters: all of those that are used zero times.
Update
This is probably clost to the most efficient it could be in Java. For convenience, I'm assuming we're using plain Ascii.
public List<Character> rarest(String s)
{
int[] freq=new int[256];
for (int p=s.length()-1;p>=0;--p)
{
char c=s.charAt(p);
if (c>255)
throw new UnexpectedDataException("Wasn't expecting that");
++freq[c];
}
int min=Integer.MAX_VALUE;
for (int x=freq.length-1;x>=0;--x)
{
// I'm assuming we don't want chars with frequency of zero
if (freq[x]>0 && min>freq[x])
min=freq[x];
}
List<Character> rares=new ArrayList<Character>();
for (int x=freq.length-1;x>=0;--x)
{
if (freq[x]==min)
rares.add((char)x);
}
return rares;
}
Any effort to keep the list sorted by frequency as you go is going to be way more inefficient, because it will have to re-sort every time you examine one character.
Any attempt to sort the list of frequencies at all is going to be more inefficient, as sorting the whole list is clearly going to be slower than just picking the smallest value.
Sorting the string and then counting is going to be slower because the sort will be more expensive than the count.
Technically, it would be faster to create a simple array at the end rather than an ArrayList, but the ArrayList makes slightly more readable code.
There may be a way to do it faster, but I suspect this is close to the optimum solution. I'd certainly be interested to see if someone has a better idea.
I think your approach is in theory the most efficient (O(n)). However in practice it needs quite a lot of memory, and is probably very slow.
It is possibly more efficient (at least it uses less memory) to convert the string to a char array, sort the array, and then calculate the frequencies using a simple loop. However, in theory it is less efficient (O(n log n)) because of sorting (unless you use a more efficient sort algorithm).
Test case:
import java.util.Arrays;
public class Test {
public static void main(String... args) throws Exception {
// System.out.println(getLowFrequencyChar("x"));
// System.out.println(getLowFrequencyChar("bab"));
// System.out.println(getLowFrequencyChar("babaa"));
for (int i = 0; i < 5; i++) {
long start = System.currentTimeMillis();
for (int j = 0; j < 1000000; j++) {
getLowFrequencyChar("long start = System.currentTimeMillis();");
}
System.out.println(System.currentTimeMillis() - start);
}
}
private static char getLowFrequencyChar(String string) {
int len = string.length();
if (len == 0) {
return 0;
} else if (len == 1) {
return string.charAt(0);
}
char[] chars = string.toCharArray();
Arrays.sort(chars);
int low = Integer.MAX_VALUE, f = 1;
char last = chars[0], x = 0;
for (int i = 1; i < len; i++) {
char c = chars[i];
if (c != last) {
if (f < low) {
if (f == 1) {
return last;
}
low = f;
x = last;
}
last = c;
f = 1;
} else {
f++;
}
}
if (f < low) {
x = last;
}
return (char) x;
}
}
The process of finding frequency of characters in a String is very easy.
For answer see my code.
import java.io.*;
public class frequency_of_char
{
public static void main(String args[])throws IOException
{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int ci,i,j,k,l;l=0;
String str,str1;
char c,ch;
System.out.println("Enter your String");
str=in.readLine();
i=str.length();
for(c='A';c<='z';c++)
{
k=0;
for(j=0;j<i;j++)
{
ch=str.charAt(j);
if(ch==c)
k++;
}
if(k>0)
System.out.println("The character "+c+" has occured for "+k+" times");
}
}
}
I'd do it the following way as it involves the fewest lines of code:
character you wish to want to know frequency of: "_"
String "this_is_a_test"
String testStr = "this_is_a_test";
String[] parts = testStr.split("_"); //note you need to use regular expressions here
int freq = parts.length -1;
You may find weird things happen if the string starts or ends with the character in question, but I'll leave it to you to test for that.
Having to iterate through the HashMap is not necessarily bad. That will only be O(h) where h is the HashMap's length--the number of unique characters--which in this case will always be less than or equal to n. For the example "aaabbc", h = 3 for the three unique characters. But, since h is strictly less than the number of possible characters: 255, it is constant. So, your big-oh will be O(n+h) which is actually O(n) since h is constant. I don't know of any algorithm that could get a better big-oh, you could try to have a bunch of java specific optimizations, but that said here is a simple algorithm I wrote that finds the char with the lowest frequency. It returns "c" from the input "aaabbc".
import java.util.HashMap;
import java.util.Map;
public class StackOverflowQuestion {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("" + findLowestFrequency("aaabbc"));
}
public static char findLowestFrequency(String input) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (char c : input.toCharArray())
if (map.containsKey(c))
map.put(c, map.get(c) + 1);
else
map.put(c, 0);
char rarest = map.keySet().iterator().next();
for (char c : map.keySet())
if (map.get(c) < map.get(rarest))
rarest = c;
return rarest;
}
}

Categories