Longest palindrome within a word - java

I am trying to make a program to find the longest a palindrome within a string.
E.g., Banana -> anana
I have made a for loop to reverse the inputted string and I can make it check each time if it is a palindrome but I'm not sure it will work since the palindrome may not start at the first letter of the string.
Right now, my programs output is the following:
a
an
ana
anan
anana
ananab
In this case it would work but if the input was, say, abracadabra, the two palindromes within would be ace and ada but the program would not find it properly.
Here is my code:
public class Palindrome {
public static void main(String[] args) {
String string = "banana";
String reverse = "";
int length = string.length() - 1;
for (int i = length; i >= 0; i--) {
reverse = reverse + string.charAt(i);
System.out.println(reverse);
}
}
}

My method considers all possible substrings of the input string. For each substring it uses StringBuilder.reverse() to reverse the substring and then compare it to the original substring to determine if it was a palindrome.
private static Collection<String> longestPalindromesIn(String input) {
// longest palindromes found until now
Set<String> result = new HashSet<>();
// length of longest palindrome found until now (all strings in result have this length)
// initialize to a negative value to make sure that the first palindrome found will appear to be longer
int longest = -1;
// iterate over all possible substrings
for (int start = 0; start <= input.length(); start++) {
for (int end = start; end <= input.length(); end++) {
String currentSubstring = input.substring(start, end);
// only consider if at least as long as the longest palindrome already found
if (currentSubstring.length() >= longest) {
if (isPalindrome(currentSubstring)) {
if (currentSubstring.length() > longest) {
// discard palindromes shorter than the one we have just found
result.clear();
longest = currentSubstring.length();
}
result.add(currentSubstring);
}
}
}
}
return result;
}
private static boolean isPalindrome(String candidate) {
// the following is the easy way of reversing a string;
// you may use your own code instead if you prefer
StringBuilder reverse = new StringBuilder(candidate);
reverse.reverse();
return candidate.equals(reverse.toString());
}
For input banana the method returns a set of a single string, anana.
abracadabra gives two palindromes, aca and ada.
abca gives a, b and c. If there is no interesting palindrome (length 2 or more), the method just returns each letter. Once each, since the result is a Set and hence filters out duplicates.
If input is the empty string "", output is the empty string too. It is a palindrome after all.

Related

Obtain lexicographically smallest & largest substring. My algorithm failed most of the test cases but I can't understand why. Help me figure it out

I had to do a test today for an interview and the problem was obtaining the lexicographically smallest and largest substring (in other words, sort by name).
Link - Complete the function SmallestAndLargestSubstring, which takes a string S consisting of lowercase English letters (a-z) as its argument and returns lexicographically smallest and largest substrings which start with a vowel and end with a consonant.
My algorithm passed the basic test cases but failed most of the others. It's not the most efficient code, but it was the fastest to write.
static String[] SmallestAndLargestSubstring(String s) {
ArrayList<Character> vowelList = new ArrayList<Character>();
vowelList.add('a');
vowelList.add('e');
vowelList.add('i');
vowelList.add('o');
vowelList.add('u');
ArrayList<Character> consonantList = new ArrayList<Character>();
for (char c='a'; c<='z'; c++) {
if (!vowelList.contains(c))
consonantList.add(c);
}
ArrayList<String> substringList = new ArrayList<String>();
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (vowelList.contains(c)) {
String substring = "";
substring+=c;
for (int j=i+1; j<s.length(); j++) {
char c2 = s.charAt(j);
substring+=c2;
if (consonantList.contains(c2)) {
substringList.add(substring);
}
}
}
}
Collections.sort(substringList);
String[] outputAdapter = new String[2];
outputAdapter[0]=substringList.get(0);
outputAdapter[1]=substringList.get(substringList.size()-1);
return outputAdapter;
}
Anyway, I wanted to figure out where I went wrong, so I reversed engineered the test cases to figure out what was the input being passed in, and hopefully I would be able to figure out what was wrong with my algorithm.
Here's what I uncovered, and these are my answers (which are wrong according to the test cases).
Input
String s = "azizezozuzawwwwwwwwwuzzzzzzzzabbbbbbbaaaabbbboiz"
My answer
smallest = "aaaab";
largest = "uzzzzzzzzabbbbbbbaaaabbbboiz";
But for the life of me, I can't figure out where my mistake is. Here's my full list of substrings, sorted from the smallest to the largest. Link to sorted results
Been racking my brains for the last 3 hours. I'd be grateful if anyone can figure out where my mistake was.
Edit: Here are 3 more test cases. My answers match these test case answers.
string = "aba"; smallest = "ab"; largest = "ab";
string = "aab"; smallest = "aab"; largest = "ab";
string = "abababababbaaaaaaaaaaaaaaz"; smallest = "aaaaaaaaaaaaaaz"; largest = "az";
/*
It is the Basic code to Obtain Substring which start with Vowel and End up with Consonant. It is going to print on the Basis of Name Comparable, The first and the Last Substring in the List.Similarly we can achieve on the basis of length, the firt and last Substring using different comparator function.
*/
public class StringSubsequencesStartVowelEndConsonant {
static List<String> subsequence = new LinkedList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter the String:\n");
String string = in.next();
findSubstring(string);
}
private static void findSubstring(String string) {
for(int i=0;i<string.length();i++){
if(isVowel(string.charAt(i))){
for(int j=string.length()-1;j>=i;j--){
if(isConsonant(string.charAt(j))){
String subString = string.substring(i,j+1);
subsequence.add(subString);
}
}
}
}
Collections.sort(subsequence);
for(String str : subsequence){
System.out.print(str+" ");
}
System.out.println();
System.out.println(subsequence.get(0));
System.out.println(subsequence.get(subsequence.size()-1));
}
private static boolean isConsonant(char chars) {
return !(chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
private static boolean isVowel(char chars) {
return (chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
}

Java- Palindrome Program

I have been assigned to complete a palindrome program. However, I cannot use the charAt method.
Typically, I'd be able to solve this fairly quickly. However, since I cannot use charAt, I have no clue as to how I should go about doing this.
My idea is to take the length of the string, divide it by two (however this limits me to strings only with an even number of chars) then convert the substrings into int's and then finally compare the two int's.
This is my code thus far-
public static boolean isPal(String s)
{
int length = s.length();
int math = length / 2;
String side1 = s.substring(1,math);
String side2 = s.substring(math, length);
int s1 = Integer.parseInt(side1);
int s2 = Integer.parseInt(side2);
if(s1 == s2){
return true;
} else {
return false;
}
}
However, I have realized that this might not, and probably is not, the best way to handle the situation. I am currently running into this error-
Exception in thread "main" java.lang.NumberFormatException: For input string: "i"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Palindrome.isPal(Lab08st.java:47)
at Lab08st.main(Lab08st.java:20)
I believe it is because I need a for loop of sorts.
However, having inadequate Java experience, I am unsure.
I am open to any and all suggestions. (So long as they do not require charAt)
Use this:
public static boolean isPal(String s) {
char[] chars = s.toCharArray();
int len = chars.length;
for (int i = 0; i < len ; i++) {
if(chars[i] != chars[len-i-1] ){
return false;
}
}
return true;
}
Your approach is flawed in several ways:
Integer.parseInt(String) only works on optionally-signed digit strings that represent base-10 numbers representable as type int. Your function will utterly fail on non-numeric inputs, and on inputs that are too large for the halves to be represented as ints (some 19-20-character inputs; all longer inputs).
Your function will fail on any input having an odd number of characters, because you cannot split such inputs evenly into halves.
Your logic is flawed anyway. It would judge "1010" a palindrome (which it isn't), and it would judge "1001" not a palindrome (though it is one).
You can pick out the input String's characters one-by-one via a variety of techniques, among them:
You can get the characters in a char[] via String.toCharArray(), as has elsewhere been suggested.
You can consume the input via a series of substring() invocations.
You can use a StringCharacterIterator to iterate over the characters
Since it's not clear why you are not permitted to use charAt(), here's an approach that altogether avoids relying on indexing:
import java.text.StringCharacterIterator;
// ...
public static boolean isPal(String s)
{
StringCharacterIterator it = new StringCharacterIterator(s);
String reversed = ""
for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
reversed = c + reversed;
}
return reversed.equals(s);
}
There are more efficient approaches, but that one is clear and simple.
Or here's one that doesn't rely (explicitly) on any classes other then String, but does use the indexes 0 and 1:
public static boolean isPal(String s)
{
String tail = s;
String reversed = ""
while (tail.length() > 0) {
reversed = tail.substring(0, 1) + reversed;
tail = tail.substring(1);
}
return reversed.equals(s);
}
Or since you had the idea of splitting the String into two, perhaps that was directed by your instructor? Are you perhaps studying recursion? Because you can also reverse the input string via a recursive algorithm: (1) split the string in two (as evenly as possible works best); (2) recursively reverse each half; (3) put the reversed halves back together in the opposite order. (Implementation left as an exercise.)
With all that said, do note that Reticality's one-liner using StringBuilder.reverse() is better on all counts if it satisfies the requirements.
My Solution-
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String str = "pappap";
String sp = str.toLowerCase();
char[] ch = sp.toCharArray();
int len = ch.length;
int lastIndex = ch.length-1;
int count = 1;
int first = 0;
int last = sp.length()-1;
for(; first < last ;){
if(ch[first] == ch[last] ){
first= first+1;
last= last-1;
}
else{
count = 0;
break;
}
}
String result = (count == 1) ? "Palindrome" : "Not a palindrome " ;
System.out.println(result);
}
}
If you are checking to see if a number, given to you as a string, is a palindrome, then you might use math to do it. Use an algorithm that compares the least significant with the most significant digit, then remove those to digits and continue. If there are an odd number of digits then you don't need to compare that middle digit with anything -- you just need the number of digits / 2 steps.
This code left as an exercise because it is homework.

How do I find the letters of a certain word within a Character array in Java?

I need to compare the characters from two different Character Arrays to find the Hidden word inputted by the user.
The goal is to input 2 Strings and to find a word scrambled within the other.
Ex. The word "tot" is scrambled in the word "tomato"
With the help of some people of the forums, I have implemented character arrays to store the user Strings, but I do not know a way to check each array for the characters needed. I have tried the code below but it always results in the program not being able to find the word. If anyone could provide a better method or solution I'd highly appreciate it.
public static void main(String[] args) {
input = new Scanner(System.in);
System.out.println("Please enter a word");
String word = input.next();
char[] charOfWrds = word.toCharArray();
System.out.println("Please enter a hidden word you would like to search for");
String search = input.next();
char[] charOfSrch = search.toCharArray();
if (isContains(charOfWrds, charOfSrch))
{
System.out.print("The word " + search + " is found in the word " + word);
}
else
{
System.out.print("The word was not found in " + word);
}
}
public static Boolean isContains(char[] charOfWrds, char[] charOfSrch) {
int count = 0;
for (char cha : charOfWrds)
{
for (char chaaa : charOfSrch)
{
if (cha == chaaa)
count++;
}
}
if (count == charOfSrch.length)
{
return true;
}
return false;
}
public static Boolean isContains(char[] charOfWords, char[] charOfSrch) {
List<Character> searchFor = new ArrayList<>();
List<Character> searchMe=new ArrayList<>();
for(char c:charOfWords)
searchFor.add(c);
for(char c:charOfSrch)
searchMe.add(c);
for(int x=searchFor.size()-1;x>=0;x--){
if(searchMe.contains(searchFor.get(x)){
searchMe.remove(searchFor.get(x));
searchFor.remove(x);//line A
}
}
return searchFor.size()==0;
}
Quick overview of what this does. I converted both of the character arrays into Lists, so that I could use the List methods. Then, I iterated through every character in the word that you need to find, and if I could find it in the other word, I removed it from both of them, meaning that if all the words were removed from the word needed to be find, the word was found in the other word;otherwise it was not.
I assumed that you could not reuse letters in the second word, but if you can, then just remove line A.
You should try regular expression rather than trying to write an algo.
Build the expression using user input and then match with the desired word.
take
tomato as charOfWrds
tot as charOfSrch
isContains will count 6 because you don't quit when you find a letter of the first word in the second.
t : two times
o : two times
t : two times
try this :
if (cha == chaaa){
count++;
break;
}
but to make this work you need to remove the letter once found from the second string, because if the word you're looking for is "tttt", then this code will give you true even if it's not, but if you remove t when you found it then it should do the trick.
I don't know if that's clear enough for you.
here is the code :
public static Boolean isContains(char[] charOfWrds, char[] charOfSrch) {
int count = 0;
for (int i=0; i<charOfWrds.length;i++){
for (int j=0;j<charOfSrch.length;j++){
if (charOfWrds[i] == charOfSrch[j]){
count++;
charOfSrch[j]=' ';
break;
}
}
}
if (count == charOfSrch.length)
{
return true;
}
return false;
}
It's working, i tried it with this :
String word = "tomato";
char[] charOfWrds = word.toCharArray();
String search = "tot";
char[] charOfSrch = search.toCharArray();
But this is ugly, you should try to use the java Api, unless you really have to do it with arrays.
My idea was similar to what #kirbyquerby provided except that it has a few optimizations.
Instead of using a linear search, after converting each word (the needle and the haystack) to a list, we sort those lists. This allows us to use binary search which changes the search complexity from O(n^2) to O(n log n).
Additionally, there is no need to remove characters from the needle list as we can just keep track of how many needle characters have been found. Once we are done searching, we simply compare the number of found needle characters to the total number of needle characters. If they are equal, we have found our needle. Lastly, if a needle character is not found, we can stop searching immediately as we know that the entire needle does not exist within the haystack.
package hiddenword;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HiddenWord {
public static void main(final String args[]) {
final String haystack = "Tomato";
final String needle = "tot";
if (contains(haystack, needle)) {
System.out.println(haystack + " contains " + needle);
} else {
System.out.println(haystack + " does not contain " + needle);
}
}
private static boolean contains(final String haystack, final String needle) {
// Convert each word to lowercase and into a List.
final List<Character> haystackChars = toSortedCharacterList(haystack.toLowerCase());
final List<Character> needleChars = toSortedCharacterList(needle.toLowerCase());
int foundNeedleChars = 0;
for (final Character c : needleChars) {
// Using sorted lists, our search time is be O(n log n) by using
// binary search instead of O(n^2) using linear search.
int index = Collections.binarySearch(haystackChars, c);
// A needle character has been found, remove it from the haystack
// and increment the count
if (index >= 0) {
haystackChars.remove(index);
++foundNeedleChars;
}
// A needle character was not found. This means that the haystack
// doesn't contain every character of the needle and we
// can quit early
else {
return false;
}
}
// If we've found all the needle characters, the needle word exists in
// the haystack word.
return foundNeedleChars == needleChars.size();
}
private static List<Character> toSortedCharacterList(final String input) {
final List<Character> list = new ArrayList<Character>();
// Convert primitive array to List
for (final char c : input.toCharArray()) {
list.add(c);
}
// Sort that thang
Collections.sort(list);
return list;
}
}
You can do this without having to convert the strings to an array with something like:
static boolean containsScrambled(String word, String search){
//loop through each character of the word whose characters we are searching for
for(int x = 0; x<search.length(); x++){
//find the current character to check
String c = search.substring(x, x+1);
if(word.indexOf(c) >= 0){
//if the character is in the word, remove the first instance of it
//as we cannot use that character again
word.replaceFirst(c, "");
}else{
//if the character is not in the word, fail and return false
return false;
}
}
//if we made it here, all of the characters existed, return true
return true;
}

Find longest word in a sentence recursively

So I need to find the longest word recursively, I've written the code, but it's not working, and I have no idea what to fix.
public static String longestWord(String sentence)
{
int i = sentence.indexOf(" ");
if (i==-1){
return sentence;
}
else{
String first = sentence.substring(0,i);
String rest = sentence.substring(i+1);
if(first.length()>=rest.length()){
return longestWord(first);
}
else{
return longestWord(rest);
}
}
}
The line:
if(first.length() >= rest.length())
should read like:
String res = longestWord(rest);
if(first.length() >= res.length())
The reason it does not work is that you are ignoring the length of the longestWord(rest): instead of comparing the length of the initial word and the rest of the sentence, you should compare the length of the initial word to the length of the longest word found in the rest of the sentence.
String first = sentence.substring(0,i);
String rest = longestWord(sentence.substring(i+1));
return first.length()>=rest.length() ? first : rest;
Your basic approach is sane: you're breaking the input into two: the first word, and the rest of the string. But then the logic is bungled a little bit.
If the first word is longer than the entire rest of the string, you should just return first, not longestWord(first) (although, you do handle that case: longestWord will notice that the word cannot be split and just return it. It's pointless though).
Secondly, if that is not the case, you cannot assume that the first word is not the longest word. You must capture the return value of longestWord(rest), and then compare that word's length to the length of first. If that word is longer, then return it. Otherwise return first.
The essence of "divide and conquer" by recursion is that you solve some smaller versions of the problem, and then integrate those results. Don't forget this second part. This is not a binary search tree search where the data is organized such that you can just recurse to one half of the space or the other to find the answer. You don't know where the longest word might be.
This is another approach to solve the question:
public static String longestWord(String sentence) {
return longest(sentence.split("\\s+"), 0, 0);
}
private static String longest(String[] words, int idx, int longest) {
if (idx == words.length)
return words[longest];
return longest(words, idx+1,
words[idx].length() > words[longest].length() ? idx : longest);
}
First, in longestWord() the sentence gets split by its spaces, producing an array of words. From that point on, the method longest() recursively iterates over all the words passing the index of the longest one found so far in the longest parameter, until there are no more words. This is an efficient answer, as it doesn't create substrings at each step.
package com.kota.java;
import java.util.*;
class LongestWord{
String str = "Ram is intelligent boy";
String stringArray[] = str.split("\\s");
public String compare(String st1, String st2) {
if (st1.length() > st2.length()) {
return st1;
} else {
return st2;
}
}
LongestWord() {
String word = "";
for (int i = 0; i < stringArray.length; i++) {
if (i == 0) {
word = stringArray[0];
}
word = compare(word, stringArray[i]);
}
System.out.println("Longest word = " + word);
}
public static void main(String[] args) {
new LongestWord();
}
}
/**
* Out put : Longest word = intelligent
*
* */

Every combination of character array

Having problems trying to show every combination of a character of array without repeating letters.
public static String[] getAllLists(String[] elements, int lengthOfList)
{
//initialize our returned list with the number of elements calculated above
String[] allLists = new String[(int)Math.pow(elements.length, lengthOfList)];
//lists of length 1 are just the original elements
if(lengthOfList == 1) return elements;
else
{
//the recursion--get all lists of length 3, length 2, all the way up to 1
String[] allSublists = getAllLists(elements, lengthOfList - 1);
//append the sublists to each element
int arrayIndex = 0;
for(int i = 0; i < elements.length; i++)
{
for(int j = 0; j < allSublists.length; j++)
{
//add the newly appended combination to the list
allLists[arrayIndex] = elements[i] + allSublists[j];
arrayIndex++;
}
}
return allLists;
}
}
The above code works perfect but use's each letter more than once which cant be done in this case.
And i am stuck how to do this now.
Here's an example implementation. Essentially it takes a String and iterates over every character, putting that character at the front. It then recurses on the remaining characters. That structure removes your issue of repeated letters, because the input to the recursion has removed the character you've already used.
I also stored results in a set to remove semantic equivalences. The input 'aab' can switch char 0 and char 1 but still be 'aab.' I used a TreeSet to preserve ordering for easier verification of the output, but HashSet would be faster.
public static Set<String> permute(String chars)
{
// Use sets to eliminate semantic duplicates (aab is still aab even if you switch the two 'a's)
// Switch to HashSet for better performance
Set<String> set = new TreeSet<String>();
// Termination condition: only 1 permutation for a string of length 1
if (chars.length() == 1)
{
set.add(chars);
}
else
{
// Give each character a chance to be the first in the permuted string
for (int i=0; i<chars.length(); i++)
{
// Remove the character at index i from the string
String pre = chars.substring(0, i);
String post = chars.substring(i+1);
String remaining = pre+post;
// Recurse to find all the permutations of the remaining chars
for (String permutation : permute(remaining))
{
// Concatenate the first character with the permutations of the remaining chars
set.add(chars.charAt(i) + permutation);
}
}
}
return set;
}
Example run:
public static void main(String[] args)
{
for (String s : CharPermuter.permute("abca"))
{
System.out.println(s);
}
}
Generates:
aabc
aacb
abac
abca
acab
acba
baac
baca
bcaa
caab
caba
cbaa

Categories