Leetcode problem 125. Valid Palindromeļ¼
Given a string s, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Example 1:
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
I appended each character into two linked lists, one forwards and one backwards, and compared them. However, I did not pass the time limit. The Leetcode's solution used a StringBuilder and reversed it. I heard that StringBuilder is implemented similar to a linked list. I have no idea why my code is much slower than the solution. I would appreciate any feedback or insights on this topic. Thank you in advance.
My code:
class Solution {
public boolean isPalindrome(String s) {
LinkedList<Character> forward = new LinkedList<Character>();
LinkedList<Character> backward = new LinkedList<Character>();
for(int i = 0 ; i < s.length() ; i++){
char ch = s.charAt(i);
if(Character.isLetterOrDigit(ch)){
if(Character.isLetter(ch)) ch = Character.toLowerCase(ch);
forward.addLast(ch);
backward.addFirst(ch);
}
}
for(int i = 0 ; i < forward.size() ; i++){
if(forward.get(i) != backward.get(i)) return false;
}
return true;
}
}
Leetcode Solution:
class Solution {
public boolean isPalindrome(String s) {
StringBuilder builder = new StringBuilder();
for (char ch : s.toCharArray()) {
if (Character.isLetterOrDigit(ch)) {
builder.append(Character.toLowerCase(ch));
}
}
String filteredString = builder.toString();
String reversedString = builder.reverse().toString();
return filteredString.equals(reversedString);
}
}
If you look at how reverse() method is implemented in AbstractStringBuilder you can see that it uses array to store characters. It is the main difference between StringBuilder and your solution. forward.get(i) and backward.get(i) have O(n) complexity, when value[j] has O(1).
Java 8 implementation:
public AbstractStringBuilder reverse() {
boolean hasSurrogates = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
char cj = value[j];
char ck = value[k];
value[j] = ck;
value[k] = cj;
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
}
}
if (hasSurrogates) {
reverseAllValidSurrogatePairs();
}
return this;
}
Actually, Leetcode solution does not seem to be the best and StringBuilder::reverse method does not have to be used at all to detect a palindrome, because it is possible to check the characters from the start and end of the string to its center and as soon as unmatching pair is found the string is NOT a palindrome.
Also conversion of StringBuilder to direct and reversed strings is redundant.
class Solution {
public boolean isPalindrome(String s) {
StringBuilder builder = new StringBuilder(s.length());
for (char ch : s.toCharArray()) {
if (Character.isLetterOrDigit(ch)) {
builder.append(Character.toLowerCase(ch));
}
}
for (int i = 0, n = builder.length(), m = n / 2; i < m; i++) {
if (builder.charAt(i) != builder.charAt(n - i - 1)) {
return false;
}
}
return true;
}
}
Similar solution using Stream API and a regexp to clean out non-letter and non-digit characters (in Unicode):
public static boolean isPalindrome(String s) {
String str = s.replaceAll("[^\\p{L}\\p{N}]", "").toLowerCase();
final int n = str.length();
return IntStream.range(0, n / 2)
.allMatch(i -> str.charAt(i) == str.charAt(n - 1 - i));
}
How would I replace a string like "Hello" with "Helko", only replacing the second L but not the first?
Use replaceAll with regular expression:
System.out.println("Hello".replaceAll("((?!^).*?|[^l]*l.*?)l","$1k"));
Simple Approach (based on excluding the second l):
Search for first index of l using indexOf and do another search for l but this time start searching from firstL + 1 which will lead to the second index l if exist!
Do a test if there is second l, If So Exclude the second l by using substring which take only the first part (start from zero till secondL) and second part (start from secondL+1 till the end), Concatenate them with k.
public static String removeSecondL(String str) {
int firstL = str.indexOf('l');
int secondL = str.indexOf('l', firstL+1);
if(secondL != -1) {
String firstPart = str.substring(0, secondL);
String secondPart = str.substring(secondL + 1);
return firstPart + 'k' + secondPart;
}
return str;
}
Tests:
public static void main(String[] args) {
System.out.println(removeSecondL("Hello")); // Helko
System.out.println(removeSecondL("lololo")); // lokolo
System.out.println(removeSecondL("no l")); // no l
}
Another Approach: Convert the String into a char array, and declare a variable lFound gonna look for the first occurrence of letter l, if it found next l will be converted to k and exit the loop by break.
String str = "Hello";
char[] chars = str.toCharArray();
boolean lFound = false;
for (int i = 0; i < chars.length; i++) {
if(lFound) {
if(chars[i] == 'l')
{
chars[i] = 'K';
break;
}
}else {
lFound = chars[i] == 'l'; //if(chars[i] == 'l') lFound = true;
}
}
System.out.println(chars); //HelKo
Lately, I turned to the conversation and I saw you writing:
I wanted to replace one instance of a character with another, like "aaaaa" with "aabaa", where only the third 'a' is replaced with 'b', but not the others.
Just follow second approach I posted with additional tests.
public static char[] removeSpecificChar(String str, char a, char b, int position) {
char[] chars = str.toCharArray();
int pos = 1;
for (int i = 0; i < chars.length; i++) {
if(pos == position) {
if(chars[i] == a)
{
chars[i] = b;
break;
}
}else {
pos += (chars[i] == a) ? 1 : 0;
}
}
return chars;
}
Test:
String str = "aaaaa";
System.out.println(removeSpecificChar(str, 'a', 'b', 3));
Print:
aabaa
Can someone help me with algorith.
Basicaly if I have word Hello,I should take last letter and put in first position,then take penultimate letter and put it after second letter and so on,take third letter and put it in third position.
It should look like that:
Word:Hello
1)oHell
2)oHlel
This is my code which I have by right now.
public static String caesarAlgorithm(
String word) {
char[] arr = word.toCharArray();
int s=arr.length-1;
for (int i=0; i<arr.length/2; i++) {
char temp = arr[i];
char temp1=arr[i+1];
arr[i] = arr[s];
arr[i+1] = temp;
s--;
}
return new String(arr);
}
public static void main(String[] args) {
System.out.print(caesarAlgorithm("Sokolade"));
}
}
It should outpirnt in my case eSdoaklo
Thanks.
Put the result in a new String. That way, you won't have to handle the index shifting on each permutation.
public static String caesarAlgorithm(String word) {
char[] arr = word.toCharArray();
String result = "";
for (int i=0; i<arr.length/2; i++) {
// get the i-th letter from the end and put it in the result string
result += arr[arr.length-1-i]; // -1 because index starts at 0
// get the i-th letter from the begining and put it in the result string
result += arr[i];
}
if (arr.length%2 != 0) {
// in case the number of characters is odd, add the middle character to the end of the string
result += arr[arr.length%2+1];
}
return result;
}
Side Note:
The method name is missleading as it is not a ceasar cipher algorithm. With a caesar cipher, you change all of the character values with the same offset, but their index doesn't change.
This kind of problem has a natural recursive structure:
static String shake(String str, int n)
{
if(n == 0) return str;
String lastChar = str.substring(str.length()-1);
String firstChar = str.substring(0, 1);
String middle = str.substring(1, str.length()-1);
return lastChar + firstChar + shake(middle, n-1);
}
Called via the helper function:
static String shake(String str)
{
return shake(str, str.length()/2);
}
Test:
System.out.println(shake("Hello"));
System.out.println(shake("Sokolade"));
Output:
oHlel
eSdoaklo
public static String caesarAlgorithm(String word) {
StringBuilder builder = new StringBuilder();
int len = word.length();
int mid = len / 2;
int i = 0, j = len - 1;
while (i < mid && j > 0) {
builder.append(word.charAt(j--) + "").append(word.charAt(i++) + "");
}
if (len % 2 != 0)
builder.append(word.charAt(mid));
return builder.toString();
}
, output
oHlel
eSdoaklo
I am currently implementing Run Length Encoding for text compression and my algorithm does return Strings of the following form:
Let's say we have a string as input
"AAAAABBBBCCCCCCCC"
then my algorithm returns
"1A2A3A4A5A1B2B3B4B1C2C3C4C5C6C7C8C"
Now I want to apply Java String split to solve this, because I want to get the highest number corresponding to character. For our example it would be
"5A4B8C"
My function can be seen below
public String getStrfinal(){
String result = "";
int counter = 1;
StringBuilder sb = new StringBuilder();
sb.append("");
for (int i=0;i<str.length()-1;i++) {
char c = str.charAt(i);
if (str.charAt(i)==str.charAt(i+1)) {
counter++;
sb.append(counter);
sb.append(c);
}
else {
counter = 1;
continue;
}
}
result = sb.toString();
return result;
}
public static String getStrfinal(){
StringBuilder sb = new StringBuilder();
char last = 0;
int count = 0;
for(int i = 0; i < str.length(); i++) {
if(i > 0 && last != str.charAt(i)) {
sb.append(count + "" + last);
last = 0;
count = 1;
}
else {
count++;
}
last = str.charAt(i);
}
sb.append(count + "" + last);
return sb.toString();
}
Here is one possible solution. It starts with the raw string and simply iterates thru the string.
public static void main(String[] args) {
String input = "AAAABBBCCCCCCCDDDEAAFBBCD";
int index = 0;
StringBuilder sb = new StringBuilder();
while (index < input.length()) {
int count = 0;
char c = input.charAt(index);
for (; index < input.length(); index++) {
if (c != input.charAt(index)) {
count++;
}
else {
break;
}
}
sb.append(Integer.toString(count));
sb.append(c);
count = 0;
}
System.out.println(sb.toString());
}
But one problem with this method and others is what happens if there are digits in the text? For example. What if the string is AAABB999222AAA which would compress to 3A2B39323A. That could also mean AAABB followed by 39 3's and 23 A's
Instead of string Buffer you can use a map it will be much easier and clean to do so.
public static void main(String[] args) {
String input = "AAAAABBBBCCCCCCCCAAABBBDDCCCC";
int counter=1;
for(int i=1; i<input.length(); i++) {
if(input.charAt(i-1)==input.charAt(i)) {
counter=counter+1;
}else if(input.charAt(i-1)!=input.charAt(i)){
System.out.print(counter+Character.toString(input.charAt(i-1)));
counter=1;
}if(i==input.length()-1){
System.out.print(counter+Character.toString(input.charAt(i)));
}
}
}
This will gives
5A4B8C3A3B2D4C
UPDATES
I Agree with #WJS if the string contains number the out put becomes messy
hence if the System.out in above code will be exchange with below i.e.
System.out.print(Character.toString(input.charAt(i-1))+"="+counter+" ");
then for input like
AAAAABBBBCCCCCCCCAAABBBDD556677CCCCz
we get out put as below
A=5 B=4 C=8 A=3 B=3 D=2 5=2 6=2 7=2 C=4 z=1
This is one of the possible solutions to your question. We can use a LinkedHashMap data structure which is similar to HashMap but it also maintains the order. So, we can traverse the string and store the occurrence of each character as Key-value pair into the map and retrieve easily with its maximum occurrence.
public String getStrFinal(String str){
if(str==null || str.length()==0) return str;
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
StringBuilder sb=new StringBuilder(); // to store the final string
for(char ch:str.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1); // put the count for each character
}
for(Map.Entry<Character,Integer> entry:map.entrySet()){ // iterate the map again and append each character's occurence into stringbuilder
sb.append(entry.getValue());
sb.append(entry.getKey());
}
System.out.println("String = " + sb.toString()); // here you go, we got the final string
return sb.toString();
}
For accessing individual characters of a String in Java, we have String.charAt(2). Is there any inbuilt function to remove an individual character of a String in java?
Something like this:
if(String.charAt(1) == String.charAt(2){
//I want to remove the individual character at index 2.
}
You can also use the StringBuilder class which is mutable.
StringBuilder sb = new StringBuilder(inputString);
It has the method deleteCharAt(), along with many other mutator methods.
Just delete the characters that you need to delete and then get the result as follows:
String resultString = sb.toString();
This avoids creation of unnecessary string objects.
You can use Java String method called replace, which will replace all characters matching the first parameter with the second parameter:
String a = "Cool";
a = a.replace("o","");
One possibility:
String result = str.substring(0, index) + str.substring(index+1);
Note that the result is a new String (as well as two intermediate String objects), because Strings in Java are immutable.
No, because Strings in Java are immutable. You'll have to create a new string removing the character you don't want.
For replacing a single char c at index position idx in string str, do something like this, and remember that a new string will be created:
String newstr = str.substring(0, idx) + str.substring(idx + 1);
String str = "M1y java8 Progr5am";
deleteCharAt()
StringBuilder build = new StringBuilder(str);
System.out.println("Pre Builder : " + build);
build.deleteCharAt(1); // Shift the positions front.
build.deleteCharAt(8-1);
build.deleteCharAt(15-2);
System.out.println("Post Builder : " + build);
replace()
StringBuffer buffer = new StringBuffer(str);
buffer.replace(1, 2, ""); // Shift the positions front.
buffer.replace(7, 8, "");
buffer.replace(13, 14, "");
System.out.println("Buffer : "+buffer);
char[]
char[] c = str.toCharArray();
String new_Str = "";
for (int i = 0; i < c.length; i++) {
if (!(i == 1 || i == 8 || i == 15))
new_Str += c[i];
}
System.out.println("Char Array : "+new_Str);
To modify Strings, read about StringBuilder because it is mutable except for immutable String. Different operations can be found here https://docs.oracle.com/javase/tutorial/java/data/buffers.html. The code snippet below creates a StringBuilder and then append the given String and then delete the first character from the String and then convert it back from StringBuilder to a String.
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.deleteCharAt(0);
str = sb.toString();
Consider the following code:
public String removeChar(String str, Integer n) {
String front = str.substring(0, n);
String back = str.substring(n+1, str.length());
return front + back;
}
You may also use the (huge) regexp machine.
inputString = inputString.replaceFirst("(?s)(.{2}).(.*)", "$1$2");
"(?s)" - tells regexp to handle newlines like normal characters (just in case).
"(.{2})" - group $1 collecting exactly 2 characters
"." - any character at index 2 (to be squeezed out).
"(.*)" - group $2 which collects the rest of the inputString.
"$1$2" - putting group $1 and group $2 together.
If you want to remove a char from a String str at a specific int index:
public static String removeCharAt(String str, int index) {
// The part of the String before the index:
String str1 = str.substring(0,index);
// The part of the String after the index:
String str2 = str.substring(index+1,str.length());
// These two parts together gives the String without the specified index
return str1+str2;
}
By the using replace method we can change single character of string.
string= string.replace("*", "");
Use replaceFirst function of String class. There are so many variants of replace function that you can use.
If you need some logical control over character removal, use this
String string = "sdsdsd";
char[] arr = string.toCharArray();
// Run loop or whatever you need
String ss = new String(arr);
If you don't need any such control, you can use what Oscar orBhesh mentioned. They are spot on.
Easiest way to remove a char from string
String str="welcome";
str=str.replaceFirst(String.valueOf(str.charAt(2)),"");//'l' will replace with ""
System.out.println(str);//output: wecome
public class RemoveCharFromString {
public static void main(String[] args) {
String output = remove("Hello", 'l');
System.out.println(output);
}
private static String remove(String input, char c) {
if (input == null || input.length() <= 1)
return input;
char[] inputArray = input.toCharArray();
char[] outputArray = new char[inputArray.length];
int outputArrayIndex = 0;
for (int i = 0; i < inputArray.length; i++) {
char p = inputArray[i];
if (p != c) {
outputArray[outputArrayIndex] = p;
outputArrayIndex++;
}
}
return new String(outputArray, 0, outputArrayIndex);
}
}
In most use-cases using StringBuilder or substring is a good approach (as already answered). However, for performance critical code, this might be a good alternative.
/**
* Delete a single character from index position 'start' from the 'target' String.
*
* ````
* deleteAt("ABC", 0) -> "BC"
* deleteAt("ABC", 1) -> "B"
* deleteAt("ABC", 2) -> "C"
* ````
*/
public static String deleteAt(final String target, final int start) {
return deleteAt(target, start, start + 1);
}
/**
* Delete the characters from index position 'start' to 'end' from the 'target' String.
*
* ````
* deleteAt("ABC", 0, 1) -> "BC"
* deleteAt("ABC", 0, 2) -> "C"
* deleteAt("ABC", 1, 3) -> "A"
* ````
*/
public static String deleteAt(final String target, final int start, int end) {
final int targetLen = target.length();
if (start < 0) {
throw new IllegalArgumentException("start=" + start);
}
if (end > targetLen || end < start) {
throw new IllegalArgumentException("end=" + end);
}
if (start == 0) {
return end == targetLen ? "" : target.substring(end);
} else if (end == targetLen) {
return target.substring(0, start);
}
final char[] buffer = new char[targetLen - end + start];
target.getChars(0, start, buffer, 0);
target.getChars(end, targetLen, buffer, start);
return new String(buffer);
}
*You can delete string value use the StringBuilder and deletecharAt.
String s1 = "aabc";
StringBuilder sb = new StringBuilder(s1);
for(int i=0;i<sb.length();i++)
{
char temp = sb.charAt(0);
if(sb.indexOf(temp+"")!=1)
{
sb.deleteCharAt(sb.indexOf(temp+""));
}
}
To Remove a Single character from The Given String please find my method hope it will be usefull. i have used str.replaceAll to remove the string but their are many ways to remove a character from a given string but i prefer replaceall method.
Code For Remove Char:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class Removecharacter
{
public static void main(String[] args)
{
String result = removeChar("Java", 'a');
String result1 = removeChar("Edition", 'i');
System.out.println(result + " " + result1);
}
public static String removeChar(String str, char c) {
if (str == null)
{
return null;
}
else
{
return str.replaceAll(Character.toString(c), "");
}
}
}
Console image :
please find The Attached image of console,
Thanks For Asking. :)
public static String removechar(String fromString, Character character) {
int indexOf = fromString.indexOf(character);
if(indexOf==-1)
return fromString;
String front = fromString.substring(0, indexOf);
String back = fromString.substring(indexOf+1, fromString.length());
return front+back;
}
BufferedReader input=new BufferedReader(new InputStreamReader(System.in));
String line1=input.readLine();
String line2=input.readLine();
char[] a=line2.toCharArray();
char[] b=line1.toCharArray();
loop: for(int t=0;t<a.length;t++) {
char a1=a[t];
for(int t1=0;t1<b.length;t1++) {
char b1=b[t1];
if(a1==b1) {
StringBuilder sb = new StringBuilder(line1);
sb.deleteCharAt(t1);
line1=sb.toString();
b=line1.toCharArray();
list.add(a1);
continue loop;
}
}
When I have these kinds of questions I always ask: "what would the Java Gurus do?" :)
And I'd answer that, in this case, by looking at the implementation of String.trim().
Here's an extrapolation of that implementation that allows for more trim characters to be used.
However, note that original trim actually removes all chars that are <= ' ', so you may have to combine this with the original to get the desired result.
String trim(String string, String toTrim) {
// input checks removed
if (toTrim.length() == 0)
return string;
final char[] trimChars = toTrim.toCharArray();
Arrays.sort(trimChars);
int start = 0;
int end = string.length();
while (start < end &&
Arrays.binarySearch(trimChars, string.charAt(start)) >= 0)
start++;
while (start < end &&
Arrays.binarySearch(trimChars, string.charAt(end - 1)) >= 0)
end--;
return string.substring(start, end);
}
public String missingChar(String str, int n) {
String front = str.substring(0, n);
// Start this substring at n+1 to omit the char.
// Can also be shortened to just str.substring(n+1)
// which goes through the end of the string.
String back = str.substring(n+1, str.length());
return front + back;
}
I just implemented this utility class that removes a char or a group of chars from a String. I think it's fast because doesn't use Regexp. I hope that it helps someone!
package your.package.name;
/**
* Utility class that removes chars from a String.
*
*/
public class RemoveChars {
public static String remove(String string, String remove) {
return new String(remove(string.toCharArray(), remove.toCharArray()));
}
public static char[] remove(final char[] chars, char[] remove) {
int count = 0;
char[] buffer = new char[chars.length];
for (int i = 0; i < chars.length; i++) {
boolean include = true;
for (int j = 0; j < remove.length; j++) {
if ((chars[i] == remove[j])) {
include = false;
break;
}
}
if (include) {
buffer[count++] = chars[i];
}
}
char[] output = new char[count];
System.arraycopy(buffer, 0, output, 0, count);
return output;
}
/**
* For tests!
*/
public static void main(String[] args) {
String string = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
String remove = "AEIOU";
System.out.println();
System.out.println("Remove AEIOU: " + string);
System.out.println("Result: " + RemoveChars.remove(string, remove));
}
}
This is the output:
Remove AEIOU: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Result: TH QCK BRWN FX JMPS VR TH LZY DG
For example if you want to calculate how many a's are there in the String, you can do it like this:
if (string.contains("a"))
{
numberOf_a++;
string = string.replaceFirst("a", "");
}