Find first non repeating character without using hashmap - java

I wanted to find first non repeating character in a string. I wrote the following function in which I am stuck at one point. Google tells me the hashmap method for this but I'll be grateful if someone could help me with my code.
public static Character firstNonRepeatedChar(String line) {
Character c = null;
int strLength = line.length();
for (int i =0; i<strLength-1; i++){
int flag = 0;
for(int j = i+1; j<strLength-i; j++){
if(line.charAt(i) == line.charAt(j)){
flag++;
break;
}
else
continue;
}
if (flag==0){
c = line.charAt(i);
break;
}
}
return c;
}
}
Problem : How can I put a check that the repeating character that is already checked once is not checked again.
Ex: If my string is "hhello" then the code first compares the h at index 0 with all the other characters. Since its repeating the next iteration of outer for loop starts in which i now points to index 1 of the string i.e the repeating h and compares it with the rest of elements. Since it does not get a repeating instance it returns 'h' as non repeating character which is wrong.
How can I fix this? Is there any way?
Pls help
EDIT: Repeating character need not be the immediate next character.
Ex: In string "helloWorld" characters 'l' and 'o' are repeating.
In string "hehelo" characters 'h' and 'e' are repeating and first non repeating character will be 'l'

***For all case of repetition
Character c = null;
int strLength = line.length();
for (int i = 0; i < strLength; i++) {
int flag = 0;
for (int j = 0; j < strLength; j++) {
if (line.charAt(i) == line.charAt(j) && i != j) {
flag = 1;
break;
}
}
if (flag == 0) {
c = line.charAt(i);
break;
}
}
return c;
This is so simple to check, Your logic is complex. try this for immediate repeated character.
Character c = null;
int strLength = line.length();
for (int i = 0; i < strLength - 1;) {
int flag = 0;
int present_char_position = 0;
if (line.charAt(i) == line.charAt(i + 1)) {
flag++;
present_char_position = i;
i += 2;//jumping from those two character if matched
continue;
} else {
present_char_position = i;
i++;//if not matched go to next character
}
if (flag == 0) {
c = line.charAt(present_char_position);
break;
}
}
return c;

Hint 1: A repeating character1 is one that is the same as the previous character in the String. A non-repeating character is .........
Implement that!
Hint 2: You don't need a nested loop.
UPDATE
I see. So you are using "non-repeating character" to mean something different to what most people would mean. What you are actually looking for is the first character that appears only once in the entire string.
Anyway ... at least I now understand why you are using a nested loop now, and I understand the bug.
Hint 3: Even when a character appears multiple time in a string, it will still appear ZERO times after its last occurrence.
That is what your inner loop tests for. So what you are finding is the first character in the string that isn't duplicated in the remainder of the string.
The fix is simple ... once you understand what you are doing wrong.
Once you have fixed that are some other tidy ups:
The else continue is redundant.
The c variable is unnecessary ... if you change:
if (flag==0){
c = line.charAt(i);
break;
}
to
if (flag==0){
return line.charAt(i);
}
and
return c;
to
return null;
1 - This is what a native English speaker understands by "find the first non-repeating character". It is possible that you mean something else. If so, please update the question to clarify. Please describe as clearly as you can what you mean. Please give examples.

The easiest way to flag doublets would be to replace the characters with a none printable one. You can then skip these positions. But this will add another O(n) to your loop replacing the characters. The worst case would result in O(n^3). Optimizing you could write an inner loop replacing only the characters ahead of your current position. This would result in a O(n^2) again, because currently you have O(n^2) (n*n/2).
UPDATE
Added code and fixed a bug, where the non repeating character is at last position of the String.
Instead of processing the String, now processing the char[].
private static final char FLAG = '\u0000';
public static Character firstNonRepeatedChar(String line)
{
final char[] chars = line.toCharArray();
Character c = null;
final int strLength = chars.length;
for (int i = 0; i < strLength; i++)
{
if (chars[i] == FLAG)
{
continue;
}
int flag = 0;
for (int j = i + 1; j < strLength; j++)
{
if (chars[i] == chars[j])
{
flag++;
chars[j] = FLAG;
}
}
if (flag == 0)
{
c = chars[i];
break;
}
}
return c;
}

Below method will return you what you are looking.
public static char getFirstNonRepeatedChar(String input) {
char c = 0;
for (int i =0; i<input.length(); i++){
int flag = 0;
for(int j = 0; j<input.length(); j++){
if(input.charAt(i) == input.charAt(j)){
flag++;
}
if(flag>1)
break;
}
if (flag == 1){
c = input.charAt(i);
break;
}
}
return c;
}

This one is for PHP
<?php
$string = "ABBGAACCE";
$stringArray = str_split($string); // string converted to array
$temp_array = [];
$non_repeating_array = get_first_non_repeating($stringArray, $temp_array);
echo reset($non_repeating_array); // display first non repeating character from string
function get_first_non_repeating($stringArray, $temp_array)
{
$repeating = []; // store all repeating characters
foreach($stringArray as $key => $char)
{
if(array_key_exists($char, $temp_array)) // check if character was already saved meaning it is repeating
{
array_push($repeating, $char); // push all repeating character in a variable
$stringArray = array_diff($stringArray, $repeating); // subtract repeating characters from the string array
}else{
$temp_array[$char] = 1;
}
}
return $stringArray; // returns the non repeating characters
}

Related

How to find frequency of characters in a string without using array in java

Given a String, I want to create a frequency distribution of characters in the String. That is, for each distinct character in the string, I want to count how many times it occurs.
Output is a String that consists of zero or more occurrences of the pattern xd, where x is a character from the source String, and d is the number of occurrences of x within the String. Each x in the output should occur once.
The challenge is to do this without using an array or Collection.
Examples:
Source: "aasdddr" Result: "a2s1d3r1"
Source: "aabacc" Result: "a3b1c2"
Source: "aasdddraabcdaa" Result: "a6s1d4r1b1c1"
I tried this way:
String str = "aasdddr", result = "";
int counter = 0;
for(int i = 0; i < str.length(); i++){
result += "" + str.charAt(i);
for(int j = 1; j < str.length(); j++){
if(str.charAt(i) == str.charAt(j)){
counter++;
}
}
result += counter;
}
System.out.println(result);
My output is a1a2s3d6d9d12r13
Finally, I found the solution. But I think any question has more than one solution.
First, we should declare an empty string to keep the result. We use a nested loop because the outer loop will keep a character fixed during each iteration of the inner loop. Also, we should declare a count variable inside the outer loop. Because in each match, it will be increased by one and after controlling each character in the inner loop, it will be zero for the next check. Finally, after the inner loop, we should put a condition to check whether we have that character inside the result string. If there isn't any character like that, then it will be added to the result string. After that, its frequency (count) will be added. Outside of the loop, we can print it.
public class FrequenciesOfChar {
public static void main(String[] args) {
String str = "aabcccd"; // be sure that you don't have any digit in your string
String result = ""; // this will hold new string
for (int i = 0; i < str.length(); i++) { // this will hold a character till be checked by inner loop
int count = 0; // put here so that it can be zero after each cycle for new character
for (int j = 0; j < str.length(); j++) { // this will change
if(str.charAt(i) == str.charAt(j)){ // this will check whether there is a same character
count++; // if there is a same character, count will increase
}
}
if( !(result.contains(""+str.charAt(i))) ){ // this checks if result doesn't contain the checked character
result += ""+str.charAt(i); // first if result doesn't contain the checked character, character will be added
result += count; // then the character's frequency will be added
}
}
System.out.println(result);
}
}
Run Result:
aabcccd - a2b1c3d1
First, counter needs to be reset inside the for loop. Each time you encounter a character in the source String, you want to restart the counter. Otherwise, as you have seen, the value of the counter is strictly increasing.
Now, think about what happens if a character occurs in more than one place in the source String, as in the "aasdddraabcdaa" example. A sequence of 1 or more a appears in 3 places. Because, at the time you get to the 2nd occurrence of a, a has been previously counted, you want to skip over it.
Because the source String cannot contain digits, the result String can be used to check if a particular character value has already been processed. So, after fixing the problem with counter, the code can be fixed by adding these two lines:
if (result.indexOf (source.charAt(i)) >= 0) {
continue; }
Here is the complete result:
package stackoverflowmisc;
public class StackOverflowMisc {
public static String freqDist(String source) {
String result = "";
int counter ;
for (int i = 0; i < source.length(); i++) {
if (result.indexOf (source.charAt(i)) >= 0) { continue; }
counter = 1;
result += source.charAt(i);
for (int j = 1; j < source.length(); j++) {
if (source.charAt(i) == source.charAt(j)) {
counter++;
}
}
result += counter;
}
return result;
}
public static void main(String[] args) {
String [] test = {"aasdddr", "aabacc", "aasdddraabcdaa"};
for (int i = 0; i < test.length; ++i) {
System.out.println (test[i] + " - " + freqDist (test[i]));
}
System.out.println ("End of Program");
}
}
Run results:
aasdddr - a2s2d4r2
aabacc - a3b2c3
aasdddraabcdaa - a6s2d5r2b2c2
End of Program
In one of the Q&A comments, you said the source string can contain only letters. How would the program work if it were allowed to contain digits? You can't use the result String, because the processing inserts digits there. Again, this is an easy fix: Add a 3rd String to record which values have already been found:
public static String freqDist2(String source) {
String result = "", found = "";
int counter ;
for (int i = 0; i < source.length(); i++) {
if (found.indexOf (source.charAt(i)) >= 0) { continue; }
counter = 1;
result += source.charAt(i);
found += source.charAt(i);
for (int j = 1; j < source.length(); j++) {
if (source.charAt(i) == source.charAt(j)) {
counter++;
}
}
result += counter;
}
return result;
}
Another possibility is to delete the corresponding characters from the source String as they are counted. If you are not allowed to modify the Source String, make a copy and use the copy.
Comment: I don't know if this is what your professor or whomever had in mind by placing the "No array" restriction, because a String is essentially built on a char array.

Counting vowels in a string

I got 3 strings from the user as input.Then count the vowels in each word and print as follows.If the vowel count = 0 and 1 then print 0.If the vowel count = 2 then print 2.If the vowel count is greater than or equal to 3 then print 3.
I tried this code.
Scanner in = new Scanner(System.in);
String[] str = new String[3];
for (int i = 0; i<3; i++)
str[i] = in .nextLine();
for (int j = 0; j<3; j++) {
String s1 = str[j];
String s = s1.toLowerCase();
int count = 0;
for (int i = 0; i<s.length(); i++)
{
if (s.charAt(i) == 'a' || s.charAt(i) == 'e' || s.charAt(i) == 'i' || s.charAt(i) == 'o' || s.charAt(i) == 'u') {
count++;
}
if (s.charAt(i) == ' ') {
if (count == 0||count == 1) {
System.out.print("0");
} else if (count == 2) {
System.out.print("1");
} else {
System.out.print("3");
}
count = 0;
}
}
if (count == 0||count == 1) {
System.out.println("0");
} else if (count == 2) {
System.out.println("1");
} else {
System.out.println("3");
}
}
But there is one condition only print the vowel count for 3 words only even if the user enter the string with more than 3 words.For eg if the user gives the string "hi hello all, how are you,I am fine and u" it prints "010
011
001" like this only but this code prints as "010
011
00100".Now how can i change the code to print the vowel count only for 3 words and not for more than 3?
You need some kind of a break after the third word. One option would be to make an extra variable for tracking it and increment it when the character is space. After 3 words you could break the loop.
Other option would be to split the String into words with split() method and the iterate over the first 3 only.
You could simplify your code a lot and it will be easier to achieve what you want. Instead of loop on each char, you can split your string. And then loop on the words. Something like this:
for (int j = 0; j<3; j++) {
String[] words = str[j].toLowerCase().split(" ");
// Use Math.min, thanks that it works even if you have only 2 words
for(int i = 0; i < Math.min(3, words.length()); i++) {
int count = 0;
for (char letter : words[i].toCharArray()) {
// if letter is vowel: count += 1;
}
// System.out.println depending on count value
}
}
You could use a Regex to split words into a sentence, using this method:
String[] splits = myPhrase.split(" ");
to split words in a sentence, but you have to be careful that if the user enters more spaces, the first one is "eliminated" and those just after end up in the split.
For example:
String phrase = "1 2 3 z";
String[] splits = phrase.split(" ");
generates this array: [1|2| |3| | |z].
So, in my opinion, at that point you could use a filter, go through the array / list again eliminating any space derived from the regex or more simply when you scroll through the array / list and find a space you don't consider it.
At this point go to analyze the first 3 elements of the array / list, discarding the others (maybe using a counter).
Finally, again using a Regex, you can also check if the character you are analyzing is a vowel or not using this command:
if (s.charAt(i).matches("[AEIOUaeiou]")){ /*it's a vowel*/}

how to take into account the presence of more than one space? java

Task: There is a string. Calculate the number of words in the string. The word is considered separated by spaces. (You can not use regular expressions)
How to solve? If you enter two or more spaces in a row - will consider that these words but I need to count as one big pass between the words
Example I_live_in_Lviv - 4 words, but if we put one more space (for an example before Lviv) -> I_live_in__Lviv - 5 words (instead of underlining, put a space(-s))
Scanner in = new Scanner(System.in);
String line = in.nextLine();
int n = 0;
if (line.length() != 0) {
n++;
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == ' ') {
n++;
}
}
}
System.out.print(n);
Answer:
Scanner in = new Scanner(System.in);
String line = in.nextLine();
int count = 0;
for(int i = 0; i <= line.length() - 1; i++){
if(Character.isLetter(line.charAt(i))){
count++;
for( ; i <= line.length() - 1; i++){
if(line.charAt(i) == ' '){
i++;
break;
}
}
}
}
System.out.print(count);
in.close();
Result:
I_live_in__Lviv_ - 4
So from what I'm understanding you have a string, e.g. " hi my name is Matthew" and you want to find how many words are in the string. I would just take two characters at a time, but step them by one, and test if the first is a space and the second isn't. So take " h", that's the beginning of a word. Then "hi", that's not, etc. Of course you'd want to check if the first character isn't a space and if not increment the word count.
Edit: Sorry I didn't elaborate, I was in a time crunch this morning. Use String.subString(i, i + 2); to get two characters from the string. Then check the new string with either subString() or charAt() (I'd recommend charAt()), of course accounting for the string length - 2 to prevent an error being thrown.
for (int i = 0; i < exampleString.length - 2; i++) {
//subtract 2 to prevent subString from throwing an error
if ((exampleString.subString(i, i + 2).charAt(1) = " " && exampleString.subString(i, i + 2).charAt(2) != " ") || i = 0) {
//add 2 to get a space and a letter, then test the first character for a
//space and the second character for NOT a space, also increment words if
//i = 0, presuming there is no space at the beginning of the string
words++;
}
}
So basically what #JB Nizet said, only in answer form... sorry I didn't see your comment until now, I wouldn't have typed all of this
just add one more variable and store the previous character in it. Check if it is space with the next character if it returns false increment the count.
Scanner in = new Scanner(System.in);
String line = in.nextLine();
int count = 0;
for(int i = 0; i <= line.length() - 1; i++){
if(Character.isLetter(line.charAt(i))){
count++;
for( ; i <= line.length() - 1; i++){
if(line.charAt(i) == ' '){
i++;
break;
}
}
}
}
System.out.print(count); //I_live_in__Lviv_ - 4
in.close();

Matching subsequence of length 2 (at same index) in two strings

Given 2 strings, a and b, return the number of the positions where they contain the same length 2 substring. For instance a and b is respectively "xxcaazz" and "xxbaaz" yields 3, since the "xx", "aa", and "az" substrings appear in the same place in both strings.
What is wrong with my solution?
int count=0;
for(int i=0;i<a.length();i++)
{
for(int u=i; u<b.length(); u++)
{
String aSub=a.substring(i,i+1);
String bSub=b.substring(u,u+1);
if(aSub.equals(bSub))
count++;
}
}
return count;
}
In order to fix your solution, you really don't need the inner loop. Since the index should be same for the substrings in both string, only one loop is needed.
Also, you should iterate till 2nd last character of the smaller string, to avoid IndexOutOfBounds. And for substring, give i+2 as second argument instead.
Overall, you would have to change your code to something like this:
int count=0;
for(int i=0; i < small(a, b).length()-1; i++)
{
String aSub=a.substring(i,i+2);
String bSub=b.substring(i,i+2);
if(aSub.equals(bSub))
count++;
}
}
return count;
Why I asked about the length of string is, it might become expensive to create substrings of length 2 in loop. For length n of smaller string, you would be creating 2 * n substrings.
I would rather not create substring, and just match character by character, while keeping track of whether previous character matched or not. This will work perfectly fine in your case, as length of substring to match is 2. Code would be like:
String a = "iaxxai";
String b = "aaxxaaxx";
boolean lastCharacterMatch = false;
int count = 0;
for (int i = 0; i < Math.min(a.length(), b.length()); i++) {
if (a.charAt(i) == b.charAt(i)) {
if (lastCharacterMatch) {
count++;
} else {
lastCharacterMatch = true;
}
} else {
lastCharacterMatch = false;
}
}
System.out.println(count);
The heart of the problem lies with your usage of the substring method. The important thing to note is that the beginning index is inclusive, and the end index is exclusive.
As an example, dissecting your usage, String aSub=a.substring(i,i+1); in the first iteration of the loop i = 0 so this line is then String aSub=a.substring(0,1); From the javadocs, and my explanation above, this would result in a substring from the first character to the first character or String aSub="x"; Changing this to i+2 and u+2 will get you the desired behavior but beware of index out of bounds errors with the way your loops are currently written.
String a = "xxcaazz";
String b = "xxbaaz";
int count = 0;
for (int i = 0; i < (a.length() > b.length() ? b : a).length() - 1; i++) {
String aSub = a.substring(i, i + 2);
String bSub = b.substring(i, i + 2);
if (aSub.equals(bSub)) {
count++;
}
}
System.out.println(count);

Allow indexOf to check for match multiple times in Java

I'm currently working on a project for a class to create a TextLine class that represents the a line of text that must be represented as an array of characters. I am not allowed to represent the TextLine object by using the string class indirectly or directly in any way, however, I can use it to work with the parameters.
For one of the methods, I am supposed to take in a string as an argument of a parameter, which is also a fragment to the TextLine object, and then return the index position of the first occurrence of the fragment in this TextLine, or -1, if the fragment is not found.
Right now, I'm trying to figure out the indexOf method, but my problem is that my method only checks for a starting point once. So if the letter of the TextLine object doesn't match the letter of the fragment the first time, but there is another match somewhere else in the object, the method doesn't check for that starting point.
For example, lets say I enter penplay as the TextLine, then I enter play as the fragment. Clearly, there is an occurrence of play in the TextLine, but what my indexOf method does, is that it checks the first p from penplay at index 0, then continues to see if the following letters match for the length of play, and if it doesn't, it returns -1. Any idea how I could allow the algorithm to keep searching for another starting point?
This is what I have for my code:
public int indexOf(String fragment){
char[] temp = fragment.toCharArray();
int j = 0;
for(int i = 0; i < someText.length; i++){
while(someText[i] == temp[j]){
for(j = 1; j < temp.length; j++){
if(temp[j] != someText[i+j]){
return -1;
}
}
return i;
}
}
return -1;
}
You're special-casing the first character, when there's no need to. Basically you need to say:
For each potential starting character...
Does the whole of fragment match, starting at that candidate position?
So something like:
// Only deal with *viable* starting points
for (int i = 0; i < someText.length - temp.length; i++) {
boolean found = true;
for (int j = 0; j < temp.length && found; j++) {
if (temp[j] != someText[i + j]) {
found = false;
}
}
if (found) {
return i;
}
}
return -1;
This can be refactored by extracting the inner loop:
for (int i = 0; i < someText.length - temp.length; i++) {
if (textMatches(temp, i)) {
return i;
}
}
return -1;
...
// TODO: Javadoc to explain parameters :)
private boolean textMatches(char[] chars, int startingIndex) {
for (int i = 0; i < chars.length; i++) {
if (chars[i] != someText[i + startingIndex]) {
return false;
}
}
return true;
}
The way you have it set up seems suitable as a kind of doesStringExistAtIndex(j, fragment) function. Since that returns -1 if the string doesn't exist at the first index, you could do something like this:
//assuming that "this" is the subject that you are searching in
public int indexOf(String fragment){
for(int i=0; i<this.length; ++i){
if(doesStringExistAtIndex(i, fragment))
return i;
}
return -1;
}
Not sure if this is what you wanted, but I basically wrote up an indexOf method. I did some testing and it seemed to work just fine in some tests I did. Of course, its going to look different because I wanted to make testing easier, but it should be 30 seconds or less of converting if you decide to use it.
public int indexOf(String fragment, String source)
{
char[] temp = fragment.toCharArray();
char[] someText = source.toCharArray();
outer : for(int i = 0; i <= someText.length - temp.length;i++) //stops looping because why loop after the fragment is longer than the source we have left when its impossible to find
{
if(someText[i] == temp[0]) //if the first characters are the same
{
int q = 0;
while(q < temp.length) //loop through the fragment
{
if(someText[i+q] != temp[q]) //if the characters are not the same, stop, and go to the next character of the source. Don't return anything
{
continue outer; //continues the loop labeled 'outer' (e.g. outer : for(...) )
}
q++; //increment index since they both match
}
return i; //fragment and some part of the source matched since it reached here. Return the index of the first character
}
}
return -1; //reached here because nothing was found :( return -1
}
EDIT 0 Added line comments

Categories

Resources