Write a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0.
// Write function below
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
Can someone explain the len=-1 and how to find length between character part in this question please?
It is used as initial value. The initial value of 'len' needs to be outside the possible range of 'len' otherwise you cannot set the first position of the first occurrence of the char.
E.g. if 'len' is initialized with 0 it will be assumed that the first occurrence of the char is at position 0.
In your function the second line, you declare that len variable to -1. The intent is to use a number, that impossible to return (you defined 0 as no, or too many occurences, and every other number could be a valid length between those two occurences).
If you've found the first occurence of the specific character, you should remember it, where to start the counting. This is when it checks for the initial value of -1.
When the second character is found, this len variable is something other than -1, so the else branch is executed.
if(len == -1) {
len = i; // found the first occurence, save its position
} else {
len = i - len +1; // not the first occurence, calculate the length
}
variable
len has been initialized with -1 because this value is not going to occur as index or length while iterating over the String
str. Later,
len is initialized with the index at which that char occurs first time in String
str by checking if
len is -1 otherwise it would be second occurrence of same
char(else condition).
Related
This program finds the count of duplicates in a string.
Example 1:
Input:
"abbdde"
Output:
2
Explanation:
"b" and "d" are the two duplicates.
Example 2:
Input:
"eefggghii22"
Output:
3
Explanation:
duplicates are "e", "g", and "2".
Help me with this code.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Write your code here
int c = 0;
str1 = str1.toLowerCase();
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
c = ctr[i];
}
}
return c;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
You need to maintain a count and if the value of that character exceeds 1, you need to increment the count.
Return that count to know the count of duplicates.
Added comments to understand the code better.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Initialised integer to count the duplicates
int count = 0;
// Converting a string to lowercase to count lowerCase and Uppercase as duplicates
str1 = str1.toLowerCase();
// According to ASCII, the Maximum number of characters is 256,
// So, initialized an array of size 256 to maintain the count of those characters.
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
count = count + 1;
}
}
return count;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
In short it is counting the number of characters appearing in the String str and saving it in ctr array.
How? ctr is the array that has a length of 256. So it can have 256 values (0-255 indexed). str1 is the string that contains the String. charAt(i) method returns the character at index i. Because String acts like an array where you can access each char a index values of an array.
Now assuming your input will always ASCII characters, each ASCII chars contain a value of 0-255 (i.e. ASCII value 'a' is 97). ++ after any variable means adding 1 to that. i.e.c++ means c = c+1
Now coming to the loop, ctr[str1.charAt(i)]++;, you can see the loops starts from 0 and ends at the length of the String str where 0 is the first value str. So if value of 0 indexed value (first value) of the String str is a, str.charAt(0) would return 97(well actually it will return 'a' but java takes the ASCII value). so the line actually is (for 0 th index) ctr[97]++; so it's incrementing the value of the 97th index (which is initially 0) by 1. So now the value is 1.
Like this way it will only increment the index values that matches with the ASCII values of the character in the String, thus counting the amount of time the characters occur.
I am given a string from which i have to find out sub-strings that satisfy the following conditions
all characters in the sub-string are same. eg: aa,bbb,cccc.
all the character except the middle character have to be the same.
eg: aba, bbabb, etc.
I've made an algo something like this
I beak the string using two loops 1st loop holds the first char and the second loop traverses through the string.
Then i send the sub-string to the vet() to see if the substring contains less than or equals two character.
If the sub-string contains two character then i check if its a palindrome
public static int reverse(String s)
{
String wrd="";
for(int i = s.length()-1 ;i>=0;i--)
wrd = wrd + s.charAt(i);
if(s.equals(wrd))
return 1;
else
return 0;
}
public static boolean vet(String s)
{
HashSet<Character> hs = new HashSet<>();
for(char c : s.toCharArray())
{
hs.add(c);
}
if(hs.size() <= 2)
return true;
else
return false;
}
static long substrCount(int n, String s) {
List<String> al = new ArrayList<>();
for(int i=0;i<s.length();i++)
{
for(int j=i;j<s.length();j++)
{
if(vet(s.substring(i,j+1)))
{
if(reverse(s.substring(i,j+1)) == 1)
al.add(s.substring(i,j+1));
}
}
}
return al.size();
}
This code works fine for small strings, however if the string is big say ten thousand character, this code will throw Time limit exception.
I suspect the loop that breaks the string and create the sub-string in the substrCount() is causing the time complexity as it has nested loops.
Please review this code and provide a better way to break the string or if the complexity is increasing due to some other section then let me know.
link : https://www.hackerrank.com/challenges/special-palindrome-again/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=strings
You can collect counts from left side and right side of the string in 2 separate arrays.
Now, we collect counts in the fashion of if previous char equals current char, increase count by 1, else set it to 1.
Example:
a a b a a c a a
1 2 1 1 2 1 1 2 // left to right
2 1 1 2 1 1 2 1 // right to left
For strings that have all characters equal, we just collect all of them while iterating itself.
For strings with all equal except the middle character, you can use above the above table and you can collect string as below:
Pseudocode:
if(str.charAt(i-1) == str.charAt(i+1)){ // you will add checks for boundaries
int min_count = Math.min(left[i-1],right[i+1]);
for(int j=min_count;j>=1;--j){
set.add(str.substring(i-j,i+j+1));
}
}
Update:
Below is my accepted solution.
static long substrCount(int n, String s) {
long cnt = 0;
int[] left = new int[n];
int[] right = new int[n];
int len = s.length();
for(int i=0;i<len;++i){
left[i] = 1;
if(i > 0 && s.charAt(i) == s.charAt(i-1)) left[i] += left[i-1];
}
for(int i=len-1;i>=0;--i){
right[i] = 1;
if(i < len-1 && s.charAt(i) == s.charAt(i+1)) right[i] += right[i+1];
}
for(int i=len-1;i>=0;--i){
if(i == 0 || i == len-1) cnt += right[i];
else{
if(s.charAt(i-1) == s.charAt(i+1) && s.charAt(i-1) != s.charAt(i)){
cnt += Math.min(left[i-1],right[i+1]) + 1;
}else if(s.charAt(i) == s.charAt(i+1)) cnt += right[i];
else cnt++;
}
}
return cnt;
}
Algorithm:
The algorithm is the same as explained above with a few additional stuff.
If the character is at the boundary, say 0 or at len-1, we just look at right[i] to count the strings, because we don't have a left here.
If a character is inside this boundary, we do checks as follows:
If previous character equals next character, we check if previous character does not equal current character. We do this because, we want to avoid future addition of strings at the current iteration itself(say for strings like aaaaa where we are at the middle a).
Second condition says s.charAt(i) == s.charAt(i+1), meaning, we again have strings like aaa and we are at the first a. So we just add right[i] to indicate addition of strings like a,aa,aaa).
Third does cnt++ meaning addition of individual character.
You can make a few optimizations like completely avoiding right array etc, but I leave that to you as an exercise.
Time complexity: O(n), Space complexity: O(n)
Your current solution runtime is O(n^4). You can reduce it to O(n^2logn) by removing the number of character count in substrings and optimising the palindrome check portion.
To do so, you have to pre-calculate an array say "counter" where every position of the "counter" array indicates number of different characters from starting index to that position.
After constructing the array, you can check if a substring has more than two characters in O(1) by subtracting the end position and starting position value of counter array. If the value is 1 then there have only one character in the substring. If the value is 2, then you can binary search in the counter array between the substrings starting and end positions to find the position of single character. After finding out the position of the single character its straight forward to check if the substring is palindrome or not.
UPDATE!
Let me explain with an example:
Suppose the string is "aaabaaa".
So, the counter array would be = [1, 1, 1, 2, 2, 2, 2];
Now, lets assume for a specific time, the outer for loops value i = 1 and the inner for loops value j = 5; so the substring is "aabaa".
Now to find the number of character in the substring by following code:
noOfDifferentCharacter = counter[j] - counter[i-1] + 1
If the noOfDifferentCharacter is 1 then no need to check for palindrome. If the noOfDifferentCharacter is 2 like in our case we need to check if the substring is palindrome. To check if the substring is palindrome have to perform a binary search in the counter array from index i to j to check for the position where the value is greater than its previous index. In our case the position is 3, then you just need to check if the position is the middle position of the substring. Note that the counter array is sorted.
Hope this helps. Let me know if you don't understand any step. Happy coding!
I am trying to understand how String length() function work while reversing a string.
String length is 4 then why i need to give length()-1 in below working code.
No issue in below code, need help to understand length()
public class MStringReverse {
String getReverse(String input) {
System.out.println(input.length());
String reverse = "";
for(int i = input.length() - 1; i >= 0; i--) {
reverse = reverse + input.charAt(i);
}
return reverse;
}
public static void main(String[] args) {
MStringReverse mr = new MStringReverse();
String result = mr.getReverse("Achilis");
System.out.println(result);
}
}
As the index starts from 0, not from 1. So if you have a String of length 4 then 0,1,2,3 are the only possible indexes. If your index provided as the argument in charAt() is less than 0 or greater than or equals the length of the String then you will get StringIndexOutOfBoundsException exception. Here you can see how charAt method works :
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
That's because indexing starts at 0.
charAt(0) is character 1.
The answer is that you are iterating on indexes, which start at 0.
Imagine an array of length 4. It will store 4 items, the first one at index 0, second at index 1, third at 2 and the last one at index 3. The index of the last element is always length() - 1, that's why you put it as the upper border in loops in order to not raise an IndexOutOfBoundsException while iterating.
You could add some console output to view the accessed indexes per String for each iteration like this:
public class MStringReverse {
static String getReverse(String input) {
System.out.println("Input length is " + input.length());
String reverse = "";
for(int i = input.length() - 1; i >= 0; i--) {
System.out.println("accessing index " + i + " of \"input\"");
reverse = reverse + input.charAt(i);
System.out.println("last index of \"reverse\" is now " + (reverse.length() - 1));
}
return reverse;
}
public static void main(String[] args) {
String result = getReverse("Achilis");
System.out.println(result);
}
}
Because your string index starts at 0. Your length is 7. If you access input.charAt(7) you will get an index out of range exception.
A c h i l i s
0 1 2 3 4 5 6
The last index of the String is 1 less than the length because of a 0-based index.
i.e.
abcd has a length of 4 but to iterate from the last character, you need to start at index 3 (which is d), therefore length()-1 is where you start.
String length is always less than one because it starts index position from 0 .
if the String length is 4 then index position starts from 0 to 3
For this, you just understand the concept of the array.
Suppose we have an array of int of size 5.
So if size is 5 that means array index is from 0 to 4 last index always -1 from actual size.
Same apply on String length method in case of reversing the string.
Suppose you
String name = "Stack";
Its length is 5 but the last index is 4 because of the last index always -1 from actual length.
I was having some problem when trying to replace certain character with ASCII character in the string.
So let's say I got this string "CCCCCCC". After perform some method, it will become "CCCCCCa". Then the second time I will be checking the second last character and perform some method to get "CCCCCca". Then third time will be checking the third last character and so on and repeat for 7 times.
for (int i = 0; i < 256; i++){
plaintext = plaintext .substring(0,plaintext .length() - counter) + Character.toString((char)i);
}
I used a for loop to loop through all 256 ASCII characters. The counter will be incremented after I performed some decryption. So basically for the first time, it will be -1 (which is the last character) then second time will be -2 (which is the second last character) and so on for the substring.
Let me put it this way, for the first time, I want all 256 ASCII appended to the end of my 7 bytes string. Then after I perform some decryption, the string will become CCCCCCCa. So when I loop for the second time, I will replace my second last character in the string with all 256 ASCII. And after some decryption, the string will become CCCCCC(a. Then I loop until there is no more C in the string.
However, I am getting String index out of range: -1 error message. Is there any other way to replace the last character of a string with decreased size by 1 after each for loop?
Thanks in advance.
First, don't forget the rest.
plaintext = plaintext.substring(0,plaintext .length() - counter)
+ Character.toString((char)i)
+ plaintext.substring(plaintext .length() - counter + 1) ; //TO add the rest
Then, you need to check if counter is not larger than plaintext.length()
for (int i = 0; i < 256 && counter <= plaintext.length(); i++){
I would suggest to use String.toCharArray() and iterate from the end, this would be much easier.
char[] array = plaintext.toCharArray();
for(int i = array.length - 1, char c = 0; i >= 0; --i){
array[i] = c++;
}
Example of both code: (using 'a' as a first character instead of 0)
public static void main(String[] args) {
String plaintext = "CCCCCC";
for (int i = 'a', counter = 1; i < 256 && counter <= plaintext.length(); i++, ++counter) {
plaintext = plaintext.substring(0, plaintext.length() - counter)
+ Character.toString((char) i)
+ plaintext.substring(plaintext.length() - counter + 1);
}
System.out.println(plaintext);
plaintext = "CCCCCC"; //fedcba
char[] array = plaintext.toCharArray();
char c = 'a';
for (int i = array.length - 1; i >= 0; --i) {
array[i] = c++;
}
System.out.println(new String(array)); //fedcba
}
fedcba
fedcba
I want to accomplish a program which can take a textfile and make the size smaller. So far it replaces all the double character occurrences, and now I want to replace "ou" with "1".
I've tried with an if-statement, but it doesn't seem to work quite well.
My method is below:
public String compressIt (String input)
{
int length = input.length(); // length of input
int ix = 0; // actual index in input
char c; // actual read character
int cCounter; // occurrence counter of actual character
String ou = "ou";
StringBuilder output = // the output
new StringBuilder(length);
// loop over every character in input
while(ix < length)
{
// read character at actual index then increments the index
c = input.charAt(ix++);
// we count one occurrence of this character here
cCounter = 1;
// while not reached end of line and next character
// is the same as previously read
while(ix < length && input.charAt(ix) == c)
{
// inc index means skip this character
ix++;
// and inc character occurence counter
cCounter++;
}
if (input.charAt(ix) == 'o' && input.charAt(++ix) == 'u' && ix < length - 1)
{
output.append("1");
}
// if more than one character occurence is counted
if(cCounter > 1)
{
// print the character count
output.append(cCounter);
}
// print the actual character
output.append(c);
}
// return the full compressed output
return output.toString();
}
It's this lines of code I'm referring to.
if (input.charAt(ix) == 'o' && input.charAt(ix + 1) == 'u')
{
output.append("1");
}
What I want to do: Replace characters. I got a text-file which contains "Alice In Wonderland". When my looping through all characters sees an 'o' and an 'u' (like "You"), I want to replace the characters so it looks like: "Y1".
Regards
So most likely you're trying loop from ix = 0 to the length of the string.
First of all my guess is that youre looping up and including string.length(). Which doesnt work, charAt is 0 indexed aka
"abc" has a charAt 0, 1 and 2 but not 3 which gives the error you describe.
Second of all the line you showed uses input.charAt (ix++) which does the following: get the char at position ix (old value) and after that, update the value ix to ix + 1, if you want ix to be updated before the surrounding charAt you'd have to write input.charAt(++ix)
Third of all there is a String.replace function, input.replace("abc", "def") will work great for simple replacements, for more complicated replacements, consider using regex.
This has nothing to do with the charAt method. You need to change your if condition to run it till length-1. It is failing in the last case as it is going out array.
for(int i=0; i<inputString.length() - 1; i++)
{
char temp = inputString.charAt(i);
char blah = inputString.charAt(i+1);
System.out.println("temp: "+ temp);
System.out.println("blah: "+ blah);
}
This works for me!