Just brushing up on some simple java stuff. I am trying to check if a string is unique, and I figured the best way would be to do so through recursion. Here is what I have so far, but am getting an out of bounds error, obviously i'm overlooking something pretty simple:
public class uniqueCharString {
public static void main(String [] args){
String a = "abcdefghijk";
System.out.println(unique(a));
}
public static boolean unique(String s){
if(s.substring(1).contains(String.valueOf(s.charAt(0)))){
return false;
}
else return unique(s.substring(1));
}
}
okay so I finished my way of thinking. I got some good advice from you guys, but I wanted to finish my thought process. How does this solution compare to some of the ones where you guys said use a set?
public static boolean unique(String s){
for(int x = 0; x < s.length(); x++){
if(s.substring(x+1).contains(String.valueOf(s.charAt(x)))){
return false;
}
}
return true;
}
The most efficient way to do this is with a Set. Iterate over each character and add them to a set. If the add operation returns false, then the character is already in your set and the String has not-all-unique chars, otherwise all are unique
String s = "some string blah blah blah";
Set<Character> set = new HashSet<>();
for (char c : s.toCharArray())
{
boolean elementFirstAdded = set.add(c);
if (!elementFirstAdded)
//Duplicate
}
//Not duplicate
Like #Kon said, a Set is (probably) more efficient.
However, to use recursion you need to add a termination condition: your function never returns true!
A zero or one length string must be unique (well, unique zero-length is a bit ambiguous...): add this at the top:
if (s.length() <= 1) {
return true;
}
Another way of doing this, in case you're crazy about performance-tuning homework problems :)
public static boolean unique(String s) {
BitSet chars = new BitSet(Character.SIZE);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (chars.get(c)) {
return false;
}
chars.set(c);
}
return true;
}
If you don't need to know what was duplicated I would just throw everything into the Set(), because a Set() cannot contain duplicates. They will never be added to the Set(). And if you just want to know if you had duplicates you can check the length of the String before and then the size of the HashSet() after.
Like this:
String a = "abcdefghijk";
String[] ary = a.split("");
Set<T> mySet = new HashSet<T>(Arrays.asList(words))
if (mySet.size() != ary.length){
//do something
}
Related
The question is as follows:
A pangram is a string that contains every letter of the alphabet. Given a sentence determine whether it is a pangram in the English alphabet. Ignore case. Return either pangram or not pangram as appropriate.
My code works for all input except "qmExzBIJmdELxyOFWv LOCmefk TwPhargKSPEqSxzveiun", for which it returns "not pangram", even though the correct answer is "pangram." Does anybody have any ideas as to why my code is outputting the incorrect solution?
public static String pangrams(String s) {
Hashtable<Character, Integer> alpha = new Hashtable<Character, Integer>();
s = s.toLowerCase();
for (int i = 0; i < s.length()-1; i++){
if (alpha.get(s.charAt(i)) != null){
int value = alpha.get(s.charAt(i));
alpha.put(s.charAt(i), value + 1);
}
else{
alpha.put(s.charAt(i), 1);
}
}
if (alpha.size() != 27){
return "not pangram";
}
else{
return "pangram";
}
}
As per your definition of pangram you might want to consider the following:
Use a Set instead of a Map
As far as I know, English has 26 letters
Make sure you don't mistakenly add digits or symbols to your set
Given the three above statements I would slightly change your code to reflect that. That would, more or less, look something like this:
public static String pangrams(String s) {
Set<Character> alpha = new HashSet<>();
s = s.toLowerCase();
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if (Character.isLetter(c)){
alpha.add(c);
}
}
if (alpha.size() == 26){
return "pangram";
}
return "not pangram";
}
I am trying to generate a String as a hint for the solution to a world solve.
This is what I have for generating the hint, but I am unsure of how to correct these errors. If the guess has the correct character guessed in the right place, the hint displays that character. If it has the letter in the word, it displays a "+" in the respective position. If the letter isn't in the word, a "*" gets returned.
For instance, if the solution to the puzzle is "HARPS", and the guess is "HELLO", the hint will be "H****". Likewise if the guess is "HEART", the hint will be "H*++*".
Also, wordLength is generated from another method that gives the amount of characters in the solution.
public String getHint(String theGuess) {
for (int index = 0; index < wordLength; index++) {
if **(theGuess.charAt(index)** = solution.charAt(index)) {
hint.**setCharAt**(index, theGuess.charAt(index));
} else if **(theGuess.charAt(index)** = solution.indexOf(solution)) {
**hint.setCharAt**(index, "+");
} else {
**hint.setCharAt**(index, "*");
}
}
return hint;
}
Errors are double starred.
For (theGuess.charAt(index) Eclipse is showing the following error message:
The left-hand side of an assignment must be a variable.
For hint.setCharAt, it tells me:
The method setCharAt(int, String) is undefined for the type String.
There are numerous problems in your code that need to be fixed:
= is used when you want to assign a new value to a variable. You want to use == when comparing two values.
setCharAt() is a method for StringBuilder, not String. This simplest solution is to just concatinate your new charater to the String using +=.
If you want to use StringBuilder, the following parts need to be fixed:
The second parameter for setCharAt() should be a character, not a string. You need to change the double quotes around "*" and "+" to single quotes like '*'
setCharAt() tries to replace a character at a specifc index. This will throw an error if the StringBuilder is shorter than the index position you are trying to replace. You can solve this by right away setting your StringBuilder to a string that is the correct length like
hint = new StringBuilder("*****").
Since you are always adding the the end of the builder though, you should really just use append() instead of setCharAt() and you won't need to worry about this index position problem.
(theGuess.charAt(index) == solution.indexOf(solution) does not search the entire solution string to see if it contains the current character. Instead, you can use indexOf() to check if the string contains the character. This link might help: How can I check if a single character appears in a string?
Here is a complete program with the code working:
public class HelloWorld
{
public static void main(String[] args)
{
OtherClass myObject = new OtherClass();
System.out.print(myObject.getHint("HEART"));
}
}
Option 1 - Add to the String using +=:
public class OtherClass
{
private String solution = "HARPS";
private int wordLength = 5;
public String getHint(String theGuess) {
String hint = "";
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hint += theGuess.charAt(index);
} else if (solution.indexOf(theGuess.charAt(index)) > 0) {
hint += "+";
} else {
hint += "*";
}
}
return hint;
}
}
Option 2 - Use StringBuilder:
public class OtherClass
{
private StringBuilder hint;
private String solution = "HARPS";
private int wordLength = 5;
public String getHint(String theGuess) {
hint = new StringBuilder();
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hint.append(theGuess.charAt(index));
} else if(solution.indexOf(theGuess.charAt(index)) > 0) {
hint.append('+');
} else {
hint.append('*');
}
}
return hint.toString();
}
}
This code should work:
public String getHint(String theGuess) {
StringBuilder hintBuilder = new StringBuilder(hint);
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hintBuilder.setCharAt(index, theGuess.charAt(index));
} else if(theGuess.charAt(index) == solution.indexOf(string)) {
hintBuilder.setCharAt(index, "+");
} else {
hintBuilder.setCharAt(index, "*");
}
}
return hintBuilder;
}
Basically, you have to use a 'StringBuilder' because Strings are immutable, meaning that they cannot be altered once they are built.
Also, when comparing two values, use == or === to compare, not =.
UPDATED
I forgot that Strings are immutable in Java, and have updated the code so that it should work.
So here I am stuck with my program where its a simple thing to do. so basically in the search metod is where I have 3 variables as you can see, Char P char T and List pos. Below the method you can see there is a Main where its says what value the char P, char T has and my idea was to make a matching program where I enter a value P and looks if there is a same value in char T. Ones it founds out, it should continue until the value is done. so in the main method after it found out the result, it should give you the index of what position the value is set to.
Now to the problem is, if I give a correct value example P =abc T = abcqweqweabc it would give me a correct, but if I do abcqweqweqwe it will loop all the time and never end which is killing my processor and ram (hehe) and I have been trying to figure out but I can't find the problem. It seems like it should work and I don't understand why it does like it.
public class StringSearch {
public static void search(char[] P, char[] T, List<Integer> pos) {
int i = 0;
int j;
while(i!=P.length){
for (j= 0; j<T.length; j++){
if(P[i] == T[j]) {
i++;
if(i == P.length) {
pos.add((j-(P.length-1)));
i = 0;
if(j==T.length-1) {
i = P.length;
}
}
}
else {
i = 0;
}
}
}
public static void main(String[] args) {
ArrayList<Integer> where = new ArrayList<Integer>();
search("abcx".toCharArray(), "abcdabcxxabctx".toCharArray(), where);
for (int i : where) {
System.out.println(i);
}
}
}
Also please! If you need to know something. Just comment and I will probably answer you in a minute! Feel free to ask question aswell!
EDIT: To give a exactly meaning of what I'm trying to do is that, Our Char T is where the "text" is and char P is where letters are that I want to match P and T. So whenever we find a correct matching between char P and T it should be add in the list which we called pos. which will give us later a result where in the index the matching is the same. like T = qweabcqwe and P = abc. It should give us a result of 4. so what I'm trying to do is to see if there is a matching between those two and where in the position are they the same and if there is, put in the list and then the loop at the main method will tell us where.
EDIT PART 2.3:
public static void search(char[] P, char[] T, List<Integer> pos) {
for (int i=0;i<=T.length-P.length;) {
if (T[i] == P[0]) {
boolean match=true;
for (int j=0;j<P.length;j++) {
if (T[i+j] != P[j]) {
match = false;
break;
}
}
if (match) {
pos.add(i);
i = P.length -1;
}
}
}
}
public static void main(String[] args) {
ArrayList<Integer> where = new ArrayList<Integer>();
search("abcx".toCharArray(), "abcdabcxxabctx".toCharArray(), where);
for (int i : where) {
System.out.println(i);
}
}
}
if there is even one case where
if(P[i] != T[j])
then you set i to 0
else {
i = 0;
and you get stuck in the while loop
BUT basicaly what you are trying to do is something that gives you the same result as indexOf()
Try this :
String Str = new String("qweabcqwe");
String SubStr1 = new String("abc");
System.out.println( Str.indexOf( SubStr1 )); // will print 3
You might want to check out the KMP algorithm explaind in detail using Java here to give you some hints if you want to implement it yourself: http://tekmarathon.com/2013/05/14/algorithm-to-find-substring-in-a-string-kmp-algorithm/
To find the index of every character that is the same at the same position in each array just do:
for (int i=0;i<P.length && i<T.length;i++) {
if (P[i] == T[i]) {
pos.add(i);
}
}
You only need one loop as you are only comparing one value.
If you want to find the location of the substring then you do need a nested loop but it can still be a simple for loop.
for (int i=0;i<=P.length-T.length;i++) { // Can stop when we get to within T length of the end of P
if (P[i] == T[0]) {
boolean match=true;
for (j=0;j<T.length;j++) {
if (P[i+j] != T[j]) {
match = false;
break;
}
}
if (match) {
pos.add(i);
// You might want to add T.length-1 to i here to cause it to skip, it depends if you want to find overlapping results or not. (i.e. searching for bobob in bobobob.
}
}
}
The problem asks to "implement an algorithm to determine if a string has all unique character.
I saw the solution, but don't quite understand.
public boolean isUniqueChars(String str) {
if (str.length() > 256) return false;
boolean[] char_set = new boolean[256];
for (int i = 0; i < str.length(); i++) {
int val = str.charAt(i);
if (char_set[val])
return false;
char_set[val] = true;
}
return true;
}
Do we not use parseInt or (int) converter in front of the code? (Will str.charAt[i] be automatically changed to int?)
What does boolean[] char set=new boolean[256] mean?
Why do we need to set char_set[val]=true?
We can also use HashSet Data structure to determine if string has all unique characters in java.
Set testSet = new HashSet();
for (int i = 0; i < str.length(); i++) {
testSet.add(new Character(str.charAt(i)));
}
if (testSet.size() == str.length()) {
System.out.println("All charcaters are Unique");
} else {
System.out.println("All charcaters are niot unique");
}
See my explanation in the comments, since you only tagged algorithm I'm assuming no language and just address the algorithm itself:
public boolean isUniqueChars(String str){
//more than 256 chars means at least one is not unique
//please see first comment by #Domagoj as to why 256 length
if(str.length()>256) return false;
//keeping an array to see which chars have been used
boolean[] char_set = new boolean[256];
//iterating over the string
for(int i=0; i<str,length;i++){
//not sure what language this is, but let's say it returns an
//int representation of the char
int val=str.charAt(i);
//meaning this has been set to true before, so this char is not unique
if(char_set[val])
//nope, not unique
return false;
//remember this char for next time
char_set[val]=true;
}
//if we reached here, then string is unique
return true;
}
A simple solution would be to convert String to a Set and compare the lengths of corresponding objects. Use java 8:
private static boolean checkUniqueChars(String copy) {
if(copy.length() <= 1) return true;
Set<Character> set = copy.chars()
.mapToObj(e->(char)e).collect(Collectors.toSet());
if (set.size() < copy.length()){
return false;
}
return true;
}
One way you can do is via bits.
Time Complexity : O(N) (You could also argue the time complexity is 0(1), since the for loop will never iterate through more than
128 characters.)
Space Complexity : O(1)
Consider each char as bit(whether its there or not). Example, we need to check if all the chars are unique in "abcada", so if we will check if the bit for a char is already turned on, if yes then we return false otherwise set the bit there.
Now how we do it ? All the chars can be represented as numbers and then bits. We are gonna use "set bit" and "get bit" approach.
We will assume, in the below code, that the string only uses the lowercase letters a through z.
public static boolean isUniqueChars(String str) {
int mask = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a'; // you will get value as 0, 1, 2.. consider these as the positions inside your mask which you need to check if the bit is set or not
if ((mask & (1 << val)) > 0) return false; // Check if the bit is already set
mask |= (1 << val); // Set bit
}
return true;
}
To understand bit manipulation , you can refer
https://www.hackerearth.com/practice/notes/bit-manipulation/
https://snook.ca/archives/javascript/creative-use-bitwise-operators
It took me a while to understand bits but once I did, it was eye opening. You can solve so many problems using bits and provides most optimal solutions.
Think about how you would do this with a paper and pencil.
Write out the alphabet once.
Then go through your string character by character.
When you reach a character cross it out of your alphabet.
If you go to cross out a character and find that it has already been crossed out, then you know the character appeared previously in your string and you can then stop.
That's essentially what the code you posted does, using an array. The operation completes in O(N) time with O(K) extra space (where K is the number of keys you have).
If your input had a large number of elements or you could not know what they were ahead of time, you could use a hash table to keep track of which elements have already been seen. This again takes O(N) time with O(cK) extra space, where K is the number of keys and c is some value greater than 1.
But hash tables can take up quite a bit of space. There's another way to do this. Sort your array, which will take O(N log N) time but which requires no extra space. Then walk through the array checking to see if any two neighbouring characters are the same. If so, you have a duplicate.
You could see the detailed explanation in my blogpost here:
Check if string has all unique characters
The simplest solution is to make a loop through all characters, use hashMap and to put each character into the hashmap table, and before this check if the character is already there. If the character is already there, it's not unique.
public class UniqueString {
public static void main(String[] args) {
String input = "tes";
Map<String, Integer> map = new HashMap<String, Integer>();
for (int i = 0; i < input.length(); i++) {
if (!map.containsKey(Character.toString(input.charAt(i)))) {
map.put(Character.toString(input.charAt(i)), 1);
} else {
System.out.println("String has duplicate char");
break;
}
}
}
}
Java SE 9
You can simply match the length of the string with the count of distinct elements. In order to get the IntStream of all characters, you can use String#chars on which you can apply Stream#distinct to get the Stream of unique elements. Make sure to convert the string to a single case (upper/lower) otherwise the function, Stream#distinct will fail to count the same character in different cases (e.g. I and i) as one.
Demo:
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Test
Stream.of(
"Hello",
"Hi",
"Bye",
"India"
).forEach(s -> System.out.println(s + " => " + hasUniqueChars(s)));
}
static boolean hasUniqueChars(String str) {
return str.toLowerCase().chars().distinct().count() == str.length();
}
}
Output:
Hello => false
Hi => true
Bye => true
India => false
Java SE 8
static boolean hasUniqueChars(String str) {
return Arrays.stream(str.toLowerCase().split("")).distinct().count() == str.length();
}
For best performance, you should use a Set, and add the characters of the string to the set. If the set.add(...) method returns false, it means that the given character has been seen before, so you return false, otherwise you return true after adding all the characters.
For the simple solution, use Set<Character>:
public static boolean allUniqueCharacters(String input) {
Set<Character> unique = new HashSet<>();
for (int i = 0; i < input.length(); i++)
if (! unique.add(input.charAt(i)))
return false;
return true;
}
That will however not handle Unicode characters outside the BMP, like Emojis, so we might want to change the set to use Unicode Code Points:
public static boolean allUniqueCodePoints(String input) {
Set<Integer> unique = new HashSet<>();
return input.codePoints().noneMatch(cp -> ! unique.add(cp));
}
However, even Code Points do not represent "characters" as we humans think of them. For that we need to process Grapheme Clusters:
public static boolean allUniqueClusters(String input) {
BreakIterator breakIterator = BreakIterator.getCharacterInstance(Locale.US);
breakIterator.setText(input);
Set<String> unique = new HashSet<>();
for (int start = 0, end; (end = breakIterator.next()) != BreakIterator.DONE; start = end)
if (! unique.add(input.substring(start, end)))
return false;
return true;
}
Or with Java 9+:
public static boolean allUniqueClusters(String input) {
Set<String> unique = new HashSet<>();
return Pattern.compile("\\X").matcher(input).results()
.noneMatch(m -> ! unique.add(m.group()));
}
In JS,
const isStringUnique = str => {
if(str){
let obj = {}
for(let char of str){
obj[char] ? obj[char]++ : obj[char]=1;
}
for(let char of str){
if(obj[char] > 1)
return false;
}
return true;
}
return true;
}
public class CheckStringUniqueChars {
public static boolean checkUnique(String str) {
int i=0,j=str.length()-1;
while(i<j) {
if(str.charAt(i) == str.charAt(j)) {
return false;
}
i++;
j--;
}
return true;
}
}
The Problem is simple Find "ABC" in "ABCDSGDABCSAGAABCCCCAAABAABC" without using String.split("ABC")
Here is the solution I propose, I'm looking for any solutions that might be better than this one.
public static void main(String[] args) {
String haystack = "ABCDSGDABCSAGAABCCCCAAABAABC";
String needle = "ABC";
char [] needl = needle.toCharArray();
int needleLen = needle.length();
int found=0;
char hay[] = haystack.toCharArray();
int index =0;
int chMatched =0;
for (int i=0; i<hay.length; i++){
if (index >= needleLen || chMatched==0)
index=0;
System.out.print("\nchar-->"+hay[i] + ", with->"+needl[index]);
if(hay[i] == needl[index]){
chMatched++;
System.out.println(", matched");
}else {
chMatched=0;
index=0;
if(hay[i] == needl[index]){
chMatched++;
System.out.print("\nchar->"+hay[i] + ", with->"+needl[index]);
System.out.print(", matched");
}else
continue;
}
if(chMatched == needleLen){
found++;
System.out.println("found. Total ->"+found);
}
index++;
}
System.out.println("Result Found-->"+found);
}
It took me a while creating this one. Can someone suggest a better solution (if any)
P.S. Drop the sysouts if they look messy to you.
How about:
boolean found = haystack.indexOf("ABC") >= 0;
**Edit - The question asks for number of occurences, so here's a modified version of the above:
public static void main(String[] args)
{
String needle = "ABC";
String haystack = "ABCDSGDABCSAGAABCCCCAAABAABC";
int numberOfOccurences = 0;
int index = haystack.indexOf(needle);
while (index != -1)
{
numberOfOccurences++;
haystack = haystack.substring(index+needle.length());
index = haystack.indexOf(needle);
}
System.out.println("" + numberOfOccurences);
}
If you're looking for an algorithm, google for "Boyer-Moore". You can do this in sub-linear time.
edit to clarify and hopefully make all the purists happy: the time bound on Boyer-Moore is, formally speaking, linear. However the effective performance is often such that you do many fewer comparisons than you would with a simpler approach, and in particular you can often skip through the "haystack" string without having to check each character.
You say your challenge is to find ABC within a string. If all you need is to know if ABC exists within the string, a simple indexOf() test will suffice.
If you need to know the number of occurrences, as your posted code tries to find, a simple approach would be to use a regex:
public static int countOccurrences(string haystack, string regexToFind) {
Pattern p = Pattern.compile(regexToFind);
Matcher m = p.matcher(haystack); // get a matcher object
int count = 0;
while(m.find()) {
count++;
}
return count;
}
Have a look at http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
public class NeedleCount
{
public static void main(String[] args)
{
String s="AVBVDABCHJHDFABCJKHKHF",ned="ABC";
int nedIndex=-1,count=0,totalNed=0;
for(int i=0;i<s.length();i++)
{
if(i>ned.length()-1)
nedIndex++;
else
nedIndex=i;
if(s.charAt(i)==ned.charAt(nedIndex))
count++;
else
{
nedIndex=0;
count=0;
if(s.charAt(i)==ned.charAt(nedIndex))
count++;
else
nedIndex=-1;
}
if(count==ned.length())
{
nedIndex=-1;
count=0;
totalNed++;
System.out.println(totalNed+" needle found at index="+(i-(ned.length()-1)));
}
}
System.out.print("Total Ned="+totalNed);
}
}
Asked by others, better in what sense? A regexp based solution will be the most concise and readable (:-) ). Boyer-Moore (http://en.wikipedia.org/wiki/Boyer–Moore_string_search_algorithm) will be the most efficient in terms of time (O(N)).
If you don't mind implementing a new datastructure as replacement for strings, have a look at Tries: http://c2.com/cgi/wiki?StringTrie or http://en.wikipedia.org/wiki/Trie
If you don't look for a regular expression but an exact match they should provide the fastest solution (proportional to length of search string).
public class FindNeedleInHaystack {
String hayStack="ASDVKDBGKBCDGFLBJADLBCNFVKVBCDXKBXCVJXBCVKFALDKBJAFFXBCD";
String needle="BCD";
boolean flag=false;
public void findNeedle() {
//Below for loop iterates the string by each character till reaches max length
for(int i=0;i<hayStack.length();i++) {
//When i=n (0,1,2... ) then we are at nth character of hayStack. Let's start comparing nth char of hayStach with first char of needle
if(hayStack.charAt(i)==needle.charAt(0)) {
//if condition return true, we reach forloop which iterates needle by lenghth.
//Now needle(BCD) first char is 'B' and nth char of hayStack is 'B'. Then let's compare remaining characters of needle with haystack using below loop.
for(int j=0;j<needle.length();j++) {
//for example at i=9 is 'B', i+j is i+0,i+1,i+2...
//if condition return true, loop continues or else it will break and goes to i+1
if(hayStack.charAt(i+j)==needle.charAt(j)) {
flag=true;
} else {
flag=false;
break;
}
}
if(flag) {
System.out.print(i+" ");
}
}
}
}
}
Below code will perform exactly O(n) complexity because we are looping n chars of haystack. If you want to capture start and end index's of needle uncomment below commented code. Solution is around playing with characters and no Java String functions (Pattern matching, IndexOf, substring etc.,) are used as they may bring extra space/time complexity
char[] needleArray = needle.toCharArray();
char[] hayStackArray = hayStack.toCharArray();
//java.util.LinkedList<Pair<Integer,Integer>> indexList = new LinkedList<>();
int head;
int tail = 0;
int needleCount = 0;
while(tail<hayStackArray.length){
head = tail;
boolean proceed = false;
for(int j=0;j<needleArray.length;j++){
if(head+j<hayStackArray.length && hayStackArray[head+j]==needleArray[j]){
tail = head+j;
proceed = true;
}else{
proceed = false;
break;
}
}
if(proceed){
// indexList.add(new Pair<>(head,tail));
needleCount++;
}
++tail;
}
System.out.println(needleCount);
//System.out.println(indexList);