OK, i know this question was asked many times here, but i still don't get it, how to find the first repeated character in a string ?
I did something which was close, but it gave me all repeated characters instead of only the first one.
Here's what i did :
private static void stringChar(){
String s = "sababa";
int count = 0;
char c[] = s.toCharArray();
System.out.println("Duplicate characters are :");
for(int i = 0; i < s.length(); i++){
for(int j = i + 1; j < s.length(); j++){
if(c[i] == c[j]) {
System.out.println(c[j]);
count++;
break;
}
}
}
}
One quick and dirty (yet effective) approach which comes to mind is to maintain a map whose keys are the characters. In this case, we don't even need a formal map, because we can use an integer array which maps to the underlying ASCII values of the characters.
The basic idea here is to walk down the string, and check the array if we have seen it before. If so, then print that character and exit.
int[] nums = new int[128]; // assuming only basic ASCII characters
String str = "stuff";
for (int i=0; i < str.length(); ++i) {
int index = str.charAt(i);
if (nums[index] != 0) {
System.out.println("The first repeated character is: " + str.charAt(i));
break;
}
++nums[index];
}
Demo
You need to break the outer loop if you have already found the repeating character.
boolean found = false;
for(int i = 0; i < s.length(); i++){
for(int j = i + 1; j < s.length(); j++){
if(c[i] == c[j]) {
System.out.println(c[j]);
found = true;
break;
}
}
if (found) {
break;
}
}
If you want the count of it
int count = 0;
char repeatingChar = '0'; //dummy to overcome compiler warning
for(int i = 0; i < s.length(); i++){
for(int j = i + 1; j < s.length(); j++){
if(c[i] == c[j]) {
repeatingChar = c[j];
count++;
}
}
if (count > 0) {
System.out.println("Repeating char is " + repeatingChar + ". Occurred " + count + " times");
break;
}
}
The first repeated char is one you have seen before as you iterate the chars in the string. You can keep track of the first time you see a char with a Boolean array. The array is indexed with the char value. Java automatically "widens" char to int. So, for each char, check if it's been seen before and if not, mark that it has been seen.
String s = "sababa";
boolean[] seenChars = new boolean[Character.MAX_VALUE + 1]; // initialized to all false.
for (char c : s.toCharArray()) {
if (Character.isSurrogate(c)) throw new IllegalArgumentException("No first char seen before seeing a surrogate. This algorithm doesn't work for codepoints needing surrogates in UTF-16.");
if (seenChars[c]) {
System.out.println("First repeated char is: " + c);
break;
}
seenChars[c] = true;
}
You might notice that I've been saying char instead of character. Character is not a well-defined term. Java's text datatypes use the UTF-16 encoding of the Unicode character set. Some Unicode codepoints require two UTF-16 code units (char), which are sometimes called surrogate pairs. Since they are not all unique as individual chars, the algorithm doesn't work if they are present. For example, try String s = "sab🚲aba"; (You can also write it as "sab\uD83D\uDEB2aba".) The answer would be "a", again. But now try String s = "sab🚲🚶aba"; (You can also write it as "sab\uD83D\uDEB2\uD83D\uDEB6aba".) The answer should still be "a" but the algorithm would say "\uD83D" (which of course can't be displayed because it is only part of a codepoint).
Short and Simple >
void findFirstDupChar() {
String s = "google";
Integer dupIndex = s.length() - 1;
boolean isDuplicateExists = false;
Map<Character, Integer> map = new LinkedHashMap<>();
char[] words = s.toCharArray();
for (int i = 0; i < words.length; i++) {
Integer index = map.put(words[i], i);
if (index != null) {
if (index < dupIndex) {
dupIndex = index;
isDuplicateExists = true;
}
}
}
System.out.println(isDuplicateExists ? words[dupIndex] + ", index=" + dupIndex : "No duplicateds found");
}
This will print output as following >
g, index=0
Related
Given a text string, only remove consecutive duplicate occurrences of the same character, but the later occurrences of the same character remain in the result as long as there was some other character between these occurrence.
Example: given argument aaaabxaaddee returns abxade.
Here's what I've tried so far:
char[] new_string = text.toCharArray();
String result = "";
for (int i = 1; i < text.length(); i++) {
if (text.charAt(0) != text.charAt(i)) {
text.charAt(0) = text.charAt(i);
result += text.charAt(i);
}
}
return res;
This is pretty simple iterate over given string only once:
public static String removeDuplicates(String str) {
StringBuilder buf = new StringBuilder(str.length());
char prv = '\0';
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch != prv)
buf.append(ch);
prv = ch;
}
return buf.toString();
}
I suggest you start with a StringBuilder whenever you want to mutate a sequence of characters in Java. Here you can loop from the left to the right, and start a second inner loop removing duplicate characters from the StringBuilder. Something like,
public static String removeDuplicates(String text) {
StringBuilder sb = new StringBuilder(text);
for (int i = 0; i < sb.length() - 1;) {
char ch = sb.charAt(i);
int j = i + 1;
while (j < sb.length() && sb.charAt(j) == ch) {
sb.deleteCharAt(j);
}
i = j;
}
return sb.toString();
}
Which I tested like
public static void main(String[] args) {
System.out.println(removeDuplicates("aaaabxaaddee"));
}
And it outputs (as requested)
abxade
You are comparing with the first character only. Update your logic to compare the current char (at i) to the next (at i+1) and also start your loop from 0.
You are only comparing the 0-th index of the char array which won't lead to the desired result. Also, you can't modify the string by text.charAt(0) = text.charAt(i). It's invalid in Java.
Instead can use a while loop inside your for loop to check for consecutive occurrences. Keep checking if the current and next character in the string is equal. If they are equal then move ahead else break the while loop and continue with other iterations.
for (int i = 0; i < text.length(); i++)
{
result += text.charAt(i);
while (i < text.length()-1 && text.charAt(i)==text.charAt(i+1))
++i;
}
You are thinking in the right direction but instead of comparing each character with 0 index position character you can compare it with previous character since you have to ignore the consecutive ones .
char[] new_string = text.toCharArray();
String result = ""+text.charAt(0);
for (int i = 1; i < text.length(); i++) {
if (text.charAt(i-1) != text.charAt(i)) {
result += text.charAt(i);
}
}
return result;
}
}
Note:-
"text.charAt(0) = text.charAt(i)" This cannot be done in java as String is an immutable Class.
You are returning 'res' while you are storing the required string in 'result'.
This question already has answers here:
How to replace multiple consecutive occurrences of a character with a maximum allowed number of occurences?
(2 answers)
Closed 3 years ago.
I need to write a method that takes a String as a parameter and returns a new String obtained by replacing every instance of repeated adjacent letters with a 'n' instances of that string.
For example, if "aaabcccd" as an input String and n =2, it returns "aabccd". I already tried the following code, but not getting expected output
String in = "aaadbbb";
char[] s = in.toCharArray();
int len = s.length;
int n = 2;
StringBuffer new_s = new StringBuffer("");
int count = 1;
char prev='\0';
for (int i = 0; i < len - 1; i++) {
if (s[i] == s[i + 1]) {
if(count <= n){
new_s.append(s[i]);
count++;
}else{
count=1;
}
} else {
new_s.append(s[i]);
}
}
System.out.println(new_s);
output-aaadb
expected-aadbb
Can be done with regexp magic using backreferences.
String in = "aaaaddbbbbc";
int n = 2;
String pattern = String.format("(([a-z])\\2{%d})\\2+", n - 1);
System.out.println(in.replaceAll(pattern, "$1"));
Outputs:
aaddbbc
Explanation:
The number inside {} is n-1.
([a-z]) is a capture group, matching any single lowercase letter from a to z. Since it's a second group of parentheses in the expression, it can be referenced as 2.
(([a-z])\\2{n}) means "match n+1 repetitions of same letter". It makes up a first capture group, and we'll use that as replacement
\\2+ matches all the extra repetitions of the same letter. They are discarded after replacement.
public static String test(String input, int repetitions) {
String flag = "";
String replacement = "";
String output = input;
ArrayList<Character> prevLetters = new ArrayList<Character>();
for(int x = 0; x < input.length(); x++) {
if(!prevLetters.contains(input.charAt(x))) {
for(int y = 0; y <= repetitions ; y++) {
flag += String.valueOf(input.charAt(x));
}
if(input.contains(flag)) {
replacement = flag.substring(0, flag.length()-1);
while(output.contains(flag)){
output = output.replace(flag, replacement);
}
}
flag = "";
prevLetters.add(input.charAt(x));
}
}
return output;
}
That is my solution, which follows a similar idea as yours. Rather than comparing each character value however, I thought it would be easier to simply check for a break in the rules (character appearing n+1 times in a row) and 'fix' it.
If you are interested in using your method, one potential issue that I noticed is that you aren't assigning count to 1 in your last else. You also won't have the chance to add the final character due to you only adding the character at index 'i' when the duration for the loop is len - 1.
To add one more alternative:
String in = "aaadbbbjjkllllllopp";
int n = 2;
StringBuilder sb = new StringBuilder();
char temp = in.charAt(0);
for(int i = 0; i < in.length()-1;){ // note that the incrementation of i is moved to the while loop
temp = in.charAt(i); // save current char in temp variable
int count = 0;
while (i < in.length() && in.charAt(i) == temp) { ///iterate as long as you find same chars or hit the end of the string
i++;
count++;
}
if (count > n){ // if and only if count is greater than max allowed set it to max allowed
count = n;
}
for(int j = 0; j < count; j++){ // append count chars
sb.append(temp);
}
}
System.out.println(sb.toString());
Look at this solution. You should take care of the last char in your input string, as you iterate only to the last but one.
private void replaceConsecutiveDuplicates() {
String input = "aaadbbb";
int n = 2;
StringBuffer sb = new StringBuffer();
int count = 1;
char current;
for( int i = 0; i < input.length(); ++i){
current = input.charAt(i);
if (i + 1 < input.length() && current == input.charAt(i + 1)) {
++count;
} else if (count > 1) {
for(int j = 0; j < n; ++j) {
sb.append(current);
}
count = 1;
}
else {
sb.append(current);
}
}
System.out.println(sb.toString());
}
I think you're on the right track. I'm not sure whether this is an assignment, so I don't want to just straight up give you an answer, but here are some hints that might help:
You're already iterating over the string. This is great! However, I think you want to compare the current character with the previous character, and not the next character.
You don't need to convert your input to a char array to iterate over it, just use charAt(idx)
You never seem to use prev, but I think you had the right idea in mind when you declared it!
Break your problem into two parts: When to update count and when to append a character. You can tackle both in your for loop, but instead of trying to do both things in the same if statements, break it up into multiple ifs.
The 3 things to do are:
Update Prev Value
Update Count
Update new String
Getting the right order for these and the exact implementation I'll leave to you (again, because I'm not sure if this is an assignment or not)
Update: Since others posted, here is my solution (with single for loop):
private String replaceConsecutiveDuplicates(String input, int n) {
if (input == null || input.length() < n) return input;
if (n == 0) return "";
StringBuffer sb = new StringBuffer();
int count = 1;
char prev = input.charAt(0);
sb.append(prev);
char current;
for( int i = 1; i < input.length(); i++) {
current = input.charAt(i);
if (prev == current) {
if (++count > n) continue;
} else {
count = 1;
}
prev = current;
sb.append(current);
}
return sb.toString();
}
I have string in java "naveen" i want output as "eennav". Please help me out in this. The idea is that the characters are to be ordered in order of frequency, and, where frequencies are the same, alphabetically.
Thanks
I have tried to find duplicates in the string , but am not able to get the required output .
String str="naveen";
int count =0;
char[] charr=str.toCharArray();
for(int i=0;i<charr.length;i++) {
//System.out.println(s[i]);
for(int j=i+1;j<charr.length;j++) {
if(charr[i]==(charr[j])) {
System.out.println(charr[i]);
}
Assuming the question is asking us to take a string containing only lower case letters and organize them by frequency of letters (high to low) and within that by alphabetical order, we can do it as below.
The strategy is first to make a pass through the characters of the input string and count the number of occurrences of each. Then we look through the counts for letters and find the largest. Working from the largest down to 1, we run through the alphabet for characters that occur that many times, and append that many of them to the result string.
There is a little bit of work involved here to convert back and forth from 'a' to 0 and 0 to 'a' and so on to 25 and 'z'.
This approach could be extended, but since the question didn't specify, I chose to make simplifying assumptions. I also did not work on optimizing, just getting it to work.
public class MyClass {
public static void main(String args[]) {
String str = "naveen"; //this string may change, but it is assumed to be all lower case letters by this implementation
int[] counts = new int[26]; //frequency count of letters a to z
for (int i = 0; i < 26; i++) {
counts[i] = 0; // intially 0 of any letter
}
char[] charr = str.toCharArray();
for (int i = 0; i < charr.length; i++) {
counts[(int)(charr[i]) - (int)('a')]++; // increment corresponding spot in counts array, spot 0 for 'a' through 25 for 'z'
}
int maxCount = counts[0]; // now find the most occurrences of any letter
for (int i = 1; i < counts.length; i++) {
if (counts[i] > maxCount) {
maxCount = counts[i];
}
}
String result = ""; // string to return
for (int j = maxCount; j > 0; j--) { // work down from most frequently occuring, within that alphabetically
for (int i = 0; i < 26; i++) {
if (counts[i] == j) {
//System.out.println("there are "+j+" of the letter "+(char)((int)('a'+i)));
for (int k = 0; k < j; k++) {
result = result + (char)((int)('a' + i));
}
};
}
}
System.out.println(result);
}
}
This question already has answers here:
Java: Print a unique character in a string
(20 answers)
Closed 4 years ago.
I am trying to print a character from a string which occurs only one time in the string. Here is the code I am using, but it is showing the answer always as H.
How can I fix this?
class StringRepeat {
static int i,j;
public static void main(String[] args) {
String s1 = "How are How";
outer:for(i=0;i<=s1.length(); i++)
{
inner:for(j=1;j<s1.length(); j++)
{
if (s1.charAt(i) != s1.charAt(j))
break outer;
}
}
System.out.println(s1.charAt(i));
}
}
Basically you can solve this in 2 ways - brute force (using arrays) and a bit more intelligently (using maps).
Brute force way
For every character in the input string check if it is the same as some other character:
public void uniqueCharsBruteForce(String input) {
for (int i = 0; i < input.length(); ++i) {
char candidate = input.charAt(i);
if (!contains(input, candidate, i)) {
System.out.println(candidate);
}
}
}
private boolean contains(String input, char candidate, int skipIndex) {
for (int i = 0; i < input.length(); ++i) {
if (i == skipIndex) {
continue;
}
if (candidate == input.charAt(i)) {
return true;
}
}
return false;
}
Code is simple but very slow, so use only for short strings. Time complexity is O(n^2).
Using maps
As you iterate through the input, count how many times each character appears. At the end, print only those who appear once only:
public void uniqueCharsBetter(String input) {
Map<Character, Integer> occurences = new HashMap<>();
for (int i = 0; i < input.length(); ++i) {
Character key = Character.valueOf(input.charAt(i));
occurences.put(key, occurences.getOrDefault(key, 0) + 1);
}
occurences.entrySet().forEach(entry -> {
if (entry.getValue().intValue() == 1) {
System.out.println(entry.getKey());
}
});
}
This can be optimized further but it's possible this is enough for your requirements. Time complexity is O(n).
This will give an StringIndexOutOfBoundsException if no unique
char is found:
outer:for(i=0;i<=s1.length(); i++)
replace it with
int i = 0;
outer: for(;i<s1.length(); i++)
There's no need for an inner label, and you need to start the search
from 0, not 1, so replace
inner:for(j=1;j<s1.length(); j++)
with
for(int j=0;j<s1.length(); j++)
You have your test inverted. If the characters at i and j are
the same, you need to continuue with the outer loop. Also, you need to
make sure you don't compare when i==j. So your test changes from:
if (s1.charAt(i) != s1.charAt(j))
break outer;
to
if (i!=j && s1.charAt(i) == s1.charAt(j))
continue outer;
If the inner for loop terminates, i.e. gets to the end of the
string, then the character at i is unique, so we need to break out
of the outer loop.
When you exit the outer loop you need to determine if you found a unique element, which will be the case if i < s1.length().
Putting this all together we get:
String s1= "How are How";
int i = 0;
outer: for(;i<s1.length(); i++)
{
for(int j=0;j<s1.length(); j++)
{
if (i!=j && s1.charAt(i) == s1.charAt(j))
continue outer;
}
break;
}
if(i<s1.length()) System.out.println(s1.charAt(i));
Here a link to the code (IDEOne).
This will print out every character that appears only once in the text.
final String s1 = "How are How";
outer:for(int i = 0; i < s1.length(); i++)
{
for(int j = 0; j < s1.length(); j++)
{
if(s1.charAt(i) == s1.charAt(j) && i != j)
{
continue outer;
}
}
System.out.println(s1.charAt(i);
}
Try this
String s = inputString.toLowerCase();
boolean[] characters = new boolean[26];
for(int i = 0; i < 26; i++)
characters[i] = true;
for(int i = 0; i < s.length(); i++)
{
if(characters[s.charAt(i) - 'a'])
{
System.out.println(s.charAt(i));
characters[s.charAt(i) - 'a'] = false;
}
}
Hope this helps. I have assumed that u treat lowercase and uppercase as same else u can modify accordingly
As I attended interview yesterday for an Organisation as I done every thing is best but I was unable to build logic for a Question called :
String [][]Names={{"John","Pepper"},
{"Smith","Adams"},
{"Katpiller","RhodSon"},
{"BillMark","pearson"}
};
As per the Last Name in the above array need to be sorted without any Collection.sort or CompareTo() or any other Collection API.
My Implementation is :
String str[]=new String[3];
for(int j=0; j<Name.length;j++)
{
for (int i=0 ; i<2; i++)
{
str[i]=Name[j][i];
}
for(int i=0;i<str.length;i++)
{
for(int k=i+1;k<str.length;k++)
{
if(str[i].compareTo(str[k])>0)
{
String temp= str[i];
str[i]=str[k];
str[k]=temp;
}
}
System.out.print(str[i]+ " ");
}
System.out.println();
}
Please Help me out this Hurdle Thanks in Advance
for(int j = Names.length - 2; j >= 0; j--)
{
String name = Names[j][0];
String lastName = Names[j][1];
int i = j + 1;
while(i < Names.length && strCompare(Names[i][1],lastName) < 0)
{
Names[i - 1][0] = Names[i][0];
Names[i - 1][1] = Names[i][1];
i = i + 1;
}
Names[i - 1][0] = name;
Names[i - 1][1] = lastName;
}
for(String[] name : Names)
System.out.print(Arrays.toString(name));
This is an implementation of Insertion Sort. Which sorts in place without the need of other using additional space and it works good on small inputs.
And my own reallyyyyyy bad implementation of a string comparation (String#compareTo) haha.. just to give you an idea on how to do it. (dont know if it works on all cases)
int strCompare(String str1, String str2){
//gets char arrays for both strings.
char[] strChar1 = str1.toUpperCase().toCharArray();
char[] strChar2 = str2.toUpperCase().toCharArray();
//gets max length of the strings
int maxLength = strChar1.length > strChar2.length? strChar1.length : strChar2.length;
//loops character by character to compare them.
for(int i = 0; i < maxLength; i++)
{
//if the length of the char array 1 is less than the index, then its smaller than str2.
if(strChar1.length <= i)
return -1;
//if the length of the char array 2 is less than the index, then its smaller than str1.
if(strChar2.length <= i)
return 1;
//compare characters and return -1 or 1 depending which one is larger.
if(strChar1[i] < strChar2[i]){
return -1;
} else if (strChar1[i] > strChar2[i]){
return 1;
}
}
//return 0 to say that they are equal if the loop doesnt return anything.
return 0;
}
Hope it helps.
Output : [Smith, Adams][John, Pepper][Katpiller, RhodSon][BillMark, pearson]
IMHO there are few questions to ask before trying to solve this problem :
should the sort be case sensitive (I suppose not)
should the sort be optimized for a great number of names (I suppose not)
should the array be sorted in place (I suppose yes)
If the answer to the second question is true, a correct algorithm must be implemented (quick sort, merge sort), and the lowercased name must be pre-calculated, if not a direct bubble sort is enough (O(n2/2) but simpler to implement)
int k;
String[] temp;
for (int i=0; i<len(Names) - 1; i++) {
k = i;
for (j=i + 1; i<len(Names); j++) {
if (Names[k][1].toLowerCase().compareTo(Names[i][1].toLowerCase()) < 0) {
k = j;
}
}
if (k != i) {
temp = Names[i];
Names[i] = Names[k];
Names[k] = temp;
}
}
If String.compareTo is not allowed, it simply has to be re-implemented and I suppose there are no accented chars in last name (é, è, ö, ü, etc.)
int compare(String a, String b) {
int n = (a.size() < b.size()) ? a.size(), b.size();
int delta;
for (int i =0; i<n, i++) {
delta = a.codePointAt(i) < b.codePointAt(j);
if (delta != 0) {
return delta;
}
}
return len(b) - len(a);
}
and the line if (Names[k][1]..compareTo(Names[i][1]...) { has to be rewritten as :
if (compare(Names[k][1].toLowerCase(), Names[i][1].toLowerCase()) < 0) {
This algorithm is really badly optimized, but it was simple to write (and would be simple to test). It is then possible to add as needed :
better sort algo (quick sort)
pre calculation of lowercase last name
management of accented characters.