I want to write codes using a static recursive method in Java, cleanString(String s) that accepts a string of letters s and returns a string where adjacent letters that are the same are replaced by a single occurrence of that letter. The method is case-sensitive.
For example:
cleanString("sensssaatiionnaallll!") -> "sensational!"
cleanString("PPProoggggraamm") -> "Program"
cleanString("Lletterriiing") -> "Lletering"
Try this:
public class Main {
public static void main(String[] args) {
System.out.println(cleanString("sensssaatiionnaallll!"));
}
static String cleanString(String input)
{
if(input.length()<1) //To stop infinite recursion
return input;
var first = input.charAt(0);
var count = input.chars().takeWhile(x -> x == first).count();
return first + cleanString(input.substring((int)count));
}
}
First, it checks if the length of the string is less than 1. If it is, return the string itself (which is empty) and stop the recursion.
Next get the first character of the string. (e.g PPProoggggraamm -> P)
Get the number of characters in the start that equal the first character (3 in the case of PPProoggggraamm)
Call the function again, but this time lopping off the first n characters from the above step, and prepending the first character. ('P' + cleanString("rooggggraamm"))
Shortest recursive code to remove adjacent characters from the input string.
public class StackOverflow {
static String cleanString(String input) {
return input==null || input.length()<=1?input:cleanStringWrapper(input.substring(1),input.substring(0,1));
}
static String cleanStringWrapper(String input, String result) {
if (input.length() - 1 <= 0) {
return result+(result.charAt(result.length() - 1)!=input.charAt(0)?input:"");
} else {
return cleanStringWrapper(input.substring(1), result+(result.charAt(result.length() - 1) != input.charAt(0)?input.charAt(0):""));
}
}
public static void main(String[] args)
{
System.out.println(cleanString("OOPS"));
}
}
Output:
cleanString("sensssaatiionnaallll!") -> "sensational!"
cleanString("PPProoggggraamm") -> "Program"
cleanString("Lletterriiing") -> "Lletering"
cleanString("Gooooogle") -> "Gogle"
cleanString("ABC") -> "ABC"
cleanString("A") -> "A"
cleanString("") -> ""
cleanString(null) -> null
It just generate a new String and exclude the repeat characters.
static String cleanString(String input) {
if(input == null) return null;
char lastChar = 0;
StringBuilder output = new StringBuilder(input.length());
for (int i=0,n=input.length(); i<n; i++) {
char c = input.charAt(i);
if(c != lastChar) {
lastChar = c;
output.append(c);
}
}
return output.toString();
}
Recursive method:
public class Example {
public static int main(String[] args) {
String input = "sensssaatiionnaallll";
String output = cleanString(input, 0);
System.out.println(output); // print: sensational
return 0;
}
private static String cleanString(String input, int index) {
if(input == null) return "";
if(index >= input.length()) return "";
StringBuilder output = new StringBuilder();
char current = input.charAt(index);
int nextIndex = index + 1;
if(nextIndex >= input.length()) {
return output.append(current).toString();
}
char next = input.charAt(nextIndex);
if (current != next) {
output.append(current);
}
output.append(cleanString(input, nextIndex));
return output.toString();
}
}
Why you want to make static method for that?
Whay i understood is that you want to remove repeated characters from your input string.
You can do it below code as well.
StringBuilder sb = new StringBuilder();
str.chars().distinct().forEach(c -> sb.append((char) c));
If you want you can make a method of this 2 lines as a feature in your code.
Hope this helps!
Related
Following is the function that I have, it gives me desired result but I wanted to know if there is other way to approach this? May be with nested for loop?
public class RandomFunctionalities2 {
public String mixWords(String firstWord, String secondWord) {
return firstWord+secondWord;
}
public String switcheroo(String word) {
if (word.length() < 3) {
return word;
}
StringBuilder c = new StringBuilder();
int i;
for (i = 0; i < 3 * (word.length() / 3); i+=3)
c.append(word.substring(i + 1, i + 3) + word.charAt(i));
c.append(word.substring(i));
return c.toString();
}
}
TEST*
public class testingRandomFunctionalities2 {
public static void main(String[] args) {
RandomFunctionalities2 rf1 = new RandomFunctionalities2();
System.out.println(rf1.switcheroo("george"));
System.out.println(rf1.switcheroo("you"));
}
}
TEST RESULT*
eogger
ouy
Process finished with exit code 0
Another approach could be to split your input at every 3rd char and join back after swaping first and third chars of each substring:
public String switcheroo2(String word) {
String[] split = word.split("(?<=\\G...)");
StringBuilder sb = new StringBuilder();
for (String s : split){
if(s.length() > 2){
sb.append(s.substring(1)).append(s.charAt(0));
}
else {
sb.append(s);
}
}
return sb.toString();
}
You could save somemore lines using Pattern class and streams by doing something like:
public String switcheroo3(String word) {
UnaryOperator<String> op = str -> str.length() < 3 ? str : str.substring(1) + str.charAt(0);
return Pattern.compile("(?<=\\G...)")
.splitAsStream(word).map(op::apply)
.collect(Collectors.joining());
}
Like in question, exercise if it is possible to create a palindromic string of minimum length 3 characters by removing 1 or 2 characters. For example string "abjchba", we can remove letters "jc" and will get palindromic, in this case program should return removed letters so "jc". I know that we can mke palindromic by removing also "ch" but in exercise is that we should remove characters that appear earlier in string. Program should always attempt to create the longest palindromic substring. I wrote methods to reverse String and method to check that string is palindromic:
private static String reverse(String string) {
return new StringBuilder(string).reverse().toString();
}
private static boolean isPalin(String string) {
return string.equals(reverse(string));
}
I also made method to create Palindromic to return symbols we should remove to make palindromic, but beacuse i'm working on sb 'temp' I got exception . Have anyone idea how to fix it and finish exercise?
private static String createPalindrome(String str) {
StringBuilder result = new StringBuilder();
StringBuilder temp = new StringBuilder(str);
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == str.charAt(str.length() - 1 - i)){
continue;
}else {
result.append(str.charAt(i));
temp.deleteCharAt(i);
if (isPalin(temp.toString())){
return result.toString();
}
}
}
return "not possible";
}
Method 1:
Find longest palindromic subsequence(LPS)
Given string: "abjchba"
Longest Palindrome Subsequence: "abhba". Others like "abjba" and "abcba" also are LPS but you want to remove chars that appear earlier so that "abhba".
If (input string length - length of LPS) > 2, return "not possible".
Remove letters from the input string that are not in the LPS.
Start matching string with LPS. 'j' and 'c' won't match. Add them to result and return.
Method 2:
Find longest common subsequence (LCS) between input string and its reverse.
String: "abjchba"
Reverse: "abhcjba"
LCS: Take "abhba" in our case
If (input string length - length of LCS) > 2, return "not possible".
Step 2 will be the same as that of in Method 1 above.
As you are trying for at most 2 deletions, I am thinking if we can do better with time complexity.
I think the simplest way to fix your code is to use recursion. When you find a char that does not match, remove it and call recursively.
// Helper function to remove a character from a string
public static String removeAt(String s, int i)
{
return s.substring(0, i) + s.substring(i + 1);
}
private static String createPalindromeRecursive(String str) {
// Only need to check half the string
for (int i = 0, j = str.length() - 1; i < j; i++, j--) {
// if (something) continue; else {} <- the else is not needed
// because the continue skips to the end of the loop
// or you can negate the condition and don't use continue
if (str.charAt(i) == str.charAt(j)){
continue;
}
String temp = createPalindrome(removeAt(str, i));
// Success. Return the new string
if (null != temp) return temp;
else return null;
}
return str;
}
private static String createPalindrome(String str) {
String palindrome = createPalindromeRecursive(str);
if (palindrome == null || palindrome.length() < str.length() - 2) {
return "not possible";
}
else {
return palindrome;
}
}
using System;
using System.Text;
class MainClass
{
public static String removeAt(String s, int i)
{
return s.Substring(0, i) + s.Substring(i + 1);
}
private static String createPalindromeRecursive(String str)
{
for (int i = 0, j = str.Length - 1; i < j; i++, j--)
{
if (str[i] == str[j])
{
continue;
}
String temp = PalindromeCreator(removeAt(str, i));
if (null != temp) return temp;
else return null;
}
return str;
}
public static string PalindromeCreator(string str)
{
String palindrome = createPalindromeRecursive(str);
StringBuilder result = new StringBuilder();
StringBuilder temp = new StringBuilder(str);
if (palindrome == null || palindrome.Length < str.Length - 2)
{
return "not possible";
}
else
{
for (int i = 0; i < str.Length; i++)
{
if (str[i] == str[(str.Length - 1 - i)])
{
continue;
}
else
{
result.Append(str[i]);
temp.Remove(i, str.Length);
return result.ToString();
}
}
return palindrome;
}
}
static void Main()
{
// keep this function call here
Console.WriteLine(PalindromeCreator(Console.ReadLine()));
}
}
I am new to Java and am trying to create a method that will allow me to remove duplicate characters in a string and create a new string with all the consecutive occurrences of the same character turned into a single character. For example, string fffggghhh would return as fgh. I have provided my code below but I am receiving an index out of range error with the length of the string that I input. For example when testing this method and entering AA as my string, I receive an index out of range 2 error.
public String DuplicatesTEST(String s) {
StringBuilder result = new StringBuilder();
for (int i = 1; i <= s.length(); i++) {
char curr = s.charAt(i);
char prev = s.charAt(0);
if (curr != prev) {
result.append(prev);
} else if (curr == prev)
prev = curr;
}
return result.toString();
}
Behavior of Data structure Set is not containing duplicates, so use Set to remove duplicates.
Try something like this:
public String DuplicatesTEST(String s) {
Set<Character> set = new HashSet<>();
StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
set.add(s.charAt(i));
}
set.forEach(result::append);
return result.toString();
}
for fffggghhhff input this return fgh.
If you want to remove duplicates with a block above solution not help then I did small change to your implementation:
public String DuplicatesTEST(String s) {
StringBuilder result = new StringBuilder();
if (s != null && !s.isEmpty()) {
char first = s.charAt(0);
for (int i = 1; i < s.length(); i++) {
if (first != s.charAt(i)) {
result.append(first);
first = s.charAt(i);
}
}
result.append(first);
}
return result.toString();
}
for fffggghhhff input this return fghf.
You can transform your method to recursive and use regexp. This greatly simplifies your code.
Try it online!
public static String removeDuplicates(String str) {
if (str.equals(str = str.replaceAll("(.)\\1", "$1")))
return str;
else
return removeDuplicates(str);
}
public static void main(String[] args) {
System.out.println(removeDuplicates("aaaaaaa")); // a
System.out.println(removeDuplicates("fffggghhh")); // fgh
System.out.println(removeDuplicates("fffggghhhff")); // fghf
}
Explanation:
regexp (.)\\1 - any character followed by the same character;
regexp $1 - replace with a character from the 1st group, i.e. the same character;
str = str.replaceAll(...) - removes all duplicates and replaces current string;
str.equals(...) - checks equality of the current string with itself, but without duplicates.
See also: Remove a pair of chars in a string next to each other
Strings are 0 based Index.
As per your input, If duplicate characters are consecutive orders then you can store first character from your input string into result StringBuilder.
Also, in your code, prev always stars at 0 which is wrong. You need to keep increment it too.
Here is is fixed version of your code:
public static String DuplicatesTEST(String s) {
StringBuilder result = new StringBuilder();
result.append(s.charAt(0));
for (int i = 1; i < s.length(); i++) {
char prev = s.charAt(i);
char curr = s.charAt(i - 1);
if (curr != prev || i == 0) {
result.append(prev);
}
else if (curr == prev) {
prev = curr;
}
}
return result.toString();
}
This is a recursion program to test whether or not a sentence is a palindrome. It will run correctly if I write "bob" but not for "Madam I'm Adam" because of the caps and symbols. We are required to use a clean string method(?) to eliminate the spaces, symbols, and caps. This is what I have but I don't believe I've implemented it correctly. Could someone tell me how to improve/fix this? (Yes, I've looked all over the internet)
import java.util.Scanner;
public class Palindromes {
public static boolean isaPalindrome(String s) {
String cleanedString = clean(s);
if (s.length() == 0 || s.length() == 1)
return true;
if (s.charAt(0) == s.charAt(s.length() - 1))
return isaPalindrome(s.substring(1, s.length() - 1));
return false;
}
public static void main(String[] args) {
System.out.print("Enter a palindrome to test: ");
Scanner console = new Scanner(System.in);
String inStr = console.nextLine();
if (isaPalindrome(inStr)) {
System.out.printf("The input string, %s, is a palindrome.\n",
inStr);
reverseStr(inStr); // must be recursive!
System.out.println();
} else {
System.out.printf("The input string, %s, is not a palindrome.\n",
inStr);
}
}
private static String clean(String s) {
String cleaned = "";
return cleaned;
}
private static String reverseStr(String inStr) {
if ((null == inStr) || (inStr.length() <= 1)) {
return inStr;
}
return reverseStr(inStr.substring(1)) + inStr.charAt(0);
}
}
Your recursive method isaPalindrome is correct. If you want to further improve it, I would suggest you to avoid using subString to create parameters for your recursive call, this will create too many strings.
Instead, keep track of the positions of the characters in the original string that you are comparing:
public static boolean isaPalindrome(String s, int leftIndex, int rightIndex) {
if (leftIndex == rightIndex) return true;
if (s.charAt(leftIndex) == s.charAt(rightIndex))
return isaPalindrome(s, leftIndex + 1, rightIndex - 1);
return false;
}
You would invoke the method as: isaPalindrome(inStr, 0, inStr.length() - 1)
As for your clean method, you can use toLowerCase and Character.isLetter method to process the original string.
private static String clean(String s) {
String lowerCaseString = s.toLowerCase();
StringBuffer result = new StringBuffer();
for (int i = 0; i < lowerCaseString.length(); ++i) {
if (Character.isLetter(lowerCaseString.charAt(i))) {
result.append(lowerCaseString.charAt(i));
}
}
return result.toString();
}
Try this:
public static void main(final String[] args) {
final String unclean = "Madam I'm Adam";
final String clean = cleanString(unclean);
System.out.println("Clean string is: " + clean);
}
static private String cleanString(final String pTheString) {
final StringBuilder sb = new StringBuilder(pTheString.length());
for (final char c : pTheString.toCharArray()) {
switch (c) {
// ignore all those
case ' ':
case '\'':
case '.':
break;
// write the rest
default:
sb.append(c);
}
}
return sb.toString().toLowerCase();
}
Can someone please discuss and explain a way I can modify my code to function with these test cases... I am trying to make my program take a word and make it a palindrome by replacing one letter in a word that prevents the word from being a palindrome
Desired test cases:
Palindromes.isPalindrome2("cat", 'c') => true
Palindromes.isPalindrome2("axaa", 'x') => true
Palindromes.isPalindrome2("12bb", 'b') => true
Palindromes.isPalindrome2("ca", 'c') => true
This is what I have thus far...
public class Palindromes {
public static boolean isPalindrome(String word) {
//Strip out non-alphanumeric characters from string
String cleanWord = word.replaceAll("[^a-zA-Z0-9]","");
//Check for palindrome quality recursively
return checkPalindrome(cleanWord);
}
public static boolean isPalindrome2(String word) {
//Strip out non-alphanumeric characters from string
String cleanWord = word.replaceAll("[^a-zA-Z0-9]","");
//Check for palindrome quality recursively
return checkPalindrome2(cleanWord);
}
public static boolean checkPalindrome(String word) {
if(word.length() < 2) {
return true;
}
char first = word.charAt(0);
char last = word.charAt(word.length()-1);
if(first != last) {
return false;
}
else {
return checkPalindrome(word.substring(1,word.length()-1));
}
}
public void replace(int first, int last) {
if(first != last)
{ first = last;}
else if(last != first)
{ last = first;}
}
public static boolean checkPalindrome2(String word) {
char special = 0;
if(word.length() < 2) {
return true;
}
char first = word.charAt(0);
char last = word.charAt(word.length()-1);
if(first != last) {
return false;
}
if(first != last)
return false;
else {
return checkPalindrome2(word.substring(1,word.length()-1));
}
}
}
replace() was my attempt at handling the wildcard letter, but I cant seem to find the appropriate solution... All help will be greatly appreciated. thanks...
Here's my steps I would do:
Split the received string into 2 substrings. The first string front being the front half of the string, the second string back being the half end of the string.
Example:
char replacement = 'c';
String input = "aabbcc";
StringBuilder front = new StringBuilder(input.substring(0, input.length()/2));
// Do modulus to not include the odd middle (it mirrors itself)
StringBuilder back = new StringBuilder(input.substring((input.length()/2)+(input.length()%2));
Compare the two strings, replacing if one matches but the other doesn't. If neither match each other and is not the given 'replacement' character, return false. If you do more than one replacement, return false (since that is what you said the requirement is)
Example:
int replacements = 0;
for (int i=0; i < front.length(); ++i)
{
int backIndex = back.length() - i;
if (front.charAt(i) != back.charAt(backIndex))
{
// Characters do not match at all to given replacement
if ((front.charAt(i) != replacement) &&
(back.charAt(backIndex) != replacement)
{
// Cannot make it
// (Or if you want to force it, set both to replacement
// by deleting this one if statement)
return false;
}
// Front matches replacement
else if (front.charAt(i) == replacement)
{
// Replace back character with replacement
back.setCharAt(backIndex, replacement);
replacements++;
}
// Back matches replacement
else if (back.charAt(backIndex) == replacement)
{
// Replace front character with replacement
front.setCharAt(i, replacement);
replacements++;
}
if (replacements > 1)
{
// Can only replace one
return false;
}
}
}
String output = front.toString() + back.toString();
Here's my code, it splits the input into two halves, and compares the first half to the reversed second half. If they are equal, the input is already a palindrome. If they are not equal, it iterates through the first half, exchanging letters with the input char to replace with, and comparing with the reversed second half at every step. Then it does the same thing, but using the second half instead of the first half:
public class CanMakePalindrome {
public static void main(String[] args) {
System.out.println("cat using c: " + canMakePalindrome("cat", 'c'));
System.out.println("axaa using x: " + canMakePalindrome("axaa", 'x'));
System.out.println("12bb using b: " + canMakePalindrome("12bb", 'b'));
System.out.println("ca using c: " + canMakePalindrome("ca", 'c'));
}
private static boolean canMakePalindrome(String input, char c) {
int length = input.length();
String start = input.substring(0, length/2);
String end = input.substring(length/2+length%2, length); // need modulus in the case of odd length input
return (replaceLoop(start,end, c) || replaceLoop(end,start, c));
}
private static boolean replaceLoop(String start, String end, char c) {
if (start.equals(reverse(end))) {
System.out.println("Input is already a palindrome.");
return true;
}
for (int i=0; i<start.length(); i++) {
char[] startchars = start.toCharArray();
char[] endchars = end.toCharArray();
endchars = reverse(endchars);
startchars[i] = c;
if ((new String(startchars).equals(new String(endchars)))) return true;
}
return false;
}
private static char[] reverse(char[] input) {
int length = input.length;
char[] reversed = new char[length];
for (int i=0;i<length;i++) {
reversed[length-i-1]=input[i];
}
return reversed;
}
private static String reverse(String input){
String reversed = new String(reverse(input.toCharArray()));
return reversed;
}
}
Output:
cat using c: true
axaa using x: true
12bb using b: false
ca using c: true
Note that 12bb cannot be made into a palindrome using only one character change, so your test case appears to not match your specifications of replacing only one letter. Also my code will return true if given an empty string as input.