I need to write function that gets 3 params(int num, int k, int nDigit).
The function get number and replace the digit inside the number in k index by nDigit.
for example:
int num = 5498
int k = 2
int nDigit= 3
the result is num = 5398
My question is how can I implement it?I undastand that the best way to convert the num to string and then just replace char on specific index by nDigit char.
But is there any way to implement it?Without
public int changeDigit(int num, int k, int nDigit){
k = pow(10,k);
double saved = num%k; // Save digits after
num = num - (num%(k*10)); //Get what's before k
return ((int) (num + (nDigit*k) + saved));
}
I won't do your homework for you, but here's some hints:
Convert integer to string:
String s = Integer.toString(1234);
Enumerating a string:
for (i = 0; i < s.length; i++)
{
char c = s.charAt(i);
}
String building (a little less efficient without the StringBuilder class)
char c = '1';
String s = "3";
String j = "";
j = j + c;
j = j + s; // j is now equal to "13"
String back to integer:
int val = Integer.parseInt("42");
You can use a StringBuilder. It's easier to see what you're doing and you don't need to perform mathematics, only adjust the characters in their positions. Then convert it back to int.
public class Main {
static int swapParams(int num, int k, int nDigit) {
StringBuilder myName = new StringBuilder(Integer.toString(num));
myName.setCharAt(k-1, Integer.toString(nDigit).charAt(0));
return Integer.parseInt(myName.toString());
}
public static void main(String[] args) {
System.out.println(swapParams(5498, 2, 3));
}
}
http://ideone.com/e4MF6m
You can do it like this:
public int func(int num, int k, int nDigit) {
String number = String.valueOf(num);
return Integer.parseInt(number.substring(0, k - 1) + nDigit + number.substring(k, number.length()));
}
This function takes the first characters of the number without the k'th number and adds the nDigit to it. Then it adds the last part of the number and returns it as an integer number.
This is my javascript solution.
const solution = numbers => { //declare a variable that will hold
the array el that is not strictly ascending let flawedIndex;
//declare a boolean variable to actually check if there is a flawed array el in the given array let flawed = false;
//iterate through the given array for(let i=0; i<numbers.length; i++) {
//check if current array el is greater than the next
if(numbers[i] > numbers[i+1])
{
//check if we already set flawed to true once.
//if flawed==true, then return that this array cannot be sorted
//strictly ascending even if we swap one elements digits
if(flawed) {
return false;
}
//if flawed is false, then set it to true and store the index of the flawed array el
else {
flawed = true;
flawedIndex = i;
}
}
}
//if flawed is still false after the end of the for loop, return true //where true = the array is sctrictly ascending if(flawed ==
false) return true;
//if flawed==true, that is there is an array el that is flawed if(flawed){
//store the result of calling the swap function on the digits of the flawed array el
let swapResult = swap(flawedIndex,numbers);
//if the swapresult is true, then return that it is ascending
if (swapResult == true) return true; }
//else return that its false return false; }
const swap = (flawIndex, numbers) => {
let num = numbers[flawIndex];
//convert the given array el to a string, and split the string based on '' let numToString = num.toString().split('');
//iterate through every digit from index 0 for(let i=0;
i<numToString.length; i++) {
//iterate from every digit from index 1
for(let j=i+1; j<numToString.length; j++) {
//swap the first index digit with every other index digit
let temp = numToString[i];
numToString[i] = numToString[j]
numToString[j] = temp;
console.log(numToString)
//check if the swapped number is lesser than the next number in the main array
//AND if it is greater than the previous el in the array. if yes, return true
let swappedNum = Number(numToString.join(''));
if(swappedNum < numbers[flawIndex + 1] && swappedNum > numbers[flawIndex-])
{
return true;
}
} } //else return false return false; }
console.log("the solution is ",solution([1, 3, 900, 10]))
Related
I am still new to Java, and I am currently working on a program that will take two strings as arguments and return the number of mismatched pairs. For my program I am working with ATGC because in science, A's always match up with T's and G's always match up with C's. I cant quite figure out how to iterate over the strings and see that the first character in string one (T for example) matches up with its intended pair (A), and if it doesn't it is a mismatched pair and it should be added to a counter to be totaled at the end. I believe I can use something called charAt(), but I am unsure of how that works.
I also need to figure out how to be able to take the absolute value of counter before it is added to the finalCounter. The main reason for this is because I just want to worry about getting the length difference between the two rather than making sure that the longer string is subracted from the smaller string.
Any help would be greatly appreciated!
''''
public class CountMismatches {
public static void main(String[] args) {
{
String seq1 = "TTCGATGGAGCTGTA";
String seq2 = "TAGCTAGCTCGGCATGA";
System.out.println(count_mismatches(seq1, seq2))
//*expected to print out 5 because there are 3 mismatched pairs and 2 that do not have a pair*
}
}
public static int count_mismatches(String seq1, String seq2) {
int mismatchCount = 0;
int counter = seq1.length() - seq2.length();
int finalCounter = mismatchCount + counter;
for(int i = 0; i < seq1.length(); i++) if (seq1.charAt(i) == seq2.charAt(i)) {
break; //checks to see if the length of seq1 and seq2 are the same
}
for(int i = 0; i < seq1.length(); i++) if (seq1.charAt(i) != seq2.charAt(i)) {
return counter; //figure out how to do absolute value for negative numbers
}
return finalCounter;
}
}
'''
Since you want to count only the places where there are differences, you can iterate through the minimum length present in both the strings and find out the places where they are different.
In the end, you can add absolute difference of length between seq1 and seq2 and return that value to the main function.
For the logic, all you have to do is apply 4 if conditions to check if character is A,G,C,T and if suitable pair is present in the other string.
public class CountMismatches {
public static void main(String[] args) {
{
String seq1 = "TTCGATGGAGCTGTA";
String seq2 = "TAGCTAGCTCGGCATGA";
System.out.println(count_mismatches(seq1, seq2));
}
}
public static int count_mismatches(String seq1, String seq2) {
int finalCounter = 0;
for (int i = 0; i < Math.min(seq1.length(), seq2.length()); i++) {
char c1 = seq1.charAt(i);
char c2 = seq2.charAt(i);
if (c1 == 'A') {
if (c2 == 'T')
continue;
else
finalCounter++;
} else if (c1 == 'T') {
if (c2 == 'A')
continue;
else
finalCounter++;
} else if (c1 == 'G') {
if (c2 == 'C')
continue;
else
finalCounter++;
} else if (c1 == 'C') {
if (c2 == 'G')
continue;
else
finalCounter++;
}
}
return finalCounter + (Math.abs(seq1.length() - seq2.length()));
}
}
and the output is as follows :
5
Make these refactorings:
To make the comparisons easy to code and understand, create a Map whose entires are each pair (both directions)
Iterate over the Strings up to the length of the shortest one, adding up the number of matching pairs as you go
The result is the length of the longest String minus the number of pairs
Like this:
public static int count_mismatches(String seq1, String seq2) {
Map<Character, Character> pairs = Map.of('A', 'T', 'T', 'A', 'G', 'C', 'C', 'G');
int count = 0;
for (int i = 0; i < Math.min(seq1.length(), seq2.length()); i++) {
if (pairs.get(seq1.charAt(i)) == seq2.charAt(i)) {
count++;
}
}
return Math.max(seq1.length(), seq2.length()) - count;
}
See live demo, which returns 5 for your sample input.
Good Evening,
Something seems off here, this snippet of code:
for(int i = 0; i < seq1.length(); i++)
if (seq1.charAt(i) == seq2.charAt(i)) {
break; //checks to see if the length of seq1 and seq2 are the same
}
Does not do what you think it does. This cycle will loop through all characters in sequence1 using i < seq1.length() and for each character that exists in seq1, it will check if said character is equal to the character with the same index in seq2.
This means that a correction is in order:
int countMismatches = 0;
for(int i = 0; i < seq1.length();i++){
switch(seq1.charAt(i)){
case 'A':
if(seq2.charAt(i) != 'T') countMismatches++;
break;
}
}
Repeat this process for the other letters, and voilá, you should be able to count your mismatches this way.
Do be careful with sequences having different lengths, as if that happens, as soon as you step out of a bound, you will receive an IndexOutOfBoundsException, indicating you've tried to check a character that does not exist.
First you must find out which string is the shortest in length. Also you need to get the length difference when calculating the shortest string. After that, use that length as a terminating condition in your for loop. You can use booleans to check whether the values are present before incrementing the counter with an if statement.
The absolute value of any number can be obtained by calling the static method abs() from the Math class. Last, just add the mismatchCounts to the absolute value of the length difference in order to obtain the result.
Here is my solution.
public class App {
public static void main(String[] args) throws Exception {
String seq1 = "TTCGATGGAGCTGTA";
String seq2 = "TAGCTAGCTCGGCATGA";
System.out.println(compareStrings(seq1, seq2));
}
public static int compareStrings(String stringOne, String stringTwo) {
Character A = 'A', T = 'T', G = 'G', C = 'C';
int mismatchCount = 0;
int lowestStringLenght = 0;
int length_one = stringOne.length();
int length_two = stringTwo.length();
int lenght_difference = 0;
if (length_one < length_two) {// string one lenght is greater
lowestStringLenght = length_one;
lenght_difference = length_one - length_two;
} else if (length_one > length_two) {// string two lenght is greater
lowestStringLenght = length_two;
lenght_difference = length_two - length_one;
} else { // lenghts must be equal, use either
lowestStringLenght = length_one;
lenght_difference = 0; // there is no difference because they are equal
}
for (int i = 0; i < lowestStringLenght; i++) {
// A matches with T
// G matches with C
// evaluate if the values A, T, G, C are present
boolean A_T_PRESENT = stringOne.charAt(i) == A && stringTwo.charAt(i) == T;
boolean G_C_PRESENT = stringOne.charAt(i) == G && stringTwo.charAt(i) == C;
boolean T_A_PRESENT = stringOne.charAt(i) == T && stringTwo.charAt(i) == A;
boolean C_G_PRESENT = stringOne.charAt(i) == C && stringTwo.charAt(i) == G;
boolean TWO_EQUAL = stringOne.charAt(i) == stringTwo.charAt(i);
// characters are equal, increase mismatch counter
if (TWO_EQUAL) {
mismatchCount++;
continue;
}
// all booleans evaluated to false, it means that the characters are not proper
// matches. Increment mismatchCount
else if (!A_T_PRESENT && !G_C_PRESENT && !T_A_PRESENT && !C_G_PRESENT) {
mismatchCount++;
continue;
} else {
continue;
}
}
// calculate the sum of the mismatches plus the abs of the lenght difference
lenght_difference = Math.abs(lenght_difference);
return mismatchCount + lenght_difference;
}
}
Avoid char
The char type is legacy, essentially broken. As a 16-bit value, char is physically incapable of representing most characters. The char type in your particular case would work. But using char is a bad habit generally, as such code may break when encountering any of about 75,000 characters defined in Unicode.
Code point
Use code point integer numbers instead. A code point is the number assigned to each of the over 140,000 characters defined by the Unicode Consortium.
Here we get an IntStream, a series of int values, one for each character in the input string. Then we collect these integer numbers into an array of int values.
int[] codePoints1 = seq1.codePoints().toArray() ;
int[] codePoints2 = seq2.codePoints().toArray() ;
You said the input strings may be of unequal length. So our two arrays may be jagged, of different lengths. Figure out the size of the shorter array.
int smallerSize = Math.min( codePoints1.length , codePoints2.length ) ;
Keep track of the index number of mismatched rows.
List<Integer> mismatchIndices = new ArrayList <>();
Loop the arrays based on that smaller size.
for( int i = 0 ; i < smallerSize ; i ++ )
{
if ( isBasePairValid( codePoint first , codePoint second ) )
{
…
} else
{
mismatchIndices.add( i ) ;
}
}
Write an isBasePairValid method
Write the isBasePairValid method, taking two arguments, the code points of the two nucleobase letters.
static int A = "A".codePointAt( 0 ) ; // Annoying zero-based index counting. So first character is number zero.
static int C = "C".codePointAt( 0 ) ;
static int G = "G".codePointAt( 0 ) ;
static int T = "T".codePointAt( 0 ) ;
if( first == A ) return ( second == T )
else if( first == T ) return ( second == A )
else if( first == C ) return ( second == G )
else if( first == G ) return ( second == C )
else { throw new IllegalStateException( … ) ; }
Count the mismatches.
int countMismatches = mismatchIndices.size() ;
The numerical sum of chars T & A and G & C is fixed and unique for legal nucleobase pairs. So you just need to ensure that the corresponding bases have one of those sums.
String seq1 = "TTCGATGGAGCTGTA";
String seq2 = "TAGCTAGCTCGGCATGA";
System.out.println(count_mismatches(seq1, seq2));
prints
5
find max length to iterate
establish fixed sums for comparison
iterate and compare to expected pairing and update count appropriately
public static int count_mismatches(String seq1, String seq2) {
int len1 = seq1.length();
int len2 = seq2.length();
int len = len1;
if (len1 > len2) {
len = len2;
}
int sumTA = 'T'+'A';
int sumGC = 'G'+'C';
int misMatchCount = Math.abs(len1-len2);
for (int i = 0; i < len; i++) {
int pair = seq1.charAt(i) + seq2.charAt(i);
if (pair != sumTA && pair != sumGC) {
misMatchCount++;
}
}
return misMatchCount;
}
A previous method called letterCounts required "counts the number of times that each letter occurs in the specified string and returns the result as an int array, where the number of ‘A’s is stored at position [0], the number of ‘B’s is stored at position [1], and so on:".
Now I have tried to create the method wordInLetters but I am stuck as to how to proceed to create a method that does what the title of this post says.
static boolean wordInLetters(final String word, final int[] letterCounts) {
boolean hasEnough = true;
for (int i = 0; i <word.length(); i ++){
if (word.charAt(i) < letterCounts[i]){
hasEnough = false;
}
else {return true;}
}
return hasEnough;
}
}
Call the previously made function, passing the word as parameter. Then compare the values returned by it with the values in letterCount array. If they are all <= return true.
Note: this assumes both arrays have the same length (i.e. 26 for ASCII alphabet).
static boolean wordInLetters(final String word, final int[] availableLetters)
{
// Get the count of letters in the word
int [] lettersInWord = letterCounts(word);
// Compare the counts
for (int i = 0; i < lettersInWord.length; i++) {
// If not enough letters, fail
if (availableLetters[i] < lettersInWord[i]) {
return false;
}
}
// If we made it to here, all is good.
return true;
}
There is no need to make a call to the other method. You can simply do this:
static boolean wordInLetters(final String word, final int[] letterCounts) {
int start = 'a';
for (int i = 0; i < word.length(); i ++){
final int x = i;
Long count = Arrays.asList(word.split("")).stream()
.filter(w -> w.equals(word.substring(x, x + 1)))
.count();
if (letterCounts[word.charAt(i) - start] < count) {
return false;
}
}
return true;
}
I'm relatively new to java and am trying to break my code down as much as possible. This question is really on how to organize methods to work together
My credit card validator works if checkSum() code is written in the validateCreditCard() method. I think it's weird 'cause it works when called by the checkDigitControl() method
I used these sources for the program's logic:
To Check ~ https://www.creditcardvalidator.org/articles/luhn-algorithm
To Generate ~ https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm
Here's my code(I apologize in advance if it's rather clumsy)
public class CreditCards {
public static void main(String[] args) {
long num;
num = genCreditCard();
boolean bool = validateCreditCard(num);
}
// Validity Check
public static boolean validateCreditCard(long card) {
String number = card+"";
String string=null;
int i;
for(i=0; i<number.length()-1; i++) {//Populate new string, leaving out last digit.
string += number.charAt(i)+"";
}
String checkDigit = number.charAt(i)+"";// Stores check digit.
long sum = checkSum(string);// Program works if this line is swapped for the code below(from checkSum)
//**********************************************************************
// int[] digits = new int[number.length()];
// int lastIndex = digits.length-1;
// int position=2; int mod=10;
// int sum=0;
//
// for(int j=lastIndex; j>=0; j--) {// Populate array in REVERSE
// digits[j] = Integer.parseInt(number.charAt(j)+"");
// digits[j] *= ( (position%2 == 0) ? 2: 1 );// x2 every other digit FROM BEHIND
// position++;
//
// digits[j] = ( (digits[j] > 9) ? (digits[j] / mod)+(digits[j] % mod) : digits[j] );//Sums integers of double-digits
// sum += digits[j];
// }
//**********************************************************************
sum *= 9;
string = sum+"";
string = string.charAt(string.length()-1)+"";// Last digit of result.
return (string.equals(checkDigit));
}
public static long genCreditCard() {
String number = "34";// American Express(15 digits) starts with 34 or 37
for(int i=0; i<12; i++)
number += (int)(Math.random() * 10) + "";// Add 12 random digits 4 base.
number += checkDigitControl(number);// Concat the check digit.
System.out.println(number);
return Long.parseLong(number);
}
// Algorithm to calculate the last/checkSum digit.
public static int checkDigitControl(String number) {
int i;
for(i=0; i<5; i++)
++i;
int sum = checkSum(number);
return 10 - sum%10;// Returns number that makes checkSum a multiple of 10.
}
public static int checkSum(String number) {
int[] digits = new int[number.length()];
int lastIndex = digits.length-1;
int position=2; int mod=10;
int sum=0;
for(int j=lastIndex; j>=0; j--) {// Populate array in REVERSE
digits[j] = Integer.parseInt(number.charAt(j)+"");
digits[j] *= ( (position%2 == 0) ? 2: 1 );// x2 every other digit FROM BEHIND
position++;
digits[j] = ( (digits[j] > 9) ? (digits[j] / mod)+(digits[j] % mod) : digits[j] );//Sums integers of double-digits
sum += digits[j];
}
return sum;
}
}
Thx in advance, sorry if this isn't the right format; it's also my 1st Stackoverflow post ¯\_(ツ)_/¯
You are initializing the variable string with null value:
String string=null;
And in the following for you are adding every char of the card number to this string.
for(i=0; i<number.length()-1; i++) {
string += number.charAt(i)+"";
}
But this will result in the variable string to be null + cardnumbers, because you didn't initialize the String string, and the value null is converted to the string "null" (Concatenating null strings in Java)
This will fix you code:
String string = new String();
Note, this code:
for(i=0; i<number.length()-1; i++) {
string += number.charAt(i)+"";
}
can be easily replace by this line that does the same thing:
number = number.substring(0, number.length() -1);
If you switch to this code just pass number to checkSum method
Trying to use Arrays.binarySearch() to search for a string in an array and return the index. However each time I call Arrays.binarySearch() I get the following exception -
Exception in thread "main" java.lang.NullPointerException
at java.util.Arrays.binarySearch0(Unknown Source)
at java.util.Arrays.binarySearch(Unknown Source)
at project.ArrayDirectory.lookupNumber(ArrayDirectory.java:97)
at project.test.main(test.java:12)
Here is my ArrayDirectory class -
public class ArrayDirectory implements Directory {
static Entry[] directory = new Entry[50];
#Override
public void addEntry(String surname, String initials, int extension) {
int n = 0;
for (int i = 0; i < directory.length; i++) { // counting number of
// entries in array
if (directory[i] != null) {
n++;
}
}
if (n == directory.length) {
Entry[] temp = new Entry[directory.length * 2]; // if array is full
// double the
// length.
for (int i = 0; i < directory.length; i++)
temp[i] = directory[i];
directory = temp;
}
int position = -1;
for (int i = 0; i < directory.length; i++) {
position = i;
if (directory[i] != null) { // sorting the array into alphabetical
// order by surname.
int y = directory[i].getSurname().compareTo(surname);
if (y > 0) {
break;
}
}
else if (directory[i] == null) {
break;
}
}
System.arraycopy(directory, position, directory, position + 1,
directory.length - position - 1);
directory[position] = new Entry(initials, surname, extension); // placing
// new
// entry
// in
// correct
// position.
}
#Override
public int lookupNumber(String surname, String initials) {
// TODO Auto-generated method stub
Entry lookup = new Entry(surname, initials);
int index = Arrays.binarySearch(directory, lookup);
return index;
}
}
Any ideas how I use binary search to find the correct index?
Thank you for you help.
edit -
I have also overridden comapreToin my Entry class -
public int compareTo(Entry other) {
return this.surname.compareTo(other.getSurname());
}
In your invocation of
int index = Arrays.binarySearch(directory,lookup);
directory seems to contain only null elements. Check that you are initializing elements correctly.
I note two things:
static Entry [] directory = new Entry [1];
First, that code allocates space for one Entry in the array. It doesn't actually instantiate an Entry. That is, directory[0] is null. Secondly, a binary-search on an array with one entry is crazy. There is only one element. It must be directory[0]. Finally, you should sort your array to do a binary search on it.
The basic concept behind a binary search is the recursion of the following steps(Note the search assumes the list or array of elements is sorted in some form and the element exists there.):
Go to the middle element of the array.
check if the searched element is equal to the element at the middle. If it is then return its index.
if not then check if the searched element is 'smaller' or 'larger' than the element in the middle.
if it is smaller then go to step 1 using only the lower/first half of the array instead of the whole.
else go to step 1 using only the upper/last half of the array instead of the whole.
As the array is continuously divided in 2 it will eventually reach the size of 1 giving the result.
Now, suppose you are looking for an integer in an int array. Here is what the code would be like:
public static int binarySearch(int number, int[] array)
{
boolean isHere = false;
Integer index =0;
for(int i=0;i<array.length;i++)
{
if(array[i] == number)
{
isHere = true;
i = array.length;
}
}
if(!isHere)
{
index = -1;
}
else
{
int arrayStart = 0;
int arrayEnd = array.length;
index = binarySearch(number, arrayStart, arrayEnd, array);
}
return index;
}
private static int binarySearch(int number, int start, int end, int[] array)
{
// this formula ensures the index number will be preserved even if
// the array is divided later.
int middle = (start+ end)/ 2;
if(array[middle] == number)
{
return middle;
}
else
{
if(number < array[middle])
{
//searches the first half of the array
return binarySearch(number, start, middle, array);
}
else
{
// searches the last half of the array
return binarySearch(number, middle, end, array);
}
}
}
You can use the compareTo() method instead of <,>, & == operators in your example. The logic should still be the same.
If the input is 'abba' then the possible palindromes are a, b, b, a, bb, abba.
I understand that determining if string is palindrome is easy. It would be like:
public static boolean isPalindrome(String str) {
int len = str.length();
for(int i=0; i<len/2; i++) {
if(str.charAt(i)!=str.charAt(len-i-1) {
return false;
}
return true;
}
But what is the efficient way of finding palindrome substrings?
This can be done in O(n), using Manacher's algorithm.
The main idea is a combination of dynamic programming and (as others have said already) computing maximum length of palindrome with center in a given letter.
What we really want to calculate is radius of the longest palindrome, not the length.
The radius is simply length/2 or (length - 1)/2 (for odd-length palindromes).
After computing palindrome radius pr at given position i we use already computed radiuses to find palindromes in range [i - pr ; i]. This lets us (because palindromes are, well, palindromes) skip further computation of radiuses for range [i ; i + pr].
While we search in range [i - pr ; i], there are four basic cases for each position i - k (where k is in 1,2,... pr):
no palindrome (radius = 0) at i - k
(this means radius = 0 at i + k, too)
inner palindrome, which means it fits in range
(this means radius at i + k is the same as at i - k)
outer palindrome, which means it doesn't fit in range
(this means radius at i + k is cut down to fit in range, i.e because i + k + radius > i + pr we reduce radius to pr - k)
sticky palindrome, which means i + k + radius = i + pr
(in that case we need to search for potentially bigger radius at i + k)
Full, detailed explanation would be rather long. What about some code samples? :)
I've found C++ implementation of this algorithm by Polish teacher, mgr Jerzy Wałaszek.
I've translated comments to english, added some other comments and simplified it a bit to be easier to catch the main part.
Take a look here.
Note: in case of problems understanding why this is O(n), try to look this way:
after finding radius (let's call it r) at some position, we need to iterate over r elements back, but as a result we can skip computation for r elements forward. Therefore, total number of iterated elements stays the same.
Perhaps you could iterate across potential middle character (odd length palindromes) and middle points between characters (even length palindromes) and extend each until you cannot get any further (next left and right characters don't match).
That would save a lot of computation when there are no many palidromes in the string. In such case the cost would be O(n) for sparse palidrome strings.
For palindrome dense inputs it would be O(n^2) as each position cannot be extended more than the length of the array / 2. Obviously this is even less towards the ends of the array.
public Set<String> palindromes(final String input) {
final Set<String> result = new HashSet<>();
for (int i = 0; i < input.length(); i++) {
// expanding even length palindromes:
expandPalindromes(result,input,i,i+1);
// expanding odd length palindromes:
expandPalindromes(result,input,i,i);
}
return result;
}
public void expandPalindromes(final Set<String> result, final String s, int i, int j) {
while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
result.add(s.substring(i,j+1));
i--; j++;
}
}
So, each distinct letter is already a palindrome - so you already have N + 1 palindromes, where N is the number of distinct letters (plus empty string). You can do that in single run - O(N).
Now, for non-trivial palindromes, you can test each point of your string to be a center of potential palindrome - grow in both directions - something that Valentin Ruano suggested.
This solution will take O(N^2) since each test is O(N) and number of possible "centers" is also O(N) - the center is either a letter or space between two letters, again as in Valentin's solution.
Note, there is also O(N) solution to your problem, based on Manacher's algoritm (article describes "longest palindrome", but algorithm could be used to count all of them)
I just came up with my own logic which helps to solve this problem.
Happy coding.. :-)
System.out.println("Finding all palindromes in a given string : ");
subPal("abcacbbbca");
private static void subPal(String str) {
String s1 = "";
int N = str.length(), count = 0;
Set<String> palindromeArray = new HashSet<String>();
System.out.println("Given string : " + str);
System.out.println("******** Ignoring single character as substring palindrome");
for (int i = 2; i <= N; i++) {
for (int j = 0; j <= N; j++) {
int k = i + j - 1;
if (k >= N)
continue;
s1 = str.substring(j, i + j);
if (s1.equals(new StringBuilder(s1).reverse().toString())) {
palindromeArray.add(s1);
}
}
}
System.out.println(palindromeArray);
for (String s : palindromeArray)
System.out.println(s + " - is a palindrome string.");
System.out.println("The no.of substring that are palindrome : "
+ palindromeArray.size());
}
Output:-
Finding all palindromes in a given string :
Given string : abcacbbbca
******** Ignoring single character as substring palindrome ********
[cac, acbbbca, cbbbc, bb, bcacb, bbb]
cac - is a palindrome string.
acbbbca - is a palindrome string.
cbbbc - is a palindrome string.
bb - is a palindrome string.
bcacb - is a palindrome string.
bbb - is a palindrome string.
The no.of substring that are palindrome : 6
I suggest building up from a base case and expanding until you have all of the palindomes.
There are two types of palindromes: even numbered and odd-numbered. I haven't figured out how to handle both in the same way so I'll break it up.
1) Add all single letters
2) With this list you have all of the starting points for your palindromes. Run each both of these for each index in the string (or 1 -> length-1 because you need at least 2 length):
findAllEvenFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i) != str.charAt(index+i+1))
return; // Here we found out that this index isn't a center for palindromes of >=i size, so we can give up
outputList.add(str.substring(index-i, index+i+1));
i++;
}
}
//Odd looks about the same, but with a change in the bounds.
findAllOddFrom(int index){
int i=0;
while(true) {
//check if index-i and index+i+1 is within string bounds
if(str.charAt(index-i-1) != str.charAt(index+i+1))
return;
outputList.add(str.substring(index-i-1, index+i+1));
i++;
}
}
I'm not sure if this helps the Big-O for your runtime, but it should be much more efficient than trying each substring. Worst case would be a string of all the same letter which may be worse than the "find every substring" plan, but with most inputs it will cut out most substrings because you can stop looking at one once you realize it's not the center of a palindrome.
I tried the following code and its working well for the cases
Also it handles individual characters too
Few of the cases which passed:
abaaa --> [aba, aaa, b, a, aa]
geek --> [g, e, ee, k]
abbaca --> [b, c, a, abba, bb, aca]
abaaba -->[aba, b, abaaba, a, baab, aa]
abababa -->[aba, babab, b, a, ababa, abababa, bab]
forgeeksskeegfor --> [f, g, e, ee, s, r, eksske, geeksskeeg,
o, eeksskee, ss, k, kssk]
Code
static Set<String> set = new HashSet<String>();
static String DIV = "|";
public static void main(String[] args) {
String str = "abababa";
String ext = getExtendedString(str);
// will check for even length palindromes
for(int i=2; i<ext.length()-1; i+=2) {
addPalindromes(i, 1, ext);
}
// will check for odd length palindromes including individual characters
for(int i=1; i<=ext.length()-2; i+=2) {
addPalindromes(i, 0, ext);
}
System.out.println(set);
}
/*
* Generates extended string, with dividors applied
* eg: input = abca
* output = |a|b|c|a|
*/
static String getExtendedString(String str) {
StringBuilder builder = new StringBuilder();
builder.append(DIV);
for(int i=0; i< str.length(); i++) {
builder.append(str.charAt(i));
builder.append(DIV);
}
String ext = builder.toString();
return ext;
}
/*
* Recursive matcher
* If match is found for palindrome ie char[mid-offset] = char[mid+ offset]
* Calculate further with offset+=2
*
*
*/
static void addPalindromes(int mid, int offset, String ext) {
// boundary checks
if(mid - offset <0 || mid + offset > ext.length()-1) {
return;
}
if (ext.charAt(mid-offset) == ext.charAt(mid+offset)) {
set.add(ext.substring(mid-offset, mid+offset+1).replace(DIV, ""));
addPalindromes(mid, offset+2, ext);
}
}
Hope its fine
public class PolindromeMyLogic {
static int polindromeCount = 0;
private static HashMap<Character, List<Integer>> findCharAndOccurance(
char[] charArray) {
HashMap<Character, List<Integer>> map = new HashMap<Character, List<Integer>>();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if (map.containsKey(c)) {
List list = map.get(c);
list.add(i);
} else {
List list = new ArrayList<Integer>();
list.add(i);
map.put(c, list);
}
}
return map;
}
private static void countPolindromeByPositions(char[] charArray,
HashMap<Character, List<Integer>> map) {
map.forEach((character, list) -> {
int n = list.size();
if (n > 1) {
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (list.get(i) + 1 == list.get(j)
|| list.get(i) + 2 == list.get(j)) {
polindromeCount++;
} else {
char[] temp = new char[(list.get(j) - list.get(i))
+ 1];
int jj = 0;
for (int ii = list.get(i); ii <= list
.get(j); ii++) {
temp[jj] = charArray[ii];
jj++;
}
if (isPolindrome(temp))
polindromeCount++;
}
}
}
}
});
}
private static boolean isPolindrome(char[] charArray) {
int n = charArray.length;
char[] temp = new char[n];
int j = 0;
for (int i = (n - 1); i >= 0; i--) {
temp[j] = charArray[i];
j++;
}
if (Arrays.equals(charArray, temp))
return true;
else
return false;
}
public static void main(String[] args) {
String str = "MADAM";
char[] charArray = str.toCharArray();
countPolindromeByPositions(charArray, findCharAndOccurance(charArray));
System.out.println(polindromeCount);
}
}
Try out this. Its my own solution.
// Maintain an Set of palindromes so that we get distinct elements at the end
// Add each char to set. Also treat that char as middle point and traverse through string to check equality of left and right char
static int palindrome(String str) {
Set<String> distinctPln = new HashSet<String>();
for (int i=0; i<str.length();i++) {
distinctPln.add(String.valueOf(str.charAt(i)));
for (int j=i-1, k=i+1; j>=0 && k<str.length(); j--, k++) {
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(j)))) {
distinctPln.add(str.substring(j,i+1));
}
// String of lenght 2 as palindrome
if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(i,k+1));
}
if ( (new Character(str.charAt(j))).equals(new Character(str.charAt(k)))) {
distinctPln.add(str.substring(j,k+1));
} else {
continue;
}
}
}
Iterator<String> distinctPlnItr = distinctPln.iterator();
while ( distinctPlnItr.hasNext()) {
System.out.print(distinctPlnItr.next()+ ",");
}
return distinctPln.size();
}
Code is to find all distinct substrings which are palindrome.
Here is the code I tried. It is working fine.
import java.util.HashSet;
import java.util.Set;
public class SubstringPalindrome {
public static void main(String[] args) {
String s = "abba";
checkPalindrome(s);
}
public static int checkPalindrome(String s) {
int L = s.length();
int counter =0;
long startTime = System.currentTimeMillis();
Set<String> hs = new HashSet<String>();
// add elements to the hash set
System.out.println("Possible substrings: ");
for (int i = 0; i < L; ++i) {
for (int j = 0; j < (L - i); ++j) {
String subs = s.substring(j, i + j + 1);
counter++;
System.out.println(subs);
if(isPalindrome(subs))
hs.add(subs);
}
}
System.out.println("Total possible substrings are "+counter);
System.out.println("Total palindromic substrings are "+hs.size());
System.out.println("Possible palindromic substrings: "+hs.toString());
long endTime = System.currentTimeMillis();
System.out.println("It took " + (endTime - startTime) + " milliseconds");
return hs.size();
}
public static boolean isPalindrome(String s) {
if(s.length() == 0 || s.length() ==1)
return true;
if(s.charAt(0) == s.charAt(s.length()-1))
return isPalindrome(s.substring(1, s.length()-1));
return false;
}
}
OUTPUT:
Possible substrings:
a
b
b
a
ab
bb
ba
abb
bba
abba
Total possible substrings are 10
Total palindromic substrings are 4
Possible palindromic substrings: [bb, a, b, abba]
It took 1 milliseconds