Determine if a string has all unique characters - java

This is from cracking the Coding Interview Book
The Questions Implement an algorithm to determine if a string has all unique characters. What if
you can not use additional data structures?
I am wondering what is happening in the if statement below? can anyone explain it to me ?
I have left my understanding of the code in the comments.Please correct me if i am wrong
public class Uniquechar2 {
public static boolean isUniqueChars2(String str) {
// Create a new boolean array of 256 characters to account for basic a cii and extended ascii characters
boolean[] charSet = new boolean[256];
//iterate through the array
for (int i = 0; i < str.length(); i++) {
// Assign the value of current value of the iterator i to int variable val.So if we are looping through "hello" at i = 0 the int value of 'h' will be assigned to val.Is that correct?
int val = str.charAt(i);
// Continuing from the example of loping throughout the string "hello" the if statement will see if 'h' is in charSet and since it will be there it will return false /is that what is happening?
if (charSet[val]) {
return false;
}
// Is this the else statement? true will be assigned to charSet[h] in this case
charSet[val] = true;
}
// I dont understand why we are returning true at the end ?
return true;
}

public static boolean isUniqueChars2(String str) {
// Create a new boolean array of 256 characters to account for basic ascii and extended ascii characters
boolean[] char_set = new boolean[256];
// Iterate through the string we are testing
for (int i = 0; i < str.length(); i++) {
// Get the numerical (ascii) value of the character in the `str` at position `i`.
int val = str.charAt(i);
// If char_set[val] has been set, that means that this character was already present in the string. (so in string 'hello' this would be true for the second 'l')
if (char_set[val]) {
return false;
}
// If the character hasn't been encountered yet (otherwise we would have returned false above), then mark this particular character as present in the string
char_set[val] = true;
}
// If the function hasn't returned false after going through the entire string that means that each character is unique - thus returning true
return true;
}

Is this the else statement
No, otherwise there would be an else in the code. But in this case, else is unnecessary since, if char_set[val] is true, the execution of the method stops immediately, due to the return false; instruction.
I dont understand why we are returning true at the end ?
Because since no duplicate has been found, the method must return true to indicate that the string is composed of unique characters. If a duplicate had been found, the method would have returned already in
if (char_set[val]) {
return false;
}

I would just use regex, which requires only one line of code:
public static boolean isUniqueChars(String str) {
return str.matches("((.)(?!.*?\\2))*");
}
Breaking down the regex:
(.) captures every character
(?!.*?\\2) is a negative look ahead for a back reference to the captured group
Together, these mean "a character that does not reappear after itself"
(...)* around the above means 0-n of them
Altogether, it means "comprised of characters that do do reappear later in the string", ie unique characters.

One-line solution without any extra data structure:
str.chars().distinct().count() == (int)str.length();

Related

How can I test if a String contains the characters of a particular string?

I have a String with value
String rest="bac";
I have another String with value
String str="baack";
If i use
str.contains(rest);
it returns false. But i want the output to be true. As "baack" contains all the letters from string rest
Is it possible to do so? With or without this method?
Unfortunately, there is no standard method doing this, as far as I know.
If what you want is to check that the second string contains at least once every character of the first string, then you can check each character one by one with the following test:
boolean result = true;
for (char c : test.toCharArray()) {
result &= str.indexOf(c) > -1;
}
return result;
Or alternatively:
for (char c : test.toCharArray()) {
if (str.indexOf(c) == -1) {
return false;
}
}
return true;
It might not be optimal, but it works and it is simple to read.
Since the order is not important, your question turns to be whether the first set of character contains the second set of character.
// Initial the sets
Set<char> bigSet = new HashSet<char>(Arrays.asList(str));
Set<char> smallSet = new HashSet<char>(Arrays.asList(rest));
for (char c : smallSet) {
if(!bigSet.contains(c)){
return false;
}
}
return true;
Here is another way to make sure all characters from one string are in the second string. It is a lengthy way but it is one of the very basic ways to work with characters from String in java. I know it is not optimal but it serves the purpose.
String rest="bac";
String str="baack";
char[] strChar = str.toCharArray();
char[] restChar = rest.toCharArray();
int count = 0;
for(int i=0;i<restChar.length;i++){
for(int j=0;j<strChar.length; j++){
if(restChar[i] == strChar[j]){
count++;
}
}
}
if(count>=restChar.length){
System.out.println("All the characters from: "+rest+" are in: "+str);
}

String index out of range: -1 error with loops

I checked old topics with this problem and couldn't fix it.
This method is meant to compare two strings, and if every letter/character of the first string is found in the second string (not necessarily vice versa), then the method should return "true" (even if the second string has extra letters).
My idea is to check the letter at every index of the first string, see if it's in the second string, and if it is, delete that letter in both strings. When the first string runs out of letters (length equals zero) then the boolean should return true.
I think my loops or substring reaches out of range at some point.
public boolean isFound(String first, String second) {
StringBuilder sb1 = new StringBuilder(first);
StringBuilder sb2 = new StringBuilder(second);
first.toCharArray();
second.toCharArray();
for (int i = 0; i < first.length(); i++) {
int k = (first.substring(i, i + 1)).indexOf(second, i);
if (sb1.length() > 0) {
sb1.deleteCharAt(k);
sb2.deleteCharAt(k);
}
}
if (sb1.length() == 0) {
return true;
} else {
return false;
}
}
Ex: "at" and "tack" should return true, "tree" and "ere" should return false.
EDIT
After reviewing the comments, my new code is now this. It always returns false, though even with "tree" and "tree".
public boolean isFound(String first, String second){
StringBuilder sb2 = new StringBuilder(second);
for(int i=0;i<first.length();i++){
int k = sb2.indexOf(first,i);
if (k==-1)
return false;
else sb2.deleteCharAt(k);
}
return true;
}
You have a number of problems in your code.
You only need one StringBuilder version, that of second
The calls to toCharArray() are superfluous
You should not search for each character of first in second but in the mutable version of it sb2.
You are using indexOf wrong. This method should be called on the StringBuilder object to search for the first argument, you have it swapped.
The pseudocode that you can use is
isSuperAnagram(String first, String second) {
sb = StringBuilder(second)
for all chars in first {
k = search index of current char of first in sb
if(k == -1) // char is not in sb
return false
else
remove char at index k from sb
}
return true
}
please review your algorithm and code/usage of APIs
` first.toCharArray();`
second.toCharArray();
wont convert first,second to array, this API would return a character array.
(first.substring(i,i+1)).indexOf(second,i); will search the whole substring2 in first.substring.
review the algo/code correct this accordingly.please take care of all the edge/corner cases.
ideal method will be to use a hashmap.(on cost of extra space)
There is simple logic you can implement it your code
for(int i=0;i<sb1.length;i++)
{
for(int j=0;j<sb2.length;j++)
{
if(sb1.[i]==sb2.[j])
{
count++;
break;
}
if(count>=sb1.length)
{
System.out.print("match");
}
}
}
if you want more condition then post it below my post i wrote for only your follow example
Ex: "at" and "tack" should return true, "tree" and "ere" should return false.

Making a substring out of a line read from file

So I am trying to read through a .txt file and find all instances of html tags, push opening tags to a stack, and then pop it when I find a closing tag. Right now I am getting String out of bounds exception for the following line:
if(scan.next().startsWith("</", 1))
{
toCompare = scan.next().substring(scan.next().indexOf('<'+2), scan.next().indexOf('>'));
tempString = htmlTag.pop();
if(!tempString.equals(toCompare))
{
isBalanced = false;
}
}
else if(scan.next().startsWith("<"))
{
tempString = scan.next().substring(scan.next().indexOf('<'+1), scan.next().indexOf('>'));
htmlTag.push(tempString);
}
It is telling me that the index of the last letter is -1. The problem I can think of is that all of the scan.next() calls are moving onto the next string. If this is the case, do I need to just write
toCompare = scan.next()
and then so my comparisons?
You have two major problems in your code:
you're calling scan.next() way too much and as you expect, this will move the scanner to the next token. Therefore, the last one will be lost and gone.
.indexOf('<'+2) doesn't return the index of '<' and adds 2 to that position, it will return the index of '>', because you're adding 2 to the int value of char < (60; > has 62). Your problem with index -1 ("It is telling me that the index of the last letter is -1.") comes from this call: .indexOf('<'+1) this looks for char '=' and if your string doesn't contain that, then it will return -1. A call for #substring(int, int) will fail if you pass -1 as the starting position.
I suggest the following two methods to extract the value between '<' and '>':
public String extract(final String str) {
if (str.startsWith("</")) {
return extract(str, 2);
} else if (str.startsWith("<")) {
return extract(str, 1);
}
return str;
}
private String extract(final String str, final int offset) {
return str.substring(str.indexOf('<') + offset, str.lastIndexOf('>'));
}
As you can see, the first method evaluates the correct offset for the second method to cut off either "offset. Mind that I wrote str.indexOf('<') + offset which behaves differently, than your str.indexOf('<' + offset).
To fix your first problem, store the result of scan.next() and replace all occurrences with that temporary string:
final String token = scan.next();
if (token.startsWith("</")) { // removed the second argument
final String currentTag = extract(token); // renamed variable
final String lastTag = htmlTag.pop(); // introduced a new temporary variable
if (!lastTag.equals(currentTag)) {
isBalanced = false;
}
}
else if (token.startsWith("<")) {
htmlTag.push(extract(token)); // no need for a variable here
}
I guess this should help you to fix your problems. You can also improve that code a little bit more, for example try to avoid calling #startsWith("</") and #startsWith("<") twice.

How to check if there are double letters in a 4 digit code in Java

The above question might seems vague but it's actually a very simple idea which i can't seem to figure out.
It basically is a 4 digit letter code containing letters from A to F for example: ABDF, BAAF, DBAF etc.
Now I'm trying to do some post input-handling where it must become impossible to enter a letter that is already in the code cause it has to be a unique 4 digit code with no repeating letter. I've been trying to make it work but none of my code seems to work so i'm back to scratch asking you guys for help :)
I hope this is somewhat clear otherwise i'll be happy to clear it up.
Thanks in advance.
Kind of a pseudocode but it would work.
String uniquePass="";
while(uniquePass.length<4){
String userInput=getUserInputChar()
if(uniquePass.contains(userInput))
rejectInputAndNotifyUser
else
uniquePass=uniquePass+userInput
}
public static boolean hasDuplicateChars(String string) {
Set<Character> chars = new HashSet<Character>();
for (char c : string.toCharArray()) {
if (!chars.add(c)) return false;
}
return true;
}
Set is a collection that contains no duplicate elements. We will use add method which returns true if this set did not already contain the specified element.
hasDuplicateChars functions iterates over characters in the input string using toCharArray function and for loop; each character is added to the chars set which is initially empty. If add method returns false it means that we have already encountered same character before. So we return false from our function.
Otherwise input is valid and method returns true.
using this function you'll be able to see if the string contains unique characters
public static boolean checkForUnique(String str){
boolean containsUnique = false;
for(char c : str.toCharArray()){
if(str.indexOf(c) == str.lastIndexOf(c)){
containsUnique = true;
} else {
containsUnique = false;
}
}
return containsUnique;
}
Update:
This will be ran everytime a user enters a character and if it fails, this would mean there is a duplicate. You have the choice of discarding that input or showing an error.
If you're validating the complete input, you can lean on the set semantics, and a few tricks
String s = "ABAF";
int count = new HashSet<>(Arrays.asList(s.split(""))).size();
if (count - 1 == 4) {
System.out.println("All ok");
} else {
System.out.println("Repeated letters");
}
the split("") will split the string to a an array like {"","A", "B", "A", "F"}.
The new HashSet<>(Arrays.asList(s.split(""))) will create a Set with String elements, and as the Set will bounce back the elements already contained, the size of the set for e.g. "AAAF" will be 3 (it'll contain the "", "A" and "F"). This way you can use the size of the set to figure out if all letters of a String are unique
If its while typing you'll than the solution depends on the input method, but you can have something like (pseudo stuff)
if (pass.contains(letter)) {
breakAndNotifyUser();
} else {
pass+=letter;
}

Finding Palindromes in a word list

I'm working on a program for Java on how to find a list of palindromes that are embedded in a word list file. I'm in an intro to Java class so any sort of help or guidance will be greatly appreciated!
Here is the code I have so far:
import java.util.Scanner;
import java.io.File;
class Palindromes {
public static void main(String[] args) throws Exception {
String pathname = "/users/abrick/resources/american-english-insane";
File dictionary = new File(pathname);
Scanner reader = new Scanner(dictionary);
while (reader.hasNext()) {
String word = reader.nextLine();
for (int i = 0; i > word.length(); i++) {
if (word.charAt(word.indexOf(i) == word.charAt(word.indexOf(i)) - 1) {
System.out.println(word);
}
}
}
}
}
There are 3 words that are 7 letters or longer in the list that I am importing.
You have a few ways to solve this problem.
A word is considered a palindrome if:
It can be read the same way backwards as forwards.
The first element is the same as the last element, up until we reach the middle.
Half of the word is the same as the other half, reversed.
A word of length 1 is trivially a palindrome.
Ultimately, your method isn't doing much of that. In fact, you're not doing any validation at all - you're only printing the word if the first and last character match.
Here's a proposal: Let's read each end of the String, and see if it's a palindrome. We have to take into account the case that it could potentially be empty, or be of length 1. We also want to get rid of any white space in the string, as that can cause errors on validation - we use replaceAll("\\s", "") to solve that.
public boolean isPalindrome(String theString) {
if(theString.length() == 0) {
throw new IllegalStateException("I wouldn't expect a word to be zero-length");
}
if(theString.length() == 1) {
return true;
} else {
char[] wordArr = theString.replaceAll("\\s", "").toLowerCase().toCharArray();
for(int i = 0, j = wordArr.length - 1; i < wordArr.length / 2; i++, j--) {
if(wordArr[i] != wordArr[j]) {
return false;
}
}
return true;
}
}
I'm assuming that you're reading in strings. Use string.toCharArray() to convert each string to a char[]. Iterate through the character array using a for loop as follows: on iteration 1, if the first character is equal to the last character, then proceed to the next iteration, else return false. On iteration 2, if the second character is equal to the second-to-last character then proceed to the next iteration, else return false. And so on, until you reach the middle of the string, at which point you return true. Be careful of off-by-one errors; some strings will have an even length, some will have an odd length.
If your palindrome checker is case insensitive, then use string.toLowerCase().toCharArray() to preprocess the character array.
You can use string.charAt(i) instead of string.toCharArray() in the for loop; in this case, if the palindrome checker is case insensitive then preprocess the string with string = string.toLowerCase()
Let's break the problem down: In the end, you are checking if the reverse of the word is equal to the word. I'm going to assume you have all of the words stored in an array called wordArray[].
I have some code for getting the reverse of the word (copied from here):
public String reverse(String str) {
if ((null == str) || (str.length() <= 1)) {
return str;
}
return new StringBuffer(str).reverse().toString();
}
So, now we just need to call that on every word. So:
for(int count = 0; count<wordArray.length;count++) {
String currentWord = wordArray[count];
if(currentWord.equals(reverse(currentWord)) {
//it's a palendrome, do something
}
}
Since this is homework, i'll not supply you with code.
When i code, the first thing i do is take a step back and ask myself,
"what am i trying to get the computer to do that i would do myself?"
Ok, so you've got this huuuuge string. Probably something like this: "lkasjdfkajsdf adda aksdjfkasdjf ghhg kajsdfkajsdf oopoo"
etc..
A string's length will either be odd or even. So, first, check that.
The odd/even will be used to figure out how many letters to read in.
If the word is odd, read in ((length-1)/2) characters.
if even (length/2) characters.
Then, compare those characters to the last characters. Notice that you'll need to skip the middle character for an odd-lengthed string.
Instead of what you have above, which checks the 1st and 2nd, then 2nd and 3rd, then 3rd and fourth characters, check from the front and back inwards, like so.
while (reader.hasNext()) {
String word = reader.nextLine();
boolean checker = true;
for (int i = 0; i < word.length(); i++) {
if(word.length()<2){return;}
if (word.charAt(i) != word.charAt(word.length()-i) {
checker = false;
}
}
if(checker == true)
{System.out.println(word);}
}

Categories

Resources