How can I convert a string in the form eyesOfTheTiger to one that reads eyes-of-the-tiger?
Just travel through the string and take different action if the character is uppercase.
public class Test {
private static String upperCaseToDash(String input) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (Character.isUpperCase(c))
sb.append('-').append(Character.toLowerCase(c));
else
sb.append(c);
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(upperCaseToDash("eyesOfTheTiger"));
}
}
Before you start implementing this function yourself via substrings, regex, etc, consider using Google Guava. Class com.google.common.base.CaseFormat solves exactly what you intend to do.
In your case you need the LOWER_CAMEL and LOWER_HYPHEN class constants and the to(CaseFormat format, String s) method.
IMO, it's always better to use a mature and well-tested library than to implement everything yourself.
You can split() the String using a regex , like "(?<!(^|[A-Z0-9]))(?=[A-Z0-9])|(?<!^)(?=[A-Z][a-z])" and then append - at the end of each split .
public String camelCaseToDashSeparated(String initialString) {
if(initialString==null || initialString.length()<1)
return initialString;
StringBuilder str = new StringBuilder();
for (String w : "eyesOfTheTiger".split("(?<!(^|[A-Z0-9]))(?=[A-Z0-9])|(?<!^)(?=[A-Z][a-z])")) {
str.append(w.toLowerCase()+"-");
}
return str.substring(0, str.length()-1);
}
Another way would be :
Travel through the String , char by char , keep adding the characters to the StringBuilder. Once you find a char in uppercase , append - to the StringBuilder with the lowercase of the char.
public static String camelCaseToDashSeparated2 (String initialString) {
StringBuffer buff = new StringBuffer();
for(int x = 0; x < initialString.length(); x++) {
char c = initialString.charAt(x);
if(Character.isUpperCase(c)) {
buff.append("-").append(Character.toLowerCase(c));
}
else {
buff.append(c);
}
}
return buff.toString();
}
Quick and dirty solution could be something like this:
(you should decide what to do with spaces, dashes, full stops,
languages other than English etc.)
public static String toDashed(String value) {
if (null == value)
return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); ++i) {
char ch = value.charAt(i);
if ((ch >= 'A') && (ch <= 'Z') && (i > 0)) {
sb.append('-');
sb.append(Character.toLowerCase(ch));
}
else
sb.append(ch);
}
return sb.toString();
}
Related
I am having an issue with a particular leetcode problem called Valid Palindrome. My code works for all test cases except the last test case 479/480.
In this test case a 106890 length string is passed in but my code takes too long to solve it.
I decided to try take a different approach and use the StringBuilder class to reverse the string and then simply use reversedString.equals(originalString) to compare whether they are a palindrome. This approach solves the question and passes all testcases
Why doesn't my two pointer approach work? Why does it fail on the last test case?
Here is my solution (Two Pointer)
class Solution {
public static boolean isPalindrome(String s) {
String fixedString = "";
for (char c : s.toCharArray()) {
if (Character.isDigit(c) || Character.isLetter(c)) {
fixedString += c;
}
}
fixedString = fixedString.toLowerCase();
int i = 0;
int j = fixedString.length() - 1;
System.out.println(fixedString.toCharArray());
while (i <= j) {
if (fixedString.toCharArray()[i] != fixedString.toCharArray()[j]) {
return false;
}
i += 1;
j -= 1;
}
return true;
}
}
Here is my second solution using StringBuilder.
public class Valid_Palindrome {
public static void main(String args[]){
System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
}
public static boolean isPalindrome(String s) {
String fixedString = "";
for(char c : s.toCharArray()){
if(Character.isDigit(c) || Character.isLetter(c)){
fixedString += c;
}
}
fixedString = fixedString.toLowerCase();
StringBuilder sb = new StringBuilder(fixedString);
sb = sb.reverse();
System.out.println(sb);
return sb.toString().equals(fixedString);
}
}
Technically speaking, isn't the second solution supposed to be much slower since it is using StringBuilder?
How do I optimize my first solution?
Here is the input string that is passed in my leetcode.
Don't build or reverse or do anything with the string, except iterate over half its characters.
In pseudo code:
Loop over the first half of the characters
For the ith character, compare it with the (length - i - 1)th character
If different, return false
If loop ends, return true
It is generally slow to perform string concatenation in a loop. Use a StringBuilder instead in the first loop to create the filtered string.
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isLetterOrDigit(c))
sb.append(Character.toLowerCase(c));
}
for (int i = 0, j = sb.length() - 1; i < j; i++, j--)
if (sb.charAt(i) != sb.charAt(j))
return false;
return true;
There are a couple of statements in your code that are probably slowing it down.
fixedString += c;
This creates a new StringBuilder object. The contents of fixedString are copied to it. Then the character (c) is appended. Then the StringBuilder is converted to a String and that String is assigned to variable fixedString.
if (fixedString.toCharArray()[i] != fixedString.toCharArray()[j])
Method toCharArray creates a new char[] and copies the contents of the String to it.
I suggest that you create the char[] once only and work with it. Of-course you need to remove the non-letters and non-digits from the original string as well as convert to lower case.
Here is my rewrite of your [two pointer] solution.
(Note that I assume that a null or empty string is not a palindrome.)
public static boolean isPalindrome(String s) {
if (s != null && !s.isEmpty()) {
char[] chars = s.toCharArray();
char[] temp = new char[chars.length];
int count = 0;
for (char c : chars) {
if (Character.isDigit(c) || Character.isLetter(c)) {
temp[count++] = Character.toLowerCase(c);
}
}
char[] letters = new char[count];
System.arraycopy(temp, 0, letters, 0, count);
int i = 0;
int j = count - 1;
System.out.println(letters);
while (i < j) {
if (letters[i] != letters[j]) {
return false;
}
i++;
j--;
}
return true;
}
return false;
}
Here is a description:
"Write a program that, given an input sentence, alternates the case of every alphabetic character, starting with uppercase. Spaces and non-alphabetical characters should be added to the final output as is, i.e. they should not be taken into account when alternating between upper/lowercase."
Here is what I've tried and does not work (System.out.println in main method should return correct sentence):
public class Main {
public static void main(String[] args) throws IOException {
InputStreamReader reader = new InputStreamReader(System.in, StandardCharsets.UTF_8);
BufferedReader in = new BufferedReader(reader);
String line;
while ((line = in.readLine()) != null) {
System.out.println(changeToUppercaseOrLowercase(countLettersWithSpaces(line), line));
}
}
private static int countLettersWithSpaces(String sentence) {
int count = 0;
for (int i = 0; i < sentence.length(); i ++)
{
char c = Character.toUpperCase(sentence.charAt(i));
if (c >= 'A' && c <= 'Z' || c == ' ' )
count ++;
}
return count;
}
private static String changeToUppercaseOrLowercase(int countLetters, String sentence) {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0; i<countLetters; i++) {
if (!sentence.substring(i,i+1).equals(" ")) {
if ((i % 2) == 0) {
stringBuilder.append(sentence.substring(i,i+1).toUpperCase());
}
else {
stringBuilder.append(sentence.substring(i,i+1).toLowerCase());
}
}
if (sentence.substring(i,i+1).equals(" ")) {
stringBuilder.append(" ");
i++;
}
}
return stringBuilder.toString();
}
}
But tests says that:
Input data:
We are the world
Expected result:
We ArE tHe WoRlD
Result:
We Re He OrLd
How to solve that? Thank you in advance!
You can use Character.isAlphabetic and keep a counter that is incremented each time a letter is encountered.
public static String alternateCase(String str){
int count = 0;
StringBuilder sb = new StringBuilder(str.length());
for(int i = 0; i < str.length(); i++){
char c = str.charAt(i);
if(Character.isAlphabetic(c))
sb.append(++count % 2 == 1 ? Character.toUpperCase(c) : Character.toLowerCase(c));
else sb.append(c);
}
return sb.toString();
}
use Character.isLetter() function to check if it's a letter or not. half your problem will be solved.
and your problem description and test case doesnt go with each other. Please try to clarify more.
There are many ways to fix this. This one has minimal impact on your existing code.
Use an evenOdd counter to ensure you are not skipping over characters but still maintaining the alternation.
private static String changeToUppercaseOrLowercase(int countLetters, String sentence) {
StringBuilder stringBuilder = new StringBuilder();
int evenOdd = 0; // init ********HERE*******
for(int i=0; i<countLetters; i++) {
if (!sentence.substring(i,i+1).equals(" ")) {
if ((evenOdd % 2) == 0) { // check ********HERE*******
stringBuilder.append(sentence.substring(i,i+1).toUpperCase());
}
else {
stringBuilder.append(sentence.substring(i,i+1).toLowerCase());
}
}
if (sentence.substring(i,i+1).equals(" ")) {
stringBuilder.append(" ");
evenOdd--; // adjust to preserve proper alternation ********HERE*********
}
evenOdd++; // the normal update ********HERE*******
}
return stringBuilder.toString();
}
The method takes 2 parameters (String,char) and returns the string with the char replaced by '+' if index is even and '#' if index is odd.
The String I use is "Mary Bella Abracadabra" and the expected output is "M+ry Bell+ +br#c#d#br+". Instead I get "M#ry Bell# #br#c#d#br#".
I can't find the error in my code. It seems that all indexes where char ch is found are odd.
public String emphasize (String phrase, char ch){
String phraseEmph = "";
char c1 = '#';
char c2 = '+';
for (int i=0; i < phrase.length(); i++){
char c = phrase.charAt(i);
char cc = Character.toLowerCase(c);
if ((cc == ch) && ((i % 2) == 0)){
phraseEmph = phrase.replace(c,c2);
phrase = phraseEmph;
}
else if ((cc == ch) && ((i % 2)!= 0)){
phraseEmph = phrase.replace(c,c1);
phrase = phraseEmph;
}
phrase = phrase;
}
return phrase;
}
public void testEmphasize(){
String phrase = "Mary Bella Abracadabra";
char ch = 'a';
String Emphasized = emphasize(phrase,ch);
System.out.println("Emphasized : " + Emphasized);
}
When you call replace it doesn't just replace the current 'a', it replaces all of them. You'll need to find a different way to replace characters so that you only change one at a time.
(I've purposefully avoided suggesting a fix. It'll be more educational if you come up with it yourself.)
Note Array start with 0 in java. String is immutable and don't provide many mutable methods. It's best to make use of StringBuilder as shown below both for easiness and memory efficiency.
public static String emphasize(String phrase, char ch) {
StringBuilder phraseEmph = new StringBuilder(phrase);
char c1 = '#';
char c2 = '+';
for (int i = 0; i < phrase.length(); i++) {
char c = phrase.charAt(i);
char cc = Character.toLowerCase(c);
if ((cc == ch) && ((i % 2) == 0)) {
phraseEmph.setCharAt(i, c2);
} else if ((cc == ch) && ((i % 2) != 0)) {
phraseEmph.setCharAt(i, c1);
}
}
return phraseEmph.toString();
}
Use StringBuilder instead of String for concatenation to a string inside a loop because it is much faster and consumes less memory.
Convert both the characters in the same case (e.g. lowercase) before comparing. This way, you can pass the character to the function in any case.
You should not use String#replace for this case as it replaces all occurrences of replacement character/string in the string being replaced.
Demo:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(emphasize("Mary Bella Abracadabra", 'a'));
System.out.println(emphasize("Mary Bella Abracadabra", 'A'));
}
public static String emphasize(String phrase, char ch) {
char c1 = '#';
char c2 = '+';
StringBuilder sb = new StringBuilder();
// Convert the char parameter to lower case
char chLower = Character.toLowerCase(ch);
for (int i = 0; i < phrase.length(); i++) {
char c = phrase.charAt(i);
if (Character.toLowerCase(c) == chLower) {
if (i % 2 == 0) {
sb.append(c1);
} else {
sb.append(c2);
}
} else {
sb.append(c);
}
}
return sb.toString();
}
}
Output:
M+ry Bell+ +br#c#d#br+
M+ry Bell+ +br#c#d#br+
Here are some suggestions.
use a StringBuilder to make the character replacements. Intialize to the original string. You can then use setCharAt to make the change.
Use indexOf in conjunction with toLowerCase. Then you don't need to verify if you found the character, just use the index returned and return the final string if -1.
then just check for even or or indices like you are doing but assign to a holding char variable.
Then use that to replace the character. Like this pseudocode
char repl;
if (even) {
repl = '#';
} else {
repl = '+';
}
make replacement
don't do a check for both even or odd. Just check for one condition, Otherwise it must be the other condition (not need to check again).
Aside from my recommendations, here is another way of doing it.
The main difference is that it uses the even/odd result to index into the array to replace the character.
public static String emphasize(String phrase, char ch) {
StringBuilder sb = new StringBuilder(phrase);
char[] chars = { '#', '+' };
int idx = -1;
while ((idx = phrase.toLowerCase().indexOf(ch, idx + 1)) >= 0) {
sb.setCharAt(idx, chars[idx % 2]);
phrase = sb.toString();
}
return phrase;
}
Full tested simplified code :
public class Main {
public static void main(String[] args) {
String phrase = "Maryaa Bella Abracadabra";
char ch = 'a';
System.out.println("Original : " + phrase);
String Emphasized = emphasize(phrase,ch);
System.out.println("Emphasized : " + Emphasized);
}
public static String emphasize (String phrase, char ch){
StringBuilder temp = new StringBuilder(phrase);
char c1 = '#';
char c2 = '+';
for (int i = 0; i < phrase.length(); i++){
char c = phrase.charAt(i);
char cc = Character.toLowerCase(c);
if(cc == ch) {
if(i%2 == 0){
temp.setCharAt(i, c1);
} else {
temp.setCharAt(i, c2);
}
}
}
return temp.toString();
}
}
Output :
Original : Maryaa Bella Abracadabra
Emphasized : M+ry#+ Bell+ +br#c#d#br+
Your code is very inefficient, my suggestion :
class emphasize {
private String phrase;
private char ch;
public emphasize(String phrase, char ch) {
this.phrase = phrase;
this.ch = ch;
}
public String execute() {
char chars[] = phrase.toCharArray();
for (int i = 0 ; i < chars.length ; i++) {
/* As char is primitive type I can use == */
if (chars[i]==Character.toLowerCase(ch) || chars[i]==Character.toUpperCase(ch)) chars[i] = i%2==0 ? '+' : '#';
}
return String.valueOf(chars);
}
}
public class Main {
public static void main(String[] args) {
String phrase = "Mary Bella Abracadabra";
char ch = 'a';
emphasize obj = new emphasize(phrase, ch);
System.out.println(obj.execute());
}
}
Output :
here it is giving error----required variable ,found value
my code
for eg aabacc when we got any pair like aa remove it from string and the final answer is (ba).
public class Solution {
// Complete the superReducedString function below.
static String superReducedString(String s) {
String sn;
int j=0;
for(int i=0;i<s.length()-1;i++)
{
if(s.charAt(i)!=s.charAt(i+1))
{
sn.charAt(j)=s.charAt(i);
j++;
}
}
return sn;
}
Since String is immutable in Java - String manipulation always generates a new String leaving the previous Strings in String Pool. StringBuffer and StringBuilder are mutable objects and provide methods for String manipulation
Sample working method using StringBuilder is provided below:
static String superReducedString(String s) {
StringBuilder myName = new StringBuilder(s);
int j=0;
for(int i=0;i<s.length()-1;i++) {
if(s.charAt(i)!=s.charAt(i+1)) {
myName.setCharAt(j, s.charAt(i));
j++;
}
}
return myName.toString();
}
You can not do such assignment like sn.charAt(j)=s.charAt(i); since charAt() is function that returns the result, but not a variable. You could use StringBuilder here:
static String superReducedString(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.length() == i+1 || s.charAt(i) != s.charAt(i + 1)) {
sb.append(s.charAt(i));
} else {
i++;
}
}
return sb.toString();
}
s.length() == i+1 checks if it's the last char. In case aabaccr the result will be as expected bar
Just another solution, in case the other answers don't work for you:
static String superReducedString(String s) {
char[] chars = s.toCharArray();
String lastChar = "";
ArrayList<String> newString = new ArrayList<>();
for (char aChar : chars) {
String currentChar = String.valueOf(aChar);
if (lastChar.equals(currentChar))
newString.remove(newString.size() - 1);
else {
newString.add(currentChar);
lastChar = currentChar;
}
}
AtomicReference<String> returnString = new AtomicReference<>("");
newString.forEach(character-> returnString.set(returnString + character));
return returnString.get();
}
The answer is quite simple.
you cannot delete anything from a String but you can move them to another String as you want.
public class Solution {
public static void main(String[] args) {
String s = "abbccd", s1 = "";
if(s.charAt(1) != s.charAt(0))
s1 += s.charAt(0);
if(s.charAt(s.length()-1) != s.charAt(s.length()-2))
s1 += s.charAt(s.length()-1);
for (int i = 1; i < s.length() - 1; i++) {
if (s.charAt(i) != s.charAt(i - 1) && s.charAt(i) != s.charAt(i + 1))
s1 += s.charAt(i);
}
System.out.println(s1);
}
}
You create another String.
Then in a for loop iterating from 1 (NOT 0) to s.length()-1 (NOT s.length()), you check if the s.charAt(i) (current character) is equal to the preceding or following one. If it's not equal to any of them, you add it to the second String and then you print it. We are checking both sides so that's why the loop is from 1 to s.length()-1, to avoid out of bounds exceptions.
EDIT: to check the first and last character.
Please help me to identify my mistakes in this code. I am new to Java. Excuse me if I have done any mistake. This is one of codingbat java questions. I am getting Timed Out error message for some inputs like "xxxyakyyyakzzz". For some inputs like "yakpak" and "pakyak" this code is working fine.
Question:
Suppose the string "yak" is unlucky. Given a string, return a version where all the "yak" are removed, but the "a" can be any char. The "yak" strings will not overlap.
public String stringYak(String str) {
String result = "";
int yakIndex = str.indexOf("yak");
if (yakIndex == -1)
return str; //there is no yak
//there is at least one yak
//if there are yaks store their indexes in the arraylist
ArrayList<Integer> yakArray = new ArrayList<Integer>();
int length = str.length();
yakIndex = 0;
while (yakIndex < length - 3) {
yakIndex = str.indexOf("yak", yakIndex);
yakArray.add(yakIndex);
yakIndex += 3;
}//all the yak indexes are stored in the arraylist
//iterate through the arraylist. skip the yaks and get non-yak substrings
for(int i = 0; i < length; i++) {
if (yakArray.contains(i))
i = i + 2;
else
result = result + str.charAt(i);
}
return result;
}
Shouldn't you be looking for any three character sequence starting with a 'y' and ending with a 'k'? Like so?
public static String stringYak(String str) {
char[] chars = (str != null) ? str.toCharArray()
: new char[] {};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == 'y' && chars[i + 2] == 'k') { // if we have 'y' and two away is 'k'
// then it's unlucky...
i += 2;
continue; //skip the statement sb.append
} //do not append any pattern like y1k or yak etc
sb.append(chars[i]);
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(stringYak("1yik2yak3yuk4")); // Remove the "unlucky" strings
// The result will be 1234.
}
It looks like your programming assignment. You need to use regular expressions.
Look at http://www.vogella.com/articles/JavaRegularExpressions/article.html#regex for more information.
Remember, that you can not use contains. Your code maybe something like
result = str.removeall("y\wk")
you can try this
public static String stringYak(String str) {
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i)=='y'){
str=str.replace("yak", "");
}
}
return str;
}