Duplicate output in Java - java

I'm new here and still learning. Today I learn find duplicate in string. From https://www.javatpoint.com/program-to-find-the-duplicate-characters-in-a-string, I try to learn complete code from web.
When string = "Great responsibility" the output will be:
Duplicate characters in a given string:
r
e
t
s
i
because it has duplicate character r e t s i
And when string is "great" the output is
Duplicate characters in a given string:
The output is blank because there are no duplicate characters, so I give a description "no duplicate" to define no character duplicate and the output goes like this
Duplicate characters in a given string:
no duplicates
no duplicates
no duplicates
no duplicates
no duplicates
This returns too many descriptions.
My code
public class DuplicateCharacters {
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0')
System.out.println(string[i]);
else
System.out.println("no duplicates");
}
}
}
How can I print only one description without repetition? I tried return 0; but it does not work.
Expected output
Duplicate characters in a given string:
no duplicates

Separate the logic for finding duplicates from how you report the findings to the user. Move the logic for finding the duplicates into a method. Pass the results of that output to another method. The main method invokes the first and passes the output to the second.
public static void main(String[] args) {
String s = .... whatever you are searching for duplicates in ....
reportDuplicates(findDuplicates(s)):
}
public static List<Character> findDuplicates(String s) {
... returns a List containing duplicates ...
}
public static void reportDuplicates(List<Character> duplicates) {
if (null == duplicates || duplicates.isEmpty()) {
... report no duplicates ...
} else {
... output the duplicates
}
}

Add a flag to your program that indicates whether there are duplicates or not. And after loop check whether this flag is true or false.
This method would look like below. I commented code where I updated it.
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
// here is flag added
boolean noDuplicates = true;
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0') {
System.out.println(string[i]);
//here is flag updated if duplicates are found
noDuplicates = false;
}
}
//here is flag check
if (noDuplicates) {
System.out.println("no duplicates");
}
}
And btw. Your algorithm has O(n^2) time complexity. You can figure out one that is better ;-)

It's normal your System.out.println("no duplicates"); is in your loop so each time a character is not duplicate you print "no duplicates".
You can defined a boolean that will become true if one duplicate it's found, like this :
public class DuplicateCharacters {
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
Boolean dupCarac = false;
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0'){
System.out.println(string[i]);
dupCarac = true;
}
}
if (!dupCarac){
System.out.println("no duplicates");
}
}
PS: Please put {} on your if and else.

You might find interesting the following approach of how you can do the same, using Streams more efficiently, without iterating through the same String multiple times.
String input = "Great responsibility";
Map<String, Long > map = Arrays.stream(input.split("")) //create a stream for each character in String
.collect((Collectors.groupingBy(item -> item, Collectors.counting()))) //Collect into a map all occurrences
.entrySet().stream().filter(e -> e.getValue() > 1 && !e.getKey().equals(" ")) //filter only duplicate occurrences and not empty spaces
.map(e -> Map.entry(e.getKey(), e.getValue() -1)) // keep count only of duplicate occurrences not total occurrences
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); //gather duplicates in a map
if (map.isEmpty()){
System.out.println("No duplicates found");
} else {
map.forEach((key, value) -> System.out.printf("%s appears %d more times in given string%n", key, value));
}

Related

LeetCode 14. longest common prefix

Question:
Write a function to find the longest common prefix string among an array of strings. If there is no common prefix, return an empty string "".
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
Code:
public class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs==null || strs.length==0)
return "";
for(int i=0;i<strs[0].length();i++) {
char x = strs[0].charAt(i);
for(int j=0;j<strs.length;j++) {
if((strs[j].length()==i)||(strs[j].charAt(i)!=x)) {
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
This is the second solution, but I don't understand the inner loop.
I think if the second element in strs returns a string and ends the for loop, the third element will not have a chance to be compared.
You have to check same position in all of the words and just compare it.
positions
word 0 1 2 3 4 5
=====================
w[0] F L O W E R
w[1] F L O W
w[2] F L I G H T
In Java:
class Main {
public static void main(String[] args) {
String[] words = {"dog","racecar","car"};
String prefix = commonPrefix(words);
System.out.println(prefix);
// return empty string
String[] words2 = {"dog","racecar","car"};
String prefix2 = commonPrefix(words2);
System.out.println(prefix2);
// Return "fl" (2 letters)
}
private static String commonPrefix(String[] words) {
// Common letter counter
int counter = 0;
external:
for (int i = 0; i < words[0].length(); i++) {
// Get letter from first word
char letter = words[0].charAt(i);
// Check rest of the words on that same positions
for (int j = 1; j < words.length; j++) {
// Break when word is shorter or letter is different
if (words[j].length() <= i || letter != words[j].charAt(i)) {
break external;
}
}
// Increase counter, because all of words
// has the same letter (e.g. "E") on the same position (e.g. position "5")
counter++;
}
// Return proper substring
return words[0].substring(0, counter);
}
}
Your first loop is itterating over all chars in the first string of array. Second loop is checking char at i posistion of all strings of array. If characters do not match, or length of string is the same as i it returns substring result.
I think the best way to understand is debug this example.
If the char in the second string is different than the char in the first one, then it is correct to return, since it means that the common prefix ends there. Checking the third and following strings is not necessary.
Basically it returns as soon as it finds a mismatch char.
If we first sort them then it would be very easy we have to only go and compare the first and the last element in the vector present there so,
the code would be like,This is C++ code for the implementation.
class Solution {
public:
string longestCommonPrefix(vector<string>& str) {
int n = str.size();
if(n==0) return "";
string ans = "";
sort(begin(str), end(str));
string a = str[0];
string b = str[n-1];
for(int i=0; i<a.size(); i++){
if(a[i]==b[i]){
ans = ans + a[i];
}
else{
break;
}
}
return ans;
}
};
public class Solution {
public string LongestCommonPrefix(string[] strs) {
if(strs.Length == 0)
{
return string.Empty;
}
var prefix = strs[0];
for(int i=1; i<strs.Length; i++) //always start from 1.index
{
while(!strs[i].StartsWith(prefix))
{
prefix = prefix.Substring(0, prefix.Length-1);
}
}
return prefix;
}
}

recursive function that checks if there are k words that they "charecter equale" to a given word

we will say that two words are "charecter equale" if both of them has the same charecter, for example: baac and abac are charecter equale, I am trying to write a recursive function that gets a string s, a word w and integer k, that checks if there are exactliy k words in the string that they charecter equale to the word, for example: the function should return true for the word abac , the string aabc abdca caba xyz ab and the number k=2.
Ineed help at the recursive part, i.e the function searchMixed, my idea was first the check if the string contain only on word (base case),
the general case is to call the function searchMixed without the first word
public class recursion1 {
public static void main(String[] args) {
boolean result=searchMixed("abac","aabc abdca caba xyz ab",2);
System.out.println("result: "+result);
}
public static boolean searchMixed(String word, String s, int k)
{
if(s.indexOf(' ')==-1 && isEquale(word,s) && k==1)
return true;
if(s.indexOf(' ')==-1 && !isEquale(word,s) && k==1)
return false;
int pos=s.indexOf(' ');
System.out.println("index of"+ s.indexOf(' '));
String first_word=first_word=s.substring(0,pos);
if(isEquale(word, first_word))
searchMixed(word, s.substring(pos+1), k-1);
else
searchMixed(word, s.substring(pos+1), k);
return false;
}
.
//this function works fine, the function checks if two words are charecter equale
public static boolean isEquale(String word, String sub_string)
{
if(word.length()!=sub_string.length())
return false;
char[] s33=new char[sub_string.length()];
char[] sww=new char[word.length()];
for(int i=0;i<sub_string.length();i++)
s33[i]=sub_string.charAt(i);
for(int i=0;i<word.length();i++)
sww[i]=word.charAt(i);
for(int i=0;i<word.length();i++)
{
for(int j=0;j<sub_string.length();j++)
{
if(sww[i]==s33[j])
s33[j]='#';
}
}
for(int i=0;i<sub_string.length();i++)
if(s33[i]!='#')
return false;
return true;
}
}
YourString = YourString.replaceAll("\\s+", " ");
String[] words = YourString.split(" ");
... to split the words.
static int n = 0;
static String keyword = "aabc";
static String[] words = null;
public static void main()
{
n = 0;
// Let's assume you accept 'k' here.
String YourString = "aabc baca hjfg gabac";
words = YourString.split(" ");
rec(words[0]);
if (k <= n)
System.out.println(true);
else
System.out.println(false);
}
static int pos = 0;
public static void rec(String word)
{
boolean flag = true;
word += " ";
if(word.length() != keyword.length() + 1)
{
flag = false;
}
for(int i = 0; i < keyword.length() && flag; i++)
{
for(int j = 0; j < word.length(); j++)
{
if(word.charAt(j) == keyword.charAt(i))
{
word = word.substring(0, j) + word.substring(j+1);
break;
}
}
if(word.equals(" "))
{
n++;
break;
}
}
if(pos + 1 != words.length)
{
rec(words[++pos]);
}
}
Now, let me explain:
In the recursive method rec(String word), a space is added to it at the end of the word being checked (so that substring(j+1) does not go out of bounds)
If the keyword and the checked word are of different lengths, it stops checking, and moves on to '5'.
If the two words are of same lengths, the loop removes a single similar character from the word (That's what word = word.substring(0, j) + word.substring(j+1); does).
At the end of the loop, if all that is remaining of the word is a space, then the counter n increases by 1 and the loop exits.
If there is more than or equal to one more Strings in the array, position of the word being checked in the array increases by 1, and the next word in the array is passed to the rec(String word) method.

Find a character recursively in a String

This is a question in the openDSA interactive learning platform from Virginia Tech:
For function "countChr", write the missing part of the recursive call.
This function should return the number of times that the letter "A"
appears in string "str".
int countChr(String str) {
if (str.length() == 0) {
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
count = 1;
}
return count + <<Missing a Recursive call>>
}
I know how to find a character non recursively in the following way:
public static void main(String [] args) {
String str ="abdcfghaasdfaadftaxvvaacvbtradcea";
int count =0;
for(int n=0; n<= str.length()-1; n++) {
if(str.charAt(n)== 'a')
count++;
}
System.out.print(count);
}
I really don't know how to do the same recursively, especially following the exact pattern given in the question.
To recursively obtain the number of occurrences of the letter 'A', you need to recursively call the function with the substring from index 1 to the end of the string:
public class Example {
public static void main(String [] args) {
String str ="abdcfghaasdfaadftaxvvaacvbtradcea";
System.out.println(countChr(str));
String str2 ="abdcfAhaasdAaadftaxvAAAacvbtradcea";
System.out.println(countChr(str2));
}
static int countChr(String str) {
if (str.length() == 0) {
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
count = 1;
}
return count + countChr(str.substring(1));
}
}
Output:
0
5
Explanation of how this works:
The function is first called with the entire String
If the String length is 0 return 0 because there cannot be an occurrence of 'A'
Initialise a counter to 0, which will be used to count the number of occurrences.
If the first character of the String is 'A' increment the counter
Now to repeat this process, we need to call the same function with the same String, except without the first character. We add the result of this recursive call to the counter, and return it.
This process can be illustrated by adding some prints:
int countChr(String str) {
System.out.println(str);
if (str.length() == 0) {
System.out.println("String has length 0, returning 0");
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
System.out.println("Character is an 'A' adding 1 to the count");
count = 1;
}
return count + countChr(str.substring(1));
}
Output:
abdcfAhaasdAaadftaxvAAAacvbtradcea
bdcfAhaasdAaadftaxvAAAacvbtradcea
dcfAhaasdAaadftaxvAAAacvbtradcea
cfAhaasdAaadftaxvAAAacvbtradcea
fAhaasdAaadftaxvAAAacvbtradcea
AhaasdAaadftaxvAAAacvbtradcea
Character is an 'A' adding 1 to the count
haasdAaadftaxvAAAacvbtradcea
aasdAaadftaxvAAAacvbtradcea
asdAaadftaxvAAAacvbtradcea
sdAaadftaxvAAAacvbtradcea
dAaadftaxvAAAacvbtradcea
AaadftaxvAAAacvbtradcea
Character is an 'A' adding 1 to the count
aadftaxvAAAacvbtradcea
adftaxvAAAacvbtradcea
dftaxvAAAacvbtradcea
ftaxvAAAacvbtradcea
taxvAAAacvbtradcea
axvAAAacvbtradcea
xvAAAacvbtradcea
vAAAacvbtradcea
AAAacvbtradcea
Character is an 'A' adding 1 to the count
AAacvbtradcea
Character is an 'A' adding 1 to the count
Aacvbtradcea
Character is an 'A' adding 1 to the count
acvbtradcea
cvbtradcea
vbtradcea
btradcea
tradcea
radcea
adcea
dcea
cea
ea
a
String has length 0, returning 0
You have to call the countChr method again within the method, with the String up to the last character you called. So if you do this:
return count + countChr( str.substring(1) );
That will give you the desired result.
return count + countChr(str.substring(1, str.length()));
or a more compact form:
return count + countChr(str.substring(1));

implement basic string compression

I am working on question 1.5 from the book Cracking The Coding interview. The problem is to take a string "aabcccccaaa" and turn it into a2b1c5a3.
If the compressed string is not smaller than the original string, then return the original string.
My code is below. I used an ArrayList because I would not know how long the compressed string would be.
My output is [a, 2, b, 1, c, 5], aabc, []. When the program gets to the end of string, it doesn't have a character to compare the last character too.
import java.util.*;
import java.io.*;
public class stringCompression {
public static void main(String[] args) {
String a = "aabcccccaaa";
String b = "aabc";
String v = "aaaa";
check(a);
System.out.println("");
check(b);
System.out.println("");
check(v);
}
public static void check(String g){
ArrayList<Character> c = new ArrayList<Character>();
int count = 1;
int i = 0;
int h = g.length();
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
}
if(c.size() == g.length()){
System.out.print(g);
}
else{
System.out.print(c);
}
}
}
In the last loop you're not adding the result to the array. When j = g.length() still needs to add the current char and count to the array. So you could check the next value of j before increment it:
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
if((j + 1) = g.length()){
c.add(g.charAt(i));
c.add((char)( '0' + count));
}
}
I would use a StringBuilder rather than an ArrayList to build your compressed String. When you start compressing, the first character should already be added to the result. The count of the character will be added once you've encountered a different character. When you've reached the end of the String you should just be appending the remaining count to the result for the last letter.
public static void main(String[] args) throws Exception {
String[] data = new String[] {
"aabcccccaaa",
"aabc",
"aaaa"
};
for (String d : data) {
System.out.println(compress(d));
}
}
public static String compress(String str) {
StringBuilder compressed = new StringBuilder();
// Add first character to compressed result
char currentChar = str.charAt(0);
compressed.append(currentChar);
// Always have a count of 1
int count = 1;
for (int i = 1; i < str.length(); i++) {
char nextChar = str.charAt(i);
if (currentChar == nextChar) {
count++;
} else {
// Append the count of the current character
compressed.append(count);
// Set the current character and count
currentChar = nextChar;
count = 1;
// Append the new current character
compressed.append(currentChar);
}
}
// Append the count of the last character
compressed.append(count);
// If the compressed string is not smaller than the original string, then return the original string
return (compressed.length() < str.length() ? compressed.toString() : str);
}
Results:
a2b1c5a3
aabc
a4
You have two errors:
one that Typo just mentioned, because your last character was not added;
and another one, if the original string is shorter like "abc" with only three chars: "a1b1c1" has six chars (the task is "If the compressed string is not smaller than the original string, then return the original string.")
You have to change your if statement, ask for >= instead of ==
if(c.size() >= g.length()){
System.out.print(g);
} else {
System.out.print(c);
}
Use StringBuilder and then iterate on the input string.
private static string CompressString(string inputString)
{
var count = 1;
var compressedSb = new StringBuilder();
for (var i = 0; i < inputString.Length; i++)
{
// Check if we are at the end
if(i == inputString.Length - 1)
{
compressedSb.Append(inputString[i] + count.ToString());
break;
}
if (inputString[i] == inputString[i + 1])
count++;
else
{
compressedSb.Append(inputString[i] + count.ToString());
count = 1;
}
}
var compressedString = compressedSb.ToString();
return compressedString.Length > inputString.Length ? inputString : compressedString;
}

Searching if String differs by one character

I'm trying to determine if a word entered differs by one character in a text file. I have code that works, but unfortunately only for words that are two characters or less which obviously isn't very useful, and the code itself looks a bit messy. Here's what I have so far:
if(random.length() == word.length()){
for(int i = 0; i < random.length(); i++){
if( (word.charAt(i) == random.charAt(i))){
str += word+"\n";
count++;
}
}
}
With random being the word that was entered by the user, and word being the word to search for in the text file.
If I changed my second if statement to something along the lines of
if( (word.charAt(i) == random.charAt(i)) && (word.charAt(i -1) == random.charAt(i-1)))
and if I change int i to be = 1 instead, I seem to get more of what I'm looking to accomplish, but then my code is searching for only if the first two letters are the same and not if the last two are as well, which it should be doing.
I assume you need a function like this? I just wrote and tested it.
static boolean equals(String word1, String word2, int mistakesAllowed) {
if(word1.equals(word2)) // if word1 equals word2, we can always return true
return true;
if(word1.length() == word2.length()) { // if word1 is as long as word 2
for(int i = 0; i < word1.length(); i++) { // go from first to last character index the words
if(word1.charAt(i) != word2.charAt(i)) { // if this character from word 1 does not equal the character from word 2
mistakesAllowed--; // reduce one mistake allowed
if(mistakesAllowed < 0) { // and if you have more mistakes than allowed
return false; // return false
}
}
}
}
return true;
}
Your code seems to be working to me, you just may be interpreting its results incorrectly.
This may be more obvious:
int count = 0; if(random.length() == word.length()) {
for(int i = 0; i < random.length(); i++)
{
if( (word.charAt(i) != random.charAt(i) ))
{
if(count == 0)
{
System.out.println("Found first difference!");
}
if(count != 0)
{
System.out.println("Strings are more than one letter different!");
}
count++;
}
} }
If you want to check Strings of different lengths, you'll need to delete characters from the longer one until it's the same size as the shorter.
For example:
If String1 = "abc";
and String2 = "zzzabcdef";
You'll need to delete 6 characters from the second string and test for every combination of 6 characters deleted. So you would want to test the strings: def, cde, abc, zab, zza, zzz, zzb, zzc, zzd, zze, zzf, zaf, zae, zad, zac, zab, zza, zzf, zze, ..., ..., on and on, the list is of size 9 choose 6, so it's definitely not optimal or recommended.
You can however, check to see if a string which is one character longer than the other is just the other string with one added letter. To do this, you want a for loop to grab two substring from 0 to i, and from i+1 to the end. This will leave out the ith character, and looping for the size of the string - 1, will give you first the full string, then the string without the first letter, then missing the second letter, and so on. Then test that substring in the same fashion we did above.
Comment if this was not what you're looking for.
EDIT
To see how many words in a file are one letter different than a variable word, you need to loop through the file, getting each word. Then testing if that was string was one letter off. It would be something like this:
String testAgainst = "lookingForWordsOneLetterDifferentThanThisString";
int words = 0;
Scanner scan = new Scanner(fileName);
while(scan.hasNext())
{
String word = scan.next();
if( isOneDifferent(word, testAgainst) )
{
words++;
}
System.out.println("Number of words one letter different: " + words);
}
public boolean isOneDifferent(String word, String testAgainst)
{
if(word.length() != testAgainst.length())
{
return false;
}
int diffs = 0;
for(int i = 0; i < word.length(); i++)
{
if(word.charAt(i) != testAgainst.charAt(i))
{
diffs++;
}
if(diffs > 1)
{
return false;
}
}
if(diffs == 1)
{
return true;
}
else
{
return false;
}
}

Categories