I am Solving a Hacker rank problem
https://www.hackerrank.com/challenges/special-palindrome-again/problem
I not able to pass test cases Still my logic is correct
I am able to find palindromes but my code finding an another palindrome which is not listed in explanation it leads to failure of test cases
List lstr=new ArrayList<>();
for(int i=0;i<s.length();i++)
{
for(int j=i+1;j<=s.length();j++)
{
String str=new StringBuilder(s.substring(i,
j)).reverse().toString();
if(s.substring(i, j).equals(str) && s.substring(i, j).length()>1 )
{
lstr.add(str);
}
}
return lstr.size()+s.length();
Input
5 asasd
special palindrome strings {a,s,a,s,d,asa,sas}
Input
7 abcbaba
special palindrome strings {a,b,c,b,a,b,a,bcb,bab,aba} but in above
example my program is finding abcba as palindrome also this leads to
failure of test cases
Special String Again
I gather you're not counting each possible special string.
Try this out, it passes all the cases.
static long substrCount(int n, String s) {
//automatically count each single character as a special string
//thus, the default number of special strings is equal to
//the length of the string
int numOfSpecialStrings = s.length();
//start iterating through the string
for (int i = 0; i < s.length(); i++) {
//to count all special strings, we
//we will restart the counting
//for each iteration.
int numOfRepeat = 0;
//this while loop takes care of the repetitive-character special strings
while (i + 1 < s.length() && s.charAt(i) == s.charAt(i + 1)) {
numOfRepeat++;
i++;
}
//In a repetitive-character string the total of all
//substrings can be calculated using the
//triangular numbers formula.
numOfSpecialStrings += (numOfRepeat * (numOfRepeat + 1) / 2);
//Now we have to take care of the special strings that
//are mirrored, but they can be e.g aba but can also
//be aabaa and etc. How do we take care of these if
//we can have an infinite amount of these?
//introduce a pointer that will take care of the substrings
//with minimum size 3 - it will check the i-1,i and i+1.
int pointer = 1;
//So, while we do not violate the boundary conditions of the loop
//we have increase the size of substring we are checking.
//E.g if pointer = 1 and we check
// aba, b is i, so i-pointer is a and i+pointer is a.
//We can see that a = a, so now we will expand our pointer
// and increment the numberOfSpecialStrings and
//will now reach i-2, i, i+2 and so on.
//This will go on until we either reach the end of the string, or the
//condition is not satisfied.
while (i - pointer >= 0 && i + pointer < s.length() &&
s.charAt(i + pointer) == s.charAt(i - 1)
&& s.charAt(i - pointer) == s.charAt(i - 1)) {
numOfSpecialStrings++;
pointer++;
}
}
System.out.println(numOfSpecialStrings);
return numOfSpecialStrings;
}
Related
The following question was asked in my last interview (yesterday), and I'm trying to solve it since then (couldn't solve it in the interview).
Sorry for any grammar mistakes or any logical mistakes, I don't have the question, it was written by memory:
You are given a number in a string format, for example: "14438832066".
You got to sum up the consecutive equal digits in that number. If no
consecutive equal digit was found, just add the digit to the result.
for example: solution(19938832066) => 11831632012
Explanation: first digit is 1.
The second and third digits are both 9 which means they will turn into 18 in the result string.
So on
with the rest of the digits (as you can see, the last 2 digits are both 6 which means they will turn into 12 in the result string).
You are required to do that for the result string as well, if needed, until no equal consecutive digits are found in the number.
Example:: number: 14438832066 solution( "19938832066") ->"11831632012" -> "2831632012"
Explanation: first result is 11831632012, but then you can see that there are still equal consecutive digits : the first and the
second digits are both 1. So process that number as well.
You are given a string and must return a string.
My solution:
I couldn't write the solution, I don't know why. It's a pretty simple question, I thought going recursive at first but didn't want to complex things.
I wrote 2 helper methods:
one that returns a boolean whether the number consists of equal consecutive digits.
one that actually makes the business logic:
turn the string into a char array
create a counter that will count instances of the same digit - (int counter = 1).
loop on the array from the first to the one before the last element :
inside the loop:
//equal digit was found - increment counter and continue to next digit
if char[i] == char[i+1] then counter++
//calculation in case we are done counting the same digit
else if counter > 0 then result.append(counter*digit[i])
// if no consecutive equal digit was found
else result.append(digit[i])
end loop: return result
Problems I had:
I created the counter inside the loop, so each iteration it got rested. took me few minutes to realize.
I had troubles realizing that 'int(digit[i])' doesn't give me the numeric value of the char, it gives the ASCII value. I had to use "Character.getNumericValue" (don't remember the exact name of the method).
Because of these problems, it took me 45 minutes to write the solution which in the end didn't even work.
I'll be glad to get a working solution, and even better - to get any feedback and tips on my solution and what, in your opinion, were my mistakes.
Thank you.
Your pseudo-code seems alright, as far as it goes. What's missing is that you don't repeatedly check the result string to see if another pass is required. I also show how you don't need to remember the API to convert a character to a digit; if you know the digits are decimal, you can interpret them yourself. As an interviewer, I would accept that there is an API that you can't precisely remember or your home-brew solution as equally valid.
String transform(String number) {
while (true) {
String result = collapse(number);
if (result.equals(number)) return result;
number = result;
}
}
private static String collapse(String number) {
StringBuilder result = new StringBuilder();
for (idx = 0; idx < number.length(); ) {
int mark = idx;
int digit = digitAt(number, idx++);
while (idx < number.length() && digitAt(number, idx) == digit) ++idx;
result.append((idx - mark) * digit);
}
return result.toString();
}
private static int digitAt(String num, int index) {
char ch = number.charAt(index);
if (ch < '0' || ch > '9') throw new IllegalArgumentException();
return ch - '0';
}
The preceding is a naïve approach that transforms the string until there are no changes. I suspect there might be a more "elegant" approach that works from left to right through the input in a single pass, but it would take some thought, and I probably couldn't come up with that in an interview.
Here's an algorithm that uses recursion and a for-loop to add consecutive equal digits. I think the code is pretty self-explanatory but please ask if you have any queries.
public static String addConsecutiveDigits(String number) {
char[] arr = number.toCharArray();
StringBuilder result = new StringBuilder();
boolean foundConsecutive = false; // boolean flag for checking if the number contained consecutive equal digits
for (int i = 0; i < arr.length; i++) {
int digit = arr[i] - '0'; //Subtracting ascii values to get integer values
int newNumber = digit;
if (i != arr.length - 1) {
int nextDigit = arr[i + 1] - '0';
if (digit == nextDigit) { // check if the digits are consecutive digits
newNumber = digit + nextDigit;
i++; // increment i as we have already added the i+1 digit
foundConsecutive = true;
}
}
result.append(newNumber);
}
if (!foundConsecutive) // if no consecutive equal digits were found then return the result;
return result.toString();
else // recurse to check for more consecutive equal digits
return addConsecutiveDigits(result.toString());
}
I'm not a Java guy, so this code might not be ideal but I would do something like this:
public String solve(String input)
{
String result = "";
int i = 0;
while (i < input.length())
{
var first = input.charAt(i);
if (i == input.length() - 1){
result += first;
break;
}
var second = input.charAt(i + 1);
if (first == second){
result += (Character.getNumericValue(first) + Character.getNumericValue(second));
i += 2;
} else {
result += first;
i += 1;
}
}
return result;
}
For the second part, I would just run the function in a loop until the result matches the input.
The input string may contain hyphens and spaces that mark places to truncate the string. The output string will be a truncated version of the input string, and the input int value is the desired length of the output string. The output string should truncate the input string at the first legal spot so the output string will have the desired length. If the truncation happens at a space, the output does not include the space, but if the truncation happens at a hyphen, the output includes the hyphen. No other hyphens are included in the output, but the other spaces are.
How can I fix my code to get the "What code should output" output without using arrays and breaks?
public static String after(int length, String s1) {
StringBuilder sb = new StringBuilder();
int x = 0;
for(; sb.length() < length && x < s1.length() - 1; x = x + 1) {
if(s1.charAt(x) != '-') {
sb.append(s1.charAt(x));
}
}
for(; x < sb.length() && s1.charAt(x) - 1 != '-'; x = x + 1) {
sb.append(s1.charAt(x));
}
if(s1.charAt(x) == ' ' && s1.length() + 1 == s1.length()) {
sb.append(s1.charAt(x));
}
return sb.toString();
}
Input are:
HW2.after(5, "La-te-ly the-re.")
HW2.after(6, "La-te-ly the-re.")
HW2.after(7, "La-te-ly the-re.")
I am getting the output :
"Latel"
"Lately"
"Lately "
What Actually output is:
"Late-"
"Lately"
"Lately the-"
Sounds like a homework question, so I'll just give you the approach I used, so you can think through the coding for yourself...
Stop your first loop one short of the number of requested characters. You have to not skip spaces, but keep a count of them, and subtract that from sb.length() you're testing in your loop because your desired length excludes spaces.
Then deal with the case where you're now pointing to a space, by testing for that, and if true, adding it to the output string and advancing x.
Then keep looking at the next character and adding it to the result as long as it isn't a dash or a space.
Finally, if you stopped on a dash, add it to the output.
I am new to Java and currently learning it in a 4 week course. I am working on on an assignment to find all of the Cs and Gs in a string named dna, and then divide the number of Cs and Gs by dna. I have written a small program, and it compiles with no syntax errors, but when I run it, all that is printed out is the length of dna and then 1(The output of the dividing part).
My code:
public static void cgRatio (String dna) {
int counter = 0; // counts how many Cs and Gs
int index = 0; // start looking from index 0
while (dna.indexOf("C") != -1 && counter != dna.length()) { // while dna is not finished and you can find C in dna
index = dna.indexOf("C", index); // Start looking from last index
if (index != -1) {
counter++;
}
else {
break;
}
}
System.out.println("Number of C in dna: " + counter);
System.out.println("Gene cg ratio: " + (counter / dna.length()));
}
If anyone can help that would be great and appreciated, thanks!
The problem is that the second argument to indexOf is the first index in the string that it searches.
Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index.
Once it finds the first "C", it will then continue to always find that same "C" in the first index it looks in. You need to change your code to this:
index = dna.indexOf("C", index + 1);
To start from the first character after the "C" that you already found. You should also change the initial index to -1 so that it starts from the first character.
There are a few problems with your code:
It uses counter as the number of cs in your dna string when it is really equal to dna.length(). This causes the ratio to be 1 if there are any cs at all, or 0 if there are none.
There should be a variable that keeps track of how many cs there are in the string and how many gs there are (as seen in the above bullet, counter cannot be used for this.)
As resueman said, this line:
index = dna.indexOf("C", index); should be changed to: index = dna.indexOf("C", index + 1);, or else the index will remain the same (it will always be equal to the index of the first c in the string.)
A while loop really is not all that well suited to this kind of thing; instead, a for loop should be used.
The ratio should be a double, not an int since doubles have more precision (they can be decimals.)
Here's code I came up with that works:
public static void cratio(String dna) {
int c = 0;
int g = 0;
for(int i =0; i < dna.length(); i++) {
if((dna.charAt(i) == 'c') || (dna.charAt(i) == 'C')) c++;
if((dna.charAt(i) == 'g') || (dna.charAt(i) == 'G')) g++;
}
System.out.println("Number of 'C's in DNA: " + c + " and number of 'G's in DNA: " + g);
int length = dna.length();
double ratio = (double) (c+g)/length * 100;
System.out.println("The ratio of 'C's and 'G's to the length of the DNA chain is: " + ratio + "%.");
}
If you have any questions, just let me know!
I have to handle some strings, I should put them N positions to left to organize the string.
Here's my code for while:
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 2; // Example
StringBuilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++) {
sb.append((char) (word.charAt(i) - lpad));
}
return sb.toString();
}
It's working for inputs that don't have to move many times...
So, the problem is that when the number N of positions to move is a little bit large (like 10), it returns me non letters, like in the example below, what can I do to prevent it?
Ex.: ABCDEFGHIJKLMNOPQRSTUVWXYZ if I move each char 10 positions to left it returns 789:;<=>?#ABCDEFGHIJKLMNOP while it must return QRSTUVWXYZABCDEFGHIJKLMNOP.
Some inputs and their expected outputs:
VQREQFGT // 2 positions to left == TOPCODER
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
LIPPSASVPH // 4 positions to left == HELLOWORLD
I think you have misunderstood what your (homework?) requirements are asking you to do. Lets look at your examples:
VQREQFGT // 2 positions to left == TOPCODER
Makes sense. Each character in the output is two characters before the corresponding input. But read on ...
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
Makes no sense (literally). The letter Q is not 10 characters before A in the alphabet. There is no letter in the alphabet that is before A in the alphabet.
OK so how do you get from A to Q in 10 steps?
Answer ... you wrap around!
A, Z, Y, X, W, V, U, T, S, R, Q ... 10 steps: count them.
So what the requirement is actually asking for is N characters to the left with wrap around. Even if they don't state this clearly, it is the only way that the examples "work".
But you just implemented N characters to the left without wrap around. You need to implement the wrap around. (I won't show you how, but there lots of ways to do it.)
There's another thing. The title of the question says "Decrement only letters" ... which implies to me that your requirement is saying that characters that are not letters should not be decremented. However, in your code you are decrementing every character in the input, whether or not it is a letter. (The fix is simple ... and you should work it out for yourself.)
what can I do to prevent it?
You make it wrap around.
If you want a value to go from 10 to 19 and then start at 10 again, in each iteration you subtract 10, increase by one, take the remainder of that divided by 20, and add 10 again.
Only here, 10 is 'A', 19 is Z, and instead of increasing by one, we add or subtract n.
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 10; // Example
StringBuilder sb = new StringBuilder();
int n = -lpad; // I'm using n here to I can use '+ n' below
for (int i = 0; i < word.length(); i++) {
int shifted = word.charAt(i) - 'A' + n;
shifted %= ('Z' - 'A' + 1); // This is for positive n
while(shifted < 0) // And this for negative ones
{
shifted += ('Z' - 'A' + 1);
}
sb.append((char)(shifted + 'A'));
}
return sb.toString();
}
Please read #StephenC's excellent answer about wrap-around. In short, you don't shift left, you rotate left, such that B → A → Z → Y. When you rotate, you wrap around to the other end.
So, for letters you want A-Z to rotate. The easiest rotation method is using modulus (%).
Your logic will be as follows:
Convert letters A-Z into numbers 0-25: n = ch - 'A'
Apply shift and wrap around. Since you're shifting left, you're subtracting from the number, so to prevent negative numbers, you start by shifting a full cycle to the right: n = (n + 26 - shift) % 26
Convert numbers back to letters: ch = (char)(n + 'A')
Here is the code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
Of course, you should validate input, and test your code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
if (count <= 0 || count >= 26)
throw new IllegalArgumentException("Invalid count: " + count);
for (char ch : buf)
if (ch < 'A' || ch > 'Z')
throw new IllegalArgumentException("Invalid character: " + ch);
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
public static void main(String[] args) {
System.out.println(rotateLeft("VQREQFGT", 2));
System.out.println(rotateLeft("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10));
System.out.println(rotateLeft("LIPPSASVPH", 4));
}
OUTPUT
TOPCODER
QRSTUVWXYZABCDEFGHIJKLMNOP
HELLOWORLD
Help me to understand how this code works. It essentially adds commas into a string of numbers. So if the user types a 1 to 3 digit number it is unchanged. For a four digit number ,it adds a comma so
1111 becomes 1,111
11111 becomes 11,111
111111111 becomes 11,111,111
and so on. Here's the code:
private String addCommasToNumericString (String digits)
{
String result = "";
int len = digits.length();
int nDigits = 0;
for (int i = len - 1; i >= 0; i--)
{
result = digits.charAt(i) + result;
nDigits++;
if (((nDigits % 3) == 0) && (i > 0))
{
result = "," + result;
}
}
return (result);
}
I´ll explain what I do understand of it
The for loop basically counts the length of the number the user has written to avoid putting a comma before the first number (e.g. ,1111). And while i is less than the length of the string it subtracts 1.
result returns the char at position i, since it counts downwards it returns the chars "opposite" from right towards left.
nDigits adds 1 from to the initial value of 0 on each iteration through the loop.
I guess now is where I am having trouble seeing exactly what is going on: if ("nDigits % 3) == 0.
So for the two first iteration through loop it will not execute the if loop because:
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
nDigits starts out as 1 because of the nDigits++ code inside the for loop, so how does it put the comma after three digits and not two? And how does it know when there is only 4 or 5 digits to place the comma corretly at position 1 and two (1,111 - 11,111)?
I think the easiest way to explain this is to slow it down to each pass.
The loop starts at the end of the string so if you have the string 12345, then after the first time through the loop result will be "5" and nDigits will be 1.
The next time through, '4' will be added to the front of the result giving you "45" and nDigits will be 2.
The third time through, it adds '3' to the front of result making that "345" and then the if-then triggers and adds a comma to the front. Result is now ",345".
More passes will give you "12,345".
I think what is confusing you is that loop starts at the '5' and not at the '1'. Everything is added to the front of result and not to the end as you would normally expect.
Hope this helps!
The key thing in this method is to count the digits from right to left. If you don't do it that way it won't work.
You can also do the same with String Manipulation instead of char manipulation. Maybe it makes it easier to understand so I'll provide an example.
My solution involves the use of the subString Method and operates in a similar manner to yours. Starting FROM RIGHT TO LEFT, it divides the original String in two substrings and adds a comma in between them every time there is a 3 digits group.
private String addCommas (String digits) {
String result = digits;
if (digits.length() <= 3) return digits; // If the original value has 3 digits or less it returns that value
for (int i = 0; i < (digits.length() – 1) / 3; i++) {
int commaPos = digits.length() – 3 – (3 * i); // comma position in each cicle
result = result.substring(0, commaPos) + "," + result.substring(commaPos);
}
return result;
}
The variable result is used for incremental build of the final output, in each iteration one or two chars are concatenated from left (i.e. the string is build from right to left).
One char is concatenated everytime by running
result = digits.charAt(i) + result;
it is the actual digit
the second char is concatenated in each third iteration by running
result = "," + result;
it is the order separator
The implementation is not optimal at all, because in Java the string are immutable and result = "," + result; ends up in creating a new object. The StringBuffer or StringBuilder are far more effective for this purpose.
Essentially what this does is start at the last digit of the number and iterate through from right to left, prepending them to the result String and putting a comma in every 3 characters.
In this particular code, len holds the total length of the number and nDigits is a count of how many of those digits have been evaluated already. Starting at position len-1 (so the index of the last digit of the number), the for-loop iterates through position 0 (the first digit of the number). It takes the digit at position i, puts it at the front of the result String, and then evaluates if there should be a comma in front of it. nDigits % 3 will return 0 every 3rd digit, so the if statement evaluates if there should be a comma by checking that if there have been 3 digits written and the one you just wrote was not 0.
for (int i = len - 1; i >= 0; i--)
i starts with len - 1, to start from the last digit. i > 0 in if (((nDigits % 3) == 0) && (i > 0)) is the one that avoid a comma before the first number (e.g. ,1111).
I modified answer of #Antonio Ricardo Diegues Silva for my purposes.
/**
* Get number in {#link String} with divider after 'n' number of digits
* #param number number for processing
* #param n amount after which will be inserted divider
* #return {#link String} number with dividers
*/
public static <T extends Number> String insertDividerBetweenEveryNDigits(T number, int n, String divider) {
StringBuilder builder = new StringBuilder().append(number);
int digitsNumber = builder.length();
if (digitsNumber > n) { // If the original value has n digits or less it just returns that value
for (int i = 1; i <= (digitsNumber - 1) / n; i++) {
int dividerPos = digitsNumber - (n * i); // divider position in each cycle
builder.insert(dividerPos, divider);
}
}
return builder.toString();
}