Is there a way to optimize space in this DP program? - c++

Problem Statement:
A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome. As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.
Input
The first line contains one integer: the length of the input string N, 3≤N≤5000. The second line contains one string with length N. The string is formed from uppercase letters from ‘A’ to ‘Z’, lowercase letters from ‘a’ to ‘z’ and digits from ‘0’ to ‘9’. Uppercase and lowercase letters are to be considered distinct.
Output
The first line contains one integer, which is the desired minimal number.
Link to problem => http://www.spoj.com/problems/IOIPALIN/
My solution:
#include <iostream>
#include <memory.h>
#include <cstdio>
using namespace std;
long memo[5010][5010];
string s;
long int n;
long solve(long i,long j){
if(memo[i][j]!=-1){
return memo[i][j];
}
if(i>=j)
return 0;
if(s[i]==s[j])
return solve(i+1,j-1);
return memo[i][j]= min(solve(i,j-1)+1,solve(i+1,j)+1);
}
int main()
{
ios_base::sync_with_stdio(false);
long int n ;
cin>>n;
cin>>s;
memset(memo,-1,sizeof(memo));
long int a = solve(0,n-1);
cout << a << endl;
return 0;
}
I am getting "time limit exceeded" for this code. How can I fix this ?

Well being a programmer its a bad practice to ask directly the solution to the question. I won't provide you with the exact code, but I will help you solve the problem.
To solve this an n^2 approach is needed. Dynamic programming is what you need. To achieve that create a string rev_str that is reverse of str. Now see the following pseudo code.
for(i = 0 to n)
for(j = 0 to n)
if(i = 0 or j = 0) dp[j][1] = 0;
else if(str[i - 1] = rev_str[j - 1]) dp[j][1] = dp[j - 1][0] + 1;
else dp[j][1] = max(dp[j][0], dp[j - 1][1];
for (j = 0 to n) dp[j][0] = dp[j][1];
your answer will be n - dp[n][0].
Basically what we are trying to do is at every step we are finding the maximum number of characters that match from str to rev_str. Those remaining will be needed to be added. Thus giving an answer.

Related

nth odd digit palindrome number

The following is the code of an nth even length palindrome, but i wanted to know the code for nth odd length palindrome.
#include <bits/stdc++.h>
using namespace std;
// Function to find nth even length Palindrome
string evenlength(string n)
{
// string r to store resultant
// palindrome. Initialize same as s
string res = n;
// In this loop string r stores
// reverse of string s after the
// string s in consecutive manner .
for (int j = n.length() - 1; j >= 0; --j)
res += n[j];
return res;
}
// Driver code
int main()
{
string n = "10";
// Function call
cout << evenlength(n);
return 0;
}
If you want an odd length palindrome (i.e. 101 for an input of 10 or 1234321 for an input of 1234), you might be able to replace the for loop with:
for (int j = static_cast<int>(n.size()) - 2; j >= 0; --j)
res += n[j];
(note n.length() - 2 rather than n.length() - 1)
This will skip the last character when adding the reversed version so that the last digit only shows up once.
Since you want to take input as a string and return a string, you can also make a new variable that is a sub string of input(ignoring last digit),reverse it and concat and return.
string Oddlength(string a)
{
string b;
b=a.substr(0,a.size()-1);
reverse(b.begin(),b.end());
a+=b;
return a;
}
This works because the nth(n>10) odd digit palindrome number is just the number concat with the reverse of the number ignoring the last digit. While for (n<10), its the number itself.
So the 120th odd digit palindrome number is "120"+ "21"="12021".
1200th odd digit palindrome number is "1200" + "021"="1200021".

Given two string S and T. Determine a substring of S that has minimum difference with T?

I have two string S and T where length of S >= length of T. I have to determine a substring of S which has same length as T and has minimum difference with T. Here difference between two strings of same length means, the number of indexes where they differ. For example: "ABCD" and "ABCE" differ at 3rd index, so their difference is 1.
I know I can use KMP(Knuth Morris Pratt) Pattern Searching algorithm to search T within S. But, what if S doesn't contain T as a substring? So, I have coded a brute force approach to solve this:
int main() {
string S, T;
cin >> S >> T;
int SZ_S = S.size(), SZ_T = T.size(), MinDifference = INT_MAX;
string ans;
for (int i = 0; i + SZ_T <= SZ_S; i++) { // I generate all the substring of S
int CurrentDifference = 0; // and check their difference with T
for (int j = 0; j < SZ_T; j++) { // and store the substring with minimum difference
if (S[i + j] != T[j])
CurrentDifference++;
}
if (CurrentDifference < MinDifference) {
ans = S.substr (i, SZ_T);
MinDifference = CurrentDifference;
}
}
cout << ans << endl;
}
But, my approach only works when S and T has shorter length. But, the problem is S and T can have length as large as 2 * 10^5. How can I approach this?
Let's maximize the number of characters that match. We can solve the problem for each character of the alphabet separately, and then sum up the results for
substrings. To solve the problem for a particular character, give string S and T as sequences 0 and 1 and multiply them using the FFT https://en.wikipedia.org/wiki/Fast_Fourier_transform.
Complexity O(|A| * N log N) where |A| size of the alphabet (for an uppercase letter is 26).

With letters represented as 2 digit numbers, converting a large number into a word

I have the following problem:
The letters a to z are represented by the numbers 10 - 35 e.g. a = 10, b = 11 ... z = 35
Given an integer how would you go about converting it into a word/sentence if each 2 digits of the number represent a letter? (the integer is the output of a decrypt process and so will always be applicable for conversion).
e.g 31232612 ---> "word"
I think that the best way to do this would be to split the integer into 2-digit chunks using % and determining the size of the number using log to the base 10? I'm unsure of exactly how this would work and I'm really interested in how other people would solve this problem.
I'm not sure whether to upload any code I have already or whether to leave it blank so in case anybody wants to give it a go from a clean slate, so just let me know.
Thanks for any feedback! (my first impression is that everything which is trivial is assumed to be homework so I thought that I would say that this isn't, I'm just doing it because I'm trying to improve and I find this kind of thing fun and thought I would share).
You will have to do something like this:
int main()
{
int numb=31231712;
std::stack<char> mystack;
int mod;
while ((mod=numb%100)!=numb){
char c=mod+88;
mystack.push(c);
numb=numb/100;
}
char c=mod+88;
mystack.push(c);
while (!mystack.empty())
{
cout << mystack.top();
mystack.pop();
}
cout << '\n';
}
It will print the word in reverse, I do not know if 88 is the right choice but that is an adjustable parameter use the ascii table. To take care of the reverse, just push all the chars in a stack. Afterwards, pop the stack till empty to get the word right.
I wrote this code, I think it can help you :)
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main () {
string word = "";
string integer;
cin >> integer;
for (int i = integer.size() - 1; i >= 0; i -= 2) {
int temp = integer[i] - '0';
if (i)
temp += 10 * (integer[i - 1] - '0');
word += (char)('a' + (temp - 10) + 1);
}
reverse(word.begin(), word.end());
cout << word << endl;
return 0;
}

Find number of palindromes that are anagrams in C++

I am taking part in an online programming contest for fun on http://www.hackerrank.com. One of the problems that I am working on is to find number of anagrams of a string that are palindrome as well. I have solve the problem but when I try to upload it it fails on a number of test cases. As the actual test cases are hidden from me I do not know for sure why its failing but I assume it could be a scalability issue. Now I do not want someone to give me a ready made solution because that would not be fair but I am just curious on what people think about my approach.
Here is the problem description from the website:
Now that the king knows how to find out whether a given word has an anagram which is a palindrome or not, he is faced with another challenge. He realizes that there can be more than one anagram which are palindromes for a given word. Can you help him find out how many anagrams are possible for a given word which are palindromes?
The king has many words. For each given word, the king needs to find out the number of anagrams of the string which are palindromes. As the number of anagrams can be large, the king needs number of anagrams % (109+ 7).
Input format :
A single line which will contain the input string
Output format :
A single line containing the number of anagram strings which are palindrome % (109 + 7).
Constraints :
1<=length of string <= 105
Each character of the string is a lowercase alphabet.
Each testcase has atleast 1 anagram which is a palindrome.
Sample Input 01 :
aaabbbb
Sample Output 01 :
3
Explanation :
Three permutation of given string which are palindrome can be given as abbabba , bbaaabb and bababab.
Sample Input 02 :
cdcdcdcdeeeef
Sample Output 02 :
90
As specified in the problem description input strings can be as large as 10^5, hence all palindromes for a large string is not possible since I will run into number saturation issues. Also since I only need to give a modulo (10^9 + 7) based answer, I thought of taking log of numbers with base (10^9 + 7) and after all computations take antilog of fraction part with base (10^9 + 7) of the answer since that will be the modulo anyway.
My algorithm is as follows:
Store freq of each char (only need to look half of the string since
second half should be same as first one by def of palindrome)
If there are more than one char appearing with odd number of time no palindrome possible
Else for each char's freq incrementally calculate number of palindromes (Dynamic Programming)
For the DP following is the subproblem:
previous_count = 1
For each additional character added number of palindromes = previous_count * (number_of_char_already_seen + 1)/(number of char same as current char)
Here is my code:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <fstream>
using namespace std;
#define MAX_SIZE 100001
void factorial2 (unsigned int num, unsigned int *fact) {
fact[num]++;
return;
}
double mylog(double x) {
double normalizer = 1000000007.0;
return log10(x)/log10(normalizer);
}
int main() {
string in;
cin >> in;
if (in.size() == 1) {
cout << 1 << endl;
return 0;
}
map<char, int> freq;
for(int i=0; i<in.size(); ++i) {
if (freq.find(in.at(i)) == freq.end()) {
freq[in.at(i)] = 1;
} else {
freq[in.at(i)]++;
}
}
map<char, int> ::iterator itr = freq.begin();
unsigned long long int count = 1;
bool first = true;
unsigned long long int normalizer = 1000000007;
unsigned long long int size = 0;
unsigned int fact[MAX_SIZE] = {0};
vector<unsigned int> numerator;
while (itr != freq.end()) {
if (first == true) {
first = false;
} else {
for (size_t i=1; i<=itr->second/2; ++i) {
factorial2(i, fact);
numerator.push_back(size+i);
}
}
size += itr->second/2;
++itr;
}
//This loop is to cancel out common factors in numerator and denominator
for (int i=MAX_SIZE-1; i>1; --i) {
while (fact[i] != 0) {
bool not_div = true;
vector<unsigned int> newNumerator;
for (size_t j=0; j<numerator.size(); ++j) {
if (fact[i] && numerator[j]%i == 0) {
if (numerator[j]/i > 1)
newNumerator.push_back(numerator[j]/i);
fact[i]--; //Do as many cancellations as possible
not_div = false;
} else {
newNumerator.push_back(numerator[j]);
}
}
numerator = newNumerator;
if (not_div) {
break;
}
}
}
double countD = 0.0;
for (size_t i=0; i<numerator.size(); ++i) {
countD += mylog(double(numerator[i]));
}
for (size_t i=2; i <MAX_SIZE; ++i) {
if (fact[i]) {
countD -= mylog((pow(double(i), double(fact[i]))));
fact[i] = 0;
}
}
//Get the fraction part of countD
countD = countD - floor(countD);
countD = pow(double(normalizer), countD);
if (floor(countD + 0.5) > floor(countD)) {
countD = ceil(countD);
} else {
countD = floor(countD);
}
count = countD;
cout << count;
return 0;
}
Now I have spent a lot of time on this problem and I just wonder if there is something wrong in my approach or am I missing something here. Any ideas?
Note that anagrams are reflexive (they look the same read from the back as from the front), so half the occurrences of each character will be on one side and we just need to calculate the number of permutations of these. The other side will be an exact reversal of this side, so it doesn't add to the number of possibilities. The odd occurrence of a character (if one exists) must always be in the middle, so it can be ignored when calculating the number of permutations.
So:
Calculate the frequencies of the characters
Check that there's only 1 odd frequency
Divide the frequency of each character (rounding down - removes any odd occurrence).
Calculate the permutation of these characters using this formula:
(as per Wikipedia - multiset permutation)
Since the above terms can get quite big, we might want to split the formula up into prime factors so we can cancel out terms so we're left with only multiplication, then I believe we can % 109 + 7 after each multiplication, which should fit into a long long (since (109+7)*105 < 9223372036854775807).
Thanks to IVlad for pointing out a more efficient method of avoiding overflow than above:
Notice that p = 109 + 7 is a prime number, so we can use Fermat's little theorem to compute the multiplicative inverses of the mi mod p, and multiply by these and take the mod at each step instead of dividing. mi-1 = mi(10^9 + 5) (mod p). Using exponentiation by squaring, this will be very fast.
I also found this question (which also has some useful duplicates).
Examples:
Input: aaabbbb
Frequency:
a b
3 4
Div 2:
a b
1 2
Solution:
3!/2!1! = 3
Input: cdcdcdcdeeeef
Frequency:
c d e f
4 4 4 1
Div 2:
c d e f
2 2 2 0
Solution:
6!/2!2!2!0! = 90
The basic formula is:
p!/(a!*b!...*z!)
where p is floor of length/2 of the word and a,b,c..,z denotes the floor of half of frequency of occurrences a,b,c..,z in the word receptively.
The only problem now you are left is how to calculate this. For that, check this out.

compare two alphanumeric string

I need to compare string into following way. Can anyone provide me some insight or algorithm in c++.
For example:
"a5" < "a11" - because 5 is less than 11
"6xxx < 007asdf" - because 6 < 7
"00042Q < 42s" - because Q < s alphabetically
"6 8" < "006 9" - because 8 < 9
I suggest you look at the algorithm strverscmp uses - indeed it might be that this function will do the job for you.
What this function does is the following. If both strings are equal,
return 0. Otherwise find the position between two bytes with the
property that before it both strings are equal, while directly after
it there is a difference. Find the largest consecutive digit strings
containing (or starting at, or ending at) this position. If one or
both of these is empty, then return what strcmp(3) would have
returned (numerical ordering of byte values). Otherwise, compare both
digit strings numerically, where digit strings with one or more
leading zeros are interpreted as if they have a decimal point in front
(so that in particular digit strings with more leading zeros come
before digit strings with fewer leading zeros). Thus, the ordering is
000, 00, 01, 010, 09, 0, 1, 9, 10.
Your examples only show digits, letters, and spaces. So for the moment I'll assume you ignore every other symbol (effectively treat them as spaces). You also seem to want to treat uppercase and lowercase letters as equivalent.
It also appears that you interpret runs of digits as a "term" and runs of letters as a "term", with any transition between a letter and a digit being equivalent to a space. A single space is considered equivalent to any number of spaces.
(Note: You are conspicuously missing an example of what to do in cases like:
"5a" vs "a11"
"a5" vs "11a"
So you have to work out what to do when you face a comparison of a numeric term with a string term. You also don't mention intrinsic equalities...such as should "5 a" == "5a" just because "5 a" < "5b"?)
One clear way of doing this would be turn the strings into std::vector of "terms", and then compare these vectors (rather than trying to compare the strings directly). These terms would be either numeric or string. This might help get you started, especially the STL answer:
how to split a string value that contains characters and numbers
Trickier methods that worked on the strings themselves without making an intermediary will be faster in one-off comparisons. But they'll likely be harder to understand and modify, and perhaps slower if you are going to repeatedly compare the same structures.
A nice aspect of parsing into a structure is that you get an intrinsic "cleanup" of the data in the process. Getting the information into a canonical form is often a goal in programs that are tolerating such a variety of inputs.
I'm assuming that you want the compare to be done in this order: presence of digits in range 1-9; value of digits; number of digits; value of the string after the digits.
It's in C, but you can easily transform it into using the C++ std::string class.
int isdigit(int c)
{
return c >= '1' && c <= '9';
}
int ndigits(const char *s)
{
int i, nd = 0;
int n = strlen(s);
for (i = 0; i < n; i++) {
if (isdigit(s[i]))
nd++;
}
return nd;
}
int compare(const char *s, const char *t)
{
int sd, td;
int i, j;
sd = ndigits(s);
td = ndigits(t);
/* presence of digits */
if (!sd && !td)
return strcasecmp(s, t);
else if (!sd)
return 1;
else if (!td)
return -1;
/* value of digits */
for (i = 0, j = 0; i < sd && j < td; i++, j++) {
while (! isdigit(*s))
s++;
while (! isdigit(*t))
t++;
if (*s != *t)
return *s - *t;
s++;
t++;
}
/* number of digits */
if (i < sd)
return 1;
else if (j < td)
return -1;
/* value of string after last digit */
return strcasecmp(s, t);
}
Try this and read about std::string.compare:
#include <iostream>
using namespace std;
int main(){
std::string fred = "a5";
std::string joe = "a11";
char x;
if ( fred.compare( joe ) )
{
std::cout << "fred is less than joe" << std::endl;
}
else
{
std::cout << "joe is less than fred" << std::endl;
}
cin >> x;
}