What happens when if statement goes true (in this code)? - java

There is a problem in codingbat.com which you're supposed to remove "yak" substring from the original string. and they provided a solution for that which I can't understand what happens when the if statement goes true!
public String stringYak(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Look for i starting a "yak" -- advance i in that case
if (i+2<str.length() && str.charAt(i)=='y' && str.charAt(i+2)=='k') {
i = i + 2;
} else { // Otherwise do the normal append
result = result + str.charAt(i);
}
}
return result;
}
It just adds up i by 2 and what? When it appends to the result string?
Link of the problem:
https://codingbat.com/prob/p126212

The provided solution checks for all single characters in the input string. For this i is the current index of the checked character. When the current char is not a y and also the (i+2) character is not a k the current char index is advanced by 1 position.
Example:
yakpak
012345
i
So here in the first iteration the char at i is y and i+2 is a k, so we have to skip 3 chars. Keep in mind i is advanced by 1 everytime. So i has to be increased by 2 more. After this iteration i is here
yakpak
012345
i
So now the current char is no y and this char will get added to the result string.
But it's even simpler in Java as this functionality is build in with regex:
public String stringYak(String str) {
return str.replaceAll("y.k","");
}
The . means every char.

If i is pointing at a y and there is as k two positions down, then it wants to skip the full y*k substring, so it add 2 to i so i now refers to the k. WHen then loop continues, i++ will skip past the k, so in effect, the entire 3-letter y*k substring has been skipped.

Related

Length of the Longest Common Substring without repeating characters

Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
I have came up with a solution that worked, but failed for several test cases. I then found a better solution and I rewrote it to try and understand it. The solution below works flawlessly, but after about 2 hours of battling with this thing, I still can not understand why this particular line of code works.
import java.util.*;
import java.math.*;
public class Solution {
public int lengthOfLongestSubstring(String str) {
if(str.length() == 0)
return 0;
HashMap<Character,Integer> map = new HashMap<>();
int startingIndexOfLongestSubstring = 0;
int max = 0;
for(int i = 0; i < str.length(); i++){
char currentChar = str.charAt(i);
if(map.containsKey(currentChar))
startingIndexOfLongestSubstring = Math.max(startingIndexOfLongestSubstring, map.get(currentChar) + 1);
map.put(currentChar, i);
max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
}//End of loop
return max;
}
}
The line in question is max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
I don't understand why this works. We're taking the max between our previous max, and the difference between our current index and the starting index of what is currently the longest substring and then adding 1. I know that the code is getting the difference between our current index, and the startingIndexOfSubstring, but I can't conceptualize WHY it works to give us the intended result; Can someone please explain this step to me, particularly WHY it works?
I'm usually bad at explaining, let me give it a shot by considering an example.
String is "wcabcdeghi".
Forget the code for a minute and assume we're trying to come up with a logic.
We start from w and keep going until we reach c -> a -> b -> c.
We need to stop at this point because "c" is repeating. So we need a map to store if a character is repeated. (In code : map.put(currentChar, i); )
Now that we know if a character is repeated, We need to know what is the max. length so far. (In code -) max
Now we know there is no point in keeping track of count of first 2 variables w->c. This is because including this, we already got the Max. value. So from next iteration onwards we need to check length only from a -> b -> soon.
Lets have a variable (In code -)startingIndexOfLongestSubstring to keep track of this. (This should've been named startingIndexOfNonRepetativeCharacter, then again I'm bad with naming as well).
Now we again keep continuing, but wait we still haven't finalized on how to keep track of sub-string that we're currently parsing. (i.e., from abcd...)
Coming to think of it, all I need is the position of where "a" was present (which is startingIndexOfNonRepetativeCharacter) so to know the length of current sub-string all I need to do is (In code -)i - startingIndexOfLongestSubstring + 1 (current character position - The non-repetative character length + (subtraction doesn't do inclusive of both sides so adding 1). Lets call this currentLength
But wait, what are we going to do with this count. Every time we find a new variable we need to check if this currentLength can break our max.
So (In code -) max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
Now we've covered most of the statements that we need and according to our logic everytime we encounter a variable which was already present all we need is startingIndexOfLongestSubstring = map.get(currentChar). So why are we doing a Max?
Consider a scenario where String is "wcabcdewghi". when we start processing our new counter as a -> b -> c -> d -> e -> w At this point our logic checks if this character was present previously or not. Since its present, it starts the count from index "1". Which totally messes up the whole count. So We need to make sure, the next index we take from map is always greater than the starting point of our count(i.e., select a character from the map only if the character occurs before startingIndexOfLongestSubstring).
Hope I've answered all lines in the code and mainly If the explanation was understandable.
Because
i - startingIndexOfLongestSubstring + 1
is amount of characters between i and startingIndexOfLongestSubstring indexes. For example how many characters between position 2 and 3? 3-2=1 but we have 2 characters: on position 2 and position 3.
I've described every action in the code:
public class Solution {
public int lengthOfLongestSubstring(String str) {
if(str.length() == 0)
return 0;
HashMap<Character,Integer> map = new HashMap<>();
int startingIndexOfLongestSubstring = 0;
int max = 0;
// loop over all characters in the string
for(int i = 0; i < str.length(); i++){
// get character at position i
char currentChar = str.charAt(i);
// if we already met this character
if(map.containsKey(currentChar))
// then get maximum of previous 'startingIndexOfLongestSubstring' and
// map.get(currentChar) + 1 (it is last occurrence of the current character in our word before plus 1)
// "plus 1" - it is because we should start count from the next character because our current character
// is the same
startingIndexOfLongestSubstring = Math.max(startingIndexOfLongestSubstring, map.get(currentChar) + 1);
// save position of the current character in the map. If map already has some value for current character
// then it will override (we don't want to know previous positions of the character)
map.put(currentChar, i);
// get maximum between 'max' (candidate for return value) and such value for current character
max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
}//End of loop
return max;
}
}

Inserting letters into a string at every possible spot [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am looking to insert a single letter one by one into every possible index of a string.
For example the string ry
Would go "ary" "bry" "cry" ... "zry" ... "ray" "rby" .... "rzy" ... "rya" "ryb"
I am not sure how to begin, any help?
Try this
System.out.println("originaltext".replaceAll(".{1}","$0ry"));
The above is using the String replaceAll(String regex, String replacement) method - "Replaces each substring of this string that matches the given regular expression with the given replacement."
".{1}" - The regular expression used to find exactly one occurrence({1}) of any character(.)
"$0ry" - The replacement string with "$0" for the matched value followed by the required characters(ry).
This is repeated for all matches!
Example Code
String originalString = /* your original string */;
char[] characters = /* array of characters you want to insert */;
Vector<String> newStrings = new Vector<>();
String newString;
for (int idx = 0; idx < originalString.length() + 1; ++idx) {
for (char ch : characters) {
newString = originalString.substring(0, idx)
+ ch
+ originalString.substring(idx, originalString.length());
newStrings.add(newString);
}
}
Explanation
Processing all cases:
In order to insert every single letter into an index in a string, you need a loop to iterate through every letter.
In order to insert a letter into every index in a string, you need a loop to iterate through every index in the string.
To do both at once, you should nest one loop inside the other. That way, every combination of an index and a character will be processed. In the problem you presented, it does not matter which loop goes inside the other--it will work either way.
(you actually have to iterate through every index in the string +1... I explain why below)
Forming the new string:
First, it is important to note the following:
What you want to do is not "insert a character into an index" but rather "insert a character between two indices". The distinction is important because you do not want to replace the previous character at that index, but rather move all characters starting at that index to the right by one index in order to make room for a new character "at that index."
This is why you must iterate through every index of the original string plus one. Because once you "insert" the character, the length of the new string is actually equal to originalString.length() + 1, i.e. there are n + 1 possible locations where you can "insert" the character.
Considering this, the way you actually form a new string (in the way you want to) is by getting everything to the left of your target index, getting everything to the right of your target index, and then concatenating them with the new character in between, e.g. leftSubstring + newCharacter + rightSubstring.
Now, it might seem that this would not work for the very first and very last index, because the leftSubstring and/or rightSubstring would be an empty string. However, string concatenation still works even with an empty string.
Notes about Example Code
characters can also be any collection that implements iterable. It does not have to be a primitive array.
characters does not have to contain primitive char elements. It may contain any type that can be concatenated with a String.
Note that the substring(int,int) method of String returns the substring including the character at beginIndex but not including the character at endIndex. One implication of this is that endIndex may be equal to string.length() without any problems.
Well you will need a loop for from i = 0 to your string's length
Then another loop for every character you want to insert - so if you want to keep creating new strings with every possible letter from A to Z make a loop from char A = 'a' to 'z' and keep increasing them ++A(this should work in java).
This should give you some ideas.
Supposing, for instance, you want them all in a list, you could do something like that (iterating all places to insert and iterating over all letters):
List<String> insertLetters(String s) {
List<String> list = new ArrayList<String>();
for (int i = 0; i <= s.length(); i++) {
String prefix = s.substring(0, i);
String postfix = s.substring(i, s.length());
for (char letter = 'a'; letter <= 'z'; letter++) {
String newString = prefix + letter + postfix;
list.add(newString);
}
}
return list;
}
String x = "ry";
char[] alphabets = "abcdefghijklmnopqrstuvwxyz".toCharArray();
String[] alphabets2 = new String[alphabets.length];
for (int i=0;i<alphabets.length;i++){
char z = alphabets[i];
alphabets2[i] = z + x;
}
for (String s: alphabets2
) {
System.out.println(s);
}
First of all you would need a Array of alphabet (Easier for you to continue).
I will not give you exact answer, but something to start, so you would learn.
int length = 0;
Arrays here
while(length <= 2) {
think what would be here: hint you put to index (length 0) the all alphabet and move to index 1 and then 2
}

A java string exercise i came across

Look for patterns like "zip" and "zap" in the string -- length-3, starting with 'z' and ending with 'p'. Return a string where for all such words, the middle letter is gone, so "zipXzap" yields "zpXzp"
Here is a solution i got from someone:
public class Rough {
public static void main(String [] args){
StringBuffer mat = new StringBuffer("matziplzdpaztp");
for(int i = 0; i < mat.length() - 2; ++i){
if (mat.charAt(i) == 'z' & mat.charAt(i + 2) == 'p'){
mat.deleteCharAt(i + 1);
}
}
System.out.println(mat);
}
}
But why is it that the for loop condition (i < mat.length() -2) is not (i < mat.length())????
Because in the loop:
if (mat.charAt(i) == 'z' & mat.charAt(i + 2) == 'p'){
// -----------------------------------^^^^^
If i were bound by i < mat.length(), then i + 2 would be out of bounds.
Because you don't have to reach the end of your sentence since your words are at least three letters long.
"2" stands for "the length except the first word",you just need to check all the positions in the string variable , and treat the positions as the first word of the substring , so just ignore the "length of the substring without the first word".
in your case , the length of "z*p" is 3, you just check all the position in the string , and treat the position as z to check something ,so just ignore "*p" ,which has length 2.
mat.length() will give length 14 and if you check for mat.charAt(i + 2) at the end it will give java.lang.StringIndexOutOfBoundsException because the string counts from index 0 not from 1. If you still want to use mat.length() you have to replace the AND '&' operator with short circuit AND '&&' operator in if condition.

Find every possible subset given a string [duplicate]

This question already has answers here:
Memory efficient power set algorithm
(5 answers)
Closed 8 years ago.
I'm trying to find every possible anagram of a string in Java - By this I mean that if I have a 4 character long word I want all the possible 3 character long words derived from it, all the 2 character long and all the 1 character long. The most straightforward way I tought of is to use two nested for loops and iterare over the string. This is my code as of now:
private ArrayList<String> subsets(String word){
ArrayList<String> s = new ArrayList<String>();
int length = word.length();
for (int c=0; c<length; c++){
for (int i=0; i<length-c; i++){
String sub = word.substring(c, c+i+1);
System.out.println(sub);
//if (!s.contains(sub) && sub!=null)
s.add(sub);
}
}
//java.util.Collections.sort(s, new MyComparator());
//System.out.println(s.toString());
return s;
}
My problem is that it works for 3 letter words, fun yelds this result (Don't mind the ordering, the word is processed so that I have a string with the letters in alphabetical order):
f
fn
fnu
n
nu
u
But when I try 4 letter words, it leaves something out, as in catq gives me:
a
ac
acq
acqt
c
cq
cqt
q
qt
t
i.e., I don't see the 3 character long word act - which is the one I'm looking for when testing this method. I can't understand what the problem is, and it's most likely a logical error I'm making when creating the substrings. If anyone can help me out, please don't give me the code for it but rather the reasoning behind your solution. This is a piece of coursework and I need to come up with the code on my own.
EDIT: to clear something out, for me acq, qca, caq, aqc, cqa, qac, etc. are the same thing - To make it even clearer, what happens is that the string gets sorted in alphabetical order, so all those permutations should come up as one unique result, acq. So, I don't need all the permutations of a string, but rather, given a 4 character long string, all the 3 character long ones that I can derive from it - that means taking out one character at a time and returning that string as a result, doing that for every character in the original string.
I hope I have made my problem a bit clearer
It's working fine, you just misspelled "caqt" as "acqt" in your tests/input.
(The issue is probably that you're sorting your input. If you want substrings, you have to leave the input unsorted.)
After your edits: see Generating all permutations of a given string Then just sort the individual letters, and put them in a set.
Ok, as you've already devised your own solution, I'll give you my take on it. Firstly, consider how big your result list is going to be. You're essentially taking each letter in turn, and either including it or not. 2 possibilities for each letter, gives you 2^n total results, where n is the number of letters. This of course includes the case where you don't use any letter, and end up with an empty string.
Next, if you enumerate every possibility with a 0 for 'include this letter' and a 1 for don't include it, taking your 'fnu' example you end up with:
000 - ''
001 - 'u'
010 - 'n'
011 - 'nu'
100 - 'f'
101 - 'fu' (no offense intended)
110 - 'fn'
111 - 'fnu'.
Clearly, these are just binary numbers, and you can derive a function that given any number from 0-7 and the three letter input, will calculate the corresponding subset.
It's fairly easy to do in java.. don't have a java compiler to hand, but this should be approximately correct:
public string getSubSet(string input, int index) {
// Should check that index >=0 and < 2^input.length here.
// Should also check that input.length <= 31.
string returnValue = "";
for (int i = 0; i < input.length; i++) {
if (i & (1 << i) != 0) // 1 << i is the equivalent of 2^i
returnValue += input[i];
}
return returnValue;
}
Then, if you need to you can just do a loop that calls this function, like this:
for (i = 1; i < (1 << input.length); i++)
getSubSet(input, i); // this doesn't do anything, but you can add it to a list, or output it as desired.
Note I started from 1 instead of 0- this is because the result at index 0 will be the empty string. Incidentally, this actually does the least significant bit first, so your output list would be 'f', 'n', 'fn', 'u', 'fu', 'nu', 'fnu', but the order didn't seem important.
This is the method I came up with, seems like it's working
private void subsets(String word, ArrayList<String> subset){
if(word.length() == 1){
subset.add(word);
return;
}
else {
String firstChar = word.substring(0,1);
word = word.substring(1);
subsets(word, subset);
int size = subset.size();
for (int i = 0; i < size; i++){
String temp = firstChar + subset.get(i);
subset.add(temp);
}
subset.add(firstChar);
return;
}
}
What I do is check if the word is bigger than one character, otherwise I'll add the character alone to the ArrayList and start the recursive process. If it is bigger, I save the first character and make a recursive call with the rest of the String. What happens is that the whole string gets sliced in characters saved in the recursive stack, until I hit the point where my word has become of length 1, only one character remaining.
When that happens, as I said at the start, the character gets added to the List, now the recursion starts and it looks at the size of the array, in the first iteration is 1, and then with a for loop adds the character saved in the stack for the previous call concatenated with every element in the ArrayList. Then it adds the character on its own and unwinds the recursion again.
I.E., with the word funthis happens:
f saved
List empty
recursive call(un)
-
u saved
List empty
recursive call(n)
-
n.length == 1
List = [n]
return
-
list.size=1
temp = u + list[0]
List = [n, un]
add the character saved in the stack on its own
List = [n, un, u]
return
-
list.size=3
temp = f + list[0]
List = [n, un, u, fn]
temp = f + list[1]
List = [n, un, u, fn, fun]
temp = f + list[2]
List = [n, un, u, fn, fun, fu]
add the character saved in the stack on its own
List = [n, un, u, fn, fun, fu, f]
return
I have been as clear as possible, I hope this clarifies what was my initial problem and how to solve it.
This is working code:
public static void main(String[] args) {
String input = "abcde";
Set<String> returnList = permutations(input);
System.out.println(returnList);
}
private static Set<String> permutations(String input) {
if (input.length() == 1) {
Set<String> a = new TreeSet<>();
a.add(input);
return a;
}
Set<String> returnSet = new TreeSet<>();
for (int i = 0; i < input.length(); i++) {
String prefix = input.substring(i, i + 1);
Set<String> permutations = permutations(input.substring(i + 1));
returnSet.add(prefix);
returnSet.addAll(permutations);
Iterator<String> it = permutations.iterator();
while (it.hasNext()) {
returnSet.add(prefix + it.next());
}
}
return returnSet;
}

How do I check if a char is a vowel?

This Java code is giving me trouble:
String word = <Uses an input>
int y = 3;
char z;
do {
z = word.charAt(y);
if (z!='a' || z!='e' || z!='i' || z!='o' || z!='u')) {
for (int i = 0; i==y; i++) {
wordT = wordT + word.charAt(i);
} break;
}
} while(true);
I want to check if the third letter of word is a non-vowel, and if it is I want it to return the non-vowel and any characters preceding it. If it is a vowel, it checks the next letter in the string, if it's also a vowel then it checks the next one until it finds a non-vowel.
Example:
word = Jaemeas then wordT must = Jaem
Example 2:
word=Jaeoimus then wordT must =Jaeoim
The problem is with my if statement, I can't figure out how to make it check all the vowels in that one line.
Clean method to check for vowels:
public static boolean isVowel(char c) {
return "AEIOUaeiou".indexOf(c) != -1;
}
Your condition is flawed. Think about the simpler version
z != 'a' || z != 'e'
If z is 'a' then the second half will be true since z is not 'e' (i.e. the whole condition is true), and if z is 'e' then the first half will be true since z is not 'a' (again, whole condition true). Of course, if z is neither 'a' nor 'e' then both parts will be true. In other words, your condition will never be false!
You likely want &&s there instead:
z != 'a' && z != 'e' && ...
Or perhaps:
"aeiou".indexOf(z) < 0
How about an approach using regular expressions? If you use the proper pattern you can get the results from the Matcher object using groups. In the code sample below the call to m.group(1) should return you the string you're looking for as long as there's a pattern match.
String wordT = null;
Pattern patternOne = Pattern.compile("^([\\w]{2}[AEIOUaeiou]*[^AEIOUaeiou]{1}).*");
Matcher m = patternOne.matcher("Jaemeas");
if (m.matches()) {
wordT = m.group(1);
}
Just a little different approach that accomplishes the same goal.
Actually there are much more efficient ways to check it but since you've asked what is the problem with yours, I can tell that the problem is you have to change those OR operators with AND operators. With your if statement, it will always be true.
So in event anyone ever comes across this and wants a easy compare method that can be used in many scenarios.
Doesn't matter if it is UPPERCASE or lowercase. A-Z and a-z.
bool vowel = ((1 << letter) & 2130466) != 0;
This is the easiest way I could think of. I tested this in C++ and on a 64bit PC so results may differ but basically there's only 32 bits available in a "32 bit integer" as such bit 64 and bit 32 get removed and you are left with a value from 1 - 26 when performing the "<< letter".
If you don't understand how bits work sorry i'm not going go super in depth but the technique of
1 << N is the same thing as 2^N power or creating a power of two.
So when we do 1 << N & X we checking if X contains the power of two that creates our vowel is located in this value 2130466. If the result doesn't equal 0 then it was successfully a vowel.
This situation can apply to anything you use bits for and even values larger then 32 for an index will work in this case so long as the range of values is 0 to 31. So like the letters as mentioned before might be 65-90 or 97-122 but since but we keep remove 32 until we are left with a remainder ranging from 1-26. The remainder isn't how it actually works, but it gives you an idea of the process.
Something to keep in mind if you have no guarantee on the incoming letters it to check if the letter is below 'A' or above 'u'. As the results will always be false anyways.
For example teh following will return a false vowel positive. "!" exclamation point is value 33 and it will provide the same bit value as 'A' or 'a' would.
For starters, you are checking if the letter is "not a" OR "not e" OR "not i" etc.
Lets say that the letter is i. Then the letter is not a, so that returns "True". Then the entire statement is True because i != a. I think what you are looking for is to AND the statements together, not OR them.
Once you do this, you need to look at how to increment y and check this again. If the first time you get a vowel, you want to see if the next character is a vowel too, or not. This only checks the character at location y=3.
String word="Jaemeas";
String wordT="";
int y=3;
char z;
do{
z=word.charAt(y);
if(z!='a'&&z!='e'&&z!='i'&&z!='o'&&z!='u'&&y<word.length()){
for(int i = 0; i<=y;i++){
wordT=wordT+word.charAt(i);
}
break;
}
else{
y++;
}
}while(true);
here is my answer.
I have declared a char[] constant for the VOWELS, then implemented a method that checks whether a char is a vowel or not (returning a boolean value). In my main method, I am declaring a string and converting it to an array of chars, so that I can pass the index of the char array as the parameter of my isVowel method:
public class FindVowelsInString {
static final char[] VOWELS = {'a', 'e', 'i', 'o', 'u'};
public static void main(String[] args) {
String str = "hello";
char[] array = str.toCharArray();
//Check with a consonant
boolean vowelChecker = FindVowelsInString.isVowel(array[0]);
System.out.println("Is this a character a vowel?" + vowelChecker);
//Check with a vowel
boolean vowelChecker2 = FindVowelsInString.isVowel(array[1]);
System.out.println("Is this a character a vowel?" + vowelChecker2);
}
private static boolean isVowel(char vowel) {
boolean isVowel = false;
for (int i = 0; i < FindVowelsInString.getVowel().length; i++) {
if (FindVowelsInString.getVowel()[i] == vowel) {
isVowel = true;
}
}
return isVowel;
}
public static char[] getVowel() {
return FindVowelsInString.VOWELS;
}
}

Categories