For this question, I need to find the largest three-digit number within a larger number.
Sample Test Case 1: 534535 Output: 535
Sample Test Case 2 : 23457888976 Output : 976
I've tried the following code:
#include <iostream>
using namespace std;
int main() {
int num;
cin>>num;
int len= to_string(num).length();
int arr[10],lnum=0,max=0;
for (int i =len-1;i>=0;i--)
{
arr[i] = num%10;
num =num/10; //to convert int into array
}
for (int i=0;i<len-2;i++)
{
if (arr[i] >arr[i+1])
lnum = arr[i]*100+arr[i+1]*10+arr[i];
if (lnum>max)
max= lnum;
}
cout<<max;
return 0;
}
Although this code seems to work for Test Case 1, it doesn't work for most of the inputs.
(Please do help with this too. )
1. This is for numbers with 10-digits only (that too, most of it have wrong output). What to do in case of bigger numbers?
2. Is there any better way to convert the integer into an array? Or will a string array work in similar way?
3. It's really slow, can anyone help me figure out how to speed this up?
Thanks for any help !!
#include <iostream>
#include <string>
using namespace std;
int main() {
int i, n;
string s;
cin >> s;
n = (int)s.size();
if(n<3){
/* there are less than 3 digits in the input number
Here, you can print the number itself as it will be largest number or
print -1 which can state that no 3 digit number exists.
*/
cout<<-1;
return 0;
}
int maxans = (s[0]-'0')*100 + (s[1]-'0')*10 + (s[2]-'0');
// storing the first 3 digits as the maximum answer till now.
int prev = maxans;
for(i = 3;i<n;i++){
int cur = (prev%100)*10 + (s[i]-'0'); // using %100 to extract the last two digits and then multiplying by 10 and adding the ith digit to make the next 3 digit number.
maxans = max(maxans, cur);
prev = cur;
}
cout<<maxans;
return 0;
}
This code is of time complexity O(n) where n is the length of input string and space complexity O(1)
This approach will work with any big number you can store in variable. The approach is as follows,
First convert number into string and then create an array of all possible numbers of 3 digits as showed below,
Number = 534535
All possible 3 digits number array = ["534", "345", "453", "535"]
Then sort this array, after sorting last element will be max number of three digit, as highlighted below,
Sorted array = ["345", "453", "534", "535"]
Another example,
Number = 23457888976
All possible 3 digits number array = ["234", "345", "457", "578", "788", "888", "889", "897", "976"]
After sorting, last element is max number as highlighted below
Sorted array = ["234", "345", "457", "578", "788", "888", "889", "897", "976"]
Note: Radix sort will perform better then std::sort(), std::sort() offers Quick sort. Radix sort is ideal for string sorting and specially in this case because max bucket size is only 10 (possible range 0-9), but you have to implement radix sort your self.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using std::cout;
std::vector<std::string> allThreeDigitNumbers(const std::string& numStr){
std::vector<std::string> allNumStr(numStr.size() - 2, std::string("000"));
std::vector<std::string>::iterator aIt = allNumStr.begin();
for(std::string::const_iterator it = numStr.cbegin(), lastIt = it + (numStr.size() - 2); lastIt != it; ++it, ++aIt){
std::copy(it, it + 3, aIt->begin());
}
return allNumStr;
}
unsigned maxThreeDigitNumberInNumber(unsigned long long num){
std::string numStr = std::to_string(num);
if(numStr.size() < 3){
return 0;
}
std::vector<std::string> allNumStr = allThreeDigitNumbers(numStr);
std::sort(allNumStr.begin(), allNumStr.end());
return std::stoul(allNumStr.back());
}
int main(){
cout<< "Max 3 digits number of 534535 => "<< maxThreeDigitNumberInNumber(534535)<< '\n';
cout<< "max 3 digits number of 23457888976 => "<< maxThreeDigitNumberInNumber(23457888976)<< '\n';
}
Output
Max 3 digits number of 534535 => 535
max 3 digits number of 23457888976 => 976
Read the comments to understand the code below:
#include <assert.h>
#include <iostream>
#include <boost/hana/functional/partial.hpp>
#include <functional>
#include <range/v3/to_container.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/take.hpp>
#include <range/v3/algorithm/all_of.hpp>
#include <string>
using namespace boost::hana;
using namespace ranges;
using namespace ranges::views;
auto constexpr is9 = partial(std::equal_to<>{}, 9);
template<typename Range>
Range fun(Range const& r) {
if (r.size() == 3) { // 3 digits only?
return r; // this is the result
} else if (all_of(r | take(3), is9)) { // 999?
return r | take(3); // nothing better than this!
} else { // otherwise?
auto tail = r | drop(1); // drop the first to get the tail
if (r.front() < tail.front()) { // if the first is less the the tip of the tail
return fun(tail); // then let the first go and recurse on the tail
} else { // otherwise
auto result = std::max( // get the maximum between
r | take(3) | to<std::string>, // the current first three
fun(tail) | to<std::string> // and the result of recursing on the tail
);
return result; // and that's the result
}
}
return r;
}
int main() {
std::string s1 = "534535";
std::string s2 = "23457888976";
assert((fun(subrange(s1)) | to<std::string>) == std::string{"535"});
assert((fun(subrange(s2)) | to<std::string>) == std::string{"976"});
}
The number is treated as a string, and since we need to compare (sub-)strings of length 3, the lexicographic operator< for std::strings gives us the same result as the arithmetic operator< would give for the two corresponding numbers.
The logic is:
we start from left and recurse to the right if needed
in the case of only 3 digits left, r.size() == 3, we return all of them, return r;
in the case of three leading nines, all_of(r | take(3), is9), we trivially return those three, return r | take(3);;
otherwise, we take the std::max between the leading 3-digit string, r | take(3) | to<std::string>, and the std::string we obtain by recursing on the rest of the sequence without the first digit, fun(tail) | to<std::string>.
Solution in Python3
#!/usr/bin/env python
num = input("Enter the number : ")
if len(num) == 3:
print(f"Largest digit is : {num}")
exit(0)
elif len(num) < 3:
print(-1)
exit(0)
maxans = int((num[0].replace("0", "")))*100 + int((num[1].replace("0", "")))*10 + int((num[2].replace("0", "")))
prev = maxans
for i in range(3, 6):
cur = (prev%100)*10 + int((num[i].replace("0", "")))
maxans = max(maxans, cur)
prev = cur
print(f"The Largest num = : {maxans}")
Related
The Problem:
A company is distributing phone numbers to its employees to make things easier. the next digit cannot be equal to the last is the only rule for example 0223 is not allowed while 2023 is allowed. At least three digits will be excluded every time. Write a function that takes in a length of the phone number and the digits that will be excluded. The function should print all possible phone numbers.
I got this question in an interview and I have seen one like it before at my university. It is a permutation problem. My question is what is the best way or decent way to solve this without a million for loops.
I do understand that this is technically how it works
length of phone number = 3;
[0-9], [0-9] excluding the last digit, [0-9] excluding the last digit
but I am unsure on how the best way to turn this into code. Any language is accepted!
thank you:
Also I might be asking this in the wrong place. please let me know if I am.
A simple way to solve this problem could be using Recursion. Here's my commented C++ code:
void solve(int depth, int size, vector <int> &curr_seq){
// If the recursion depth is equal to size, that means we've decided size
// numbers, which means that curr_seq.size() == size. In other words, we've
// decided enough numbers at this point to create a complete phone number, so
// we print it and return.
if(depth == size){
for(int item : curr_seq){
cout << item;
}
cout << "\n";
return;
}
// Try appending every possible digit to the current phone number
for(int i = 0; i <= 9; ++i){
// Make sure to only append the digit i if it is not equal to the last digit
// of the phone number. We can also append it, however, if curr_seq
// is empty (because that means that we haven't decided the 1st digit yet).
if(curr_seq.empty() || curr[curr.size() - 1] != i){
curr_seq.push_back(i);
solve(depth + 1, size, curr);
curr_seq.pop_back();
}
}
}
I think I like the recursive solution, but you can also just generate all permutations up to the limit (iterate), filter out any with repeating digits, and print the successful candidates:
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std;
// Because C/C++ still has no integer power function.
int ipow(int base, int exp) {
int result = 1;
for (;;) {
if (exp & 1)
result *= base;
exp >>= 1;
if (!exp)
return result;
base *= base;
}
}
void noconsec(const int len) {
int lim = ipow(10, len);
// For e.g. len 4 (lim 10000),
// obviously 00xx won't work, so skip anything smaller than lim / 100.
int start = (len <= 2) ? 0 : (lim / 100);
for (int num = start;num < lim;num++) {
// Convert to string.
std::stringstream ss;
ss << std::setw(len) << std::setfill('0') << num;
std::string num_s = ss.str();
// Skip any consecutive digits.
bool is_okay = true;
auto prev_digit = num_s[0];
for (int digit_idx = 1;digit_idx < num_s.length();digit_idx++) {
auto digit = num_s[digit_idx];
if (prev_digit == digit) {
is_okay = false;
}
prev_digit = digit;
}
// Output result.
if (is_okay) {
cout << num_s << "\n";
}
}
}
int main(const int argc, const char * const argv[]) {
noconsec(4);
}
Differences to note, this needs an integer power function to compute the limit. Converting an int to a string and then checking the string is more complex than constructing the string directly. I guess it could be useful if you have a list of integers already, but mostly I did it for fun.
I was given an input string, which is formed of N number of repetitions of a base string.
I need to find the occurrence of 'b' between two index points.
string mystr="ababba"
number of repetitions = 1000 ,
find occurrence of 'b' between two indexes, say 120 and 250.
I cannot use brute force where I increment my way upto 120 and then count the number of 'b' till the end index, this times out for large input string.
I have calculated and stored the occurrence of b in the the string of 6 character "ababba" as 3.
how do I proceed?
for( auto& each : mystr)
{
if (each == 'b')
cntb++;
}
try this:
#include <iostream>
#include <cstring>
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main()
{
char inputString[11];
int b_in_string, b_occurrence, repetitions, startIndex, endIndex, actual_needed_count;
cout<<"Input string: ";
cin>>inputString;
cout<<"Repetitions: ";
cin>>repetitions;
cout<<"Start index: ";
cin>>startIndex;
cout<<"End index: ";
cin>>endIndex;
if(endIndex < startIndex)
{
cout<<"End index must be larger than start index. Program terminated.";
return 1;
}
b_in_string = 0;
b_occurrence = 0;
for(int i = 0; i < sizeof(inputString); i++)
{
if(inputString[i] == 'b')
{
b_in_string++;
}
}
actual_needed_count = endIndex - startIndex + 1; //start and end indexes inclusive
b_occurrence = b_in_string * actual_needed_count;
cout<<"Number of times 'b' occurs: ";
cout<<b_occurrence;
return 0;
}
It works on https://www.onlinegdb.com/online_c++_compiler. Hope it helps.
How to obtain rightmost unset bit position of a number N in c++.
1<= N <= 2^60
storing as number does not work since 2^60 can only be stored in string.
thus following does not work
long long getBitUtil(long long n) {
return log2(n&-n)+1;
}
long long getBit(long long n) {
return getBitUtil(~n);
}
Try this. Code is self explanatory with comments
int getRightmostUnSetBit(string s, int pos)
{
int l= s.size();
int lc = s[l-1];
if(lc>=48 && lc<=57 && lc%2 ==0)
return pos; // if last digit is even return position
else
{// divide the number into half and call function again.
string s2 = "";
int rem =0;
for(int i =0; i<l;i++)
{
int d = s[i]-'0';
d = rem *10 + d;
int q = d/2;
rem = d%2;
s2.push_back('0'+q);
}
return getRightmostUnSetBit(s2,pos+1); //call for s2
}
}
Take input in string and call from main
int pos = getRightmostUnSetBit(s,1);// will not work if s is "0" or similar to "000...". So check for it before function calling.
For normal integers the solution is basically given in the book Hackers Delight. I can only refer to the book. I cannot copy. But section 2.1 gives already good hints.
Depending on your OS you will most likely have 64 bit data types. With 64 bit data types, you can still use arithmentic solutions for your given number range. Above that, you should use string representations.
Then we will convert a big decimal number given as string into a string containing its binary equivalent.
Then we search for the last 0 in the resulting binary string.
The secret is to do a division by 2 for a number given as string. This can be done as we learned in school on a piece of paper.
And then check, if the number is even or odd and put a 1 or 0 respectively in the resulting string.
This will work for abitrary big numbers. Limiting factor (but here not really) is the length of the resulting binary string. That must fit into a std::string :-)
See:
#include <string>
#include <iostream>
#include <bitset>
#include <iterator>
#include <regex>
#include <stack>
#include <algorithm>
// Odd numbers. We will find out, if a digit is odd or even
std::string oddNumbers{ "13579" };
// Devide a number in a string by 2. Just like in school on a piece of paper
void divideDecimalNumberAsStringBy2(std::string& str)
{
// Handling of overflow during devisions
unsigned int nextNumberToAdd{ 0 };
// The resulting new string
std::string newString{};
// Go through all digits, starting from the beginning
for (char& c : str) {
// Get overflow for next round
unsigned int numberToAdd = nextNumberToAdd;
// Get the overflow value for the next devision run. If number is odd, it will be 5
nextNumberToAdd = (oddNumbers.find(c) != std::string::npos) ? 5 : 0;
// Do the devision. Add overflow from last round
unsigned int newDigit = (c - '0') / 2 + numberToAdd;
// Build up newe string
newString += static_cast<char>(newDigit + '0');
}
// Remove leading zeroes
str = std::regex_replace(newString, std::regex("^0+"), "");
}
// Convert a string with a big decimal number to a string with a binar representation of the number
std::string convertDecimalStringToBinaryString(std::string& str)
{
// Resulting string
std::string binaryDigits{};
// Until the string is empty. Will be shorter and short because of devision by 2
while (!str.empty()) {
// For an even number we add 0, for an odd number we add 1
binaryDigits += (oddNumbers.find(str.back()) == std::string::npos) ? '0' : '1';
// And devide by 2
divideDecimalNumberAsStringBy2(str);
}
// Bits come in wrong order, so we need to revers it
std::reverse(binaryDigits.begin(), binaryDigits.end());
return binaryDigits;
}
int main()
{
// Initial string with a big number. Get input from user
std::string bigNumber{};
std::cout << "Enter big number: ";
std::cin >> bigNumber;
// Convert it
std::string binaryDigits = convertDecimalStringToBinaryString(bigNumber);
// Find the last 0
unsigned int posOfLast0 = binaryDigits.rfind('0');
// Show result
if (posOfLast0 == std::string::npos)
std::cout << "\nNo digit is 0 --> " << binaryDigits << '\n';
else
std::cout << "\nSize of resulting string: "<< binaryDigits.size() << "\nPos of last 0: " << posOfLast0+1 << "\nBinary String:\n\n" << binaryDigits << '\n';
return 0;
}
I came across one of the common interview question which was to find the closest palindrome number. Say if the input is 127 then output will be 131 and if it is 125 then it should give 121 as output.
I can come up with the logic but my logic fails on certain cases like 91, 911. In these inputs it give 99 , 919 but the correct output is 88 and 909.
Algorithm steps are:
Convert the number into string.
copy first half to second half in reverse order
convert to number and measure the abs. difference with original number diff1
add 1 to half string and now copy first half to second half in reverse order
convert to number and measure the abs. difference with original number diff2
if diff1 is less than diff2 return first number else return second number
This is actually an interesting problem. Obviously what you want to do to make this more than just a brute force is to use the most significant digits and put them in the least significant digit locations to form a palindrome. (I'm going to refer to the difference between the palindrome and the original as the "distance")
From that I'm going to say that we can ignore the least significant half of the numbers because it really doesn't matter (it matters when determining the distance, but that's all).
I'm going to take an abstract number: ABCDEF. Where A,B,C,D,E,F are all random digits. Again as I said D,E,F are not needed for determining the palindrome as what we want is to mirror the first half of the digits onto the second half. Obviously we don't want to do it the other way around or we'd be modifying more significant digits resulting in a greater distance from the original.
So a palindrome would be ABCCBA, however as you've already stated this doesn't always you the shortest distance. However the "solution" is still of the form XYZZYX so if we think about minimizing the "significance" of the digits we're modifying that would mean we'd want to modify C (or the middle most digit).
Lets take a step back and look at why: ABCCBA
At first it might be tempting to modify A because it's in the least significant position: the far right. However in order to modify the least significant we need to modify the most significant. So A is out.
The same can be said for B, so C ends up being our digit of choice.
Okay so now that we've worked out that we want to modify C to get our potentially closer number we need to think about bounds. ABCDEF is our original number, and if ABCCBA isn't the closest palindrome, then what could be? Based on our little detour above we can find it by modifying C. So there are two cases, ABCDEF is greater than ABCCBA or that is less than ABCCBA.
If ABCDEF is greater than ABCCBA then lets add 1 to C. We'll say T = C+1 so now we have a number ABTTBA. So we'll test to make sure that ABCDEF - ABCCBA > ABCDEF - ABTTBA
and if so we know that ABTTBA is the nearest palindrome. As any more modifications to C would just take us more and more distant.
Alternately if ABCDEF is less than ABCCBA then we'll subtract 1 from C. Let's say V = C-1. So we have ABVVBA, which just like above we'll test: ABCDEF - ABCCBA > ABCDEF - ABVVBA and you'll have the same solution.
The trick is that ABCDEF is always between ABTTBA and ABVVBA and the only other palindrome between those numbers is ABCCBA. So you only have 3 options for a solution. and if you compare ABCDEF to ABCCBA you only need to check 2.
I don't think it will be hard for you to adapt this to numbers of any size. and in the case of an odd number of digits you'd simply have ABCBA, ABVBA and ABTBA and so on...
So just like your examples: lets take 911.
Ignore the last 1 we only take the first half (round up). so 91X.
Replace X with 9. we have 919. this is out mid point.
We know our original 911 is less than 919 so subtract 1 from our middle number so we get our second (lower bound) 909.
Compare 911 - 919 and 911 - 909
return the one with the smallest difference.
So this gives us a constant time algorithm :)
As pointed out in the comments this is not constant time in the worst case (oops), but is certainly better than a brute force approach.
This appears to be what you have, but I thought I'd elaborate to hopefully shed light on the issue as it seems to be a small programming error on your part otherwise.
This is an implementation of Naveen's and Don's algorithm. It uses Happy Yellow Face's algorithm as a test oracle.
I would be happy to see people tweak it to remove redundant steps or special cases.
gcc 4.7.3: g++ -Wall -Wextra -std=c++0x nearest-palindrome.cpp
#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
// I do not have std::to_string.
template <class T>
std::string to_string(const T& v) {
std::stringstream ss;
ss << v;
return ss.str(); }
// Nor do I have std::stoi. :(
int stoi(const std::string& s) {
std::stringstream ss(s);
int v;
ss >> v;
return v; }
bool isPalindrome(int n) {
const auto s = to_string(n);
return s == std::string(s.rbegin(), s.rend()); }
int specNearestPalindrome(int n) {
assert(0 <= n);
int less = n, more = n;
while (true) {
if (isPalindrome(less)) { return less; }
if (isPalindrome(more)) { return more; }
--less; ++more; } }
std::string reflect(std::string& str, int n) {
std::string s(str);
s.resize(s.size() + n);
std::reverse_copy(std::begin(str),
std::next(std::begin(str), n),
std::next(std::begin(s), str.size()));
return s; }
bool isPow10(int n) {
return n < 10 ? n == 1 : (n % 10 == 0) && isPow10(n / 10); }
int nearestPalindrome(int n) {
assert(0 <= n);
if (n != 1 && isPow10(n)) { return n - 1; } // special case
auto nstr = to_string(n);
// first half, rounding up
auto f1 = nstr.substr(0, (nstr.size() + 1) / 2);
auto p1 = stoi(reflect(f1, nstr.size() / 2));
const auto twiddle = p1 <= n ? 1 : -1;
auto f2 = to_string((stoi(f1) + twiddle));
auto p2 = stoi(reflect(f2, nstr.size() / 2));
if (p2 < p1) { std::swap(p1, p2); }
return n - p1 <= p2 - n ? p1 : p2; }
int main() {
std::vector<int> tests = { 0, 1, 6, 9, 10, 11, 12, 71, 74, 79, 99, 100, 999, 1000, 9900, 9999, 999000 };
for (const auto& t : tests) {
std::cout <<
(nearestPalindrome(t) == specNearestPalindrome(t) ? "." : "X");
}
std::cout << std::endl;
return 0; }
Here is a generic algorithm that would work1, although using brute-force:
int findNearestPalindrome(int n) {
int less = n;
int more = n;
while(true) {
if (isPalindrome(less)) return less;
if (isPalindrome(more)) return more;
--less;
++more;
}
}
WithinisPalindrome() function, all you need to do is convert the number to a string, and then compare the string with itself reversed.
1 However, this wouldn't check for tie cases, like Ted Hopp commented. You'd have to make a few changes to make it tie-recognizable.
#include <iostream>
#include <cmath>
#include <functional>
#include <limits>
#include <sstream>
// for convience
using namespace std;
using ULL = unsigned long long int;
// calculate the number of digits
auto Len = [](auto num) -> ULL {
return floor(log10(num)) + 1; };
// extract left half of number
auto Halfn = [](auto num, auto olen) {
for (unsigned i = 0; i < olen / 2; num /= 10, ++i);
return num;
};
int main() {
ULL num; cin >> num;
// some basic checking
if (num < 10) {
cerr << "Error, enter a number >= 10";
return 0;
}
if (numeric_limits<ULL>::max() < num) {
cerr << "Error, number too large\n";
return 0;
}
cout << ([](auto num) {
auto olen = Len(num);
auto lhalf = Halfn(num, olen);
function<ULL(ULL)> palin = [olen] (auto lhalf) {
auto half = to_string(lhalf);
// this is the mirror string that needs to be
// appended to left half to form the final
// palindrome
auto tmp = half.substr(0, olen / 2);
// take care of a corner case which
// happens when the number of digits in
// the left half of number decrease, while
// trying to find a lower palindrome
// e.g. num = 100000
// left half = 100 , the value passed to the
// function palin, is 99. if all digits are 9
// then we need to adjust the count of 9,
// otherwise if i simply replicate it, i'll get
// 9999 but one more 9 is required for the
// correct output.
if (olen / 2 > tmp.size() &&
all_of(tmp.begin(), tmp.end(),
[](auto c) { return '9' == c; })) {
tmp += '9';
}
// append, convert and return
half = half + string(tmp.crbegin(),
tmp.crend());
return stoull(half);
};
auto bpalin = palin(lhalf);
auto hpalin = palin(lhalf + 1);
auto lpalin = palin(lhalf - 1);
stringstream ss;
ss << "base palindrome = " << bpalin <<'\n';
ss << "higher palindrome = "<<hpalin <<'\n';
ss << "lower palindrome = " << lpalin <<'\n';
// calculating absolute difference for
// finding the nearest palindrome
auto diffb = labs(bpalin - num);
auto diffh = labs(hpalin - num);
auto diffl = labs(lpalin - num);
auto nearest = (diffb < diffh) ?
(diffb < diffl) ? bpalin : lpalin :
(diffh < diffl) ? hpalin : lpalin;
ss << "nearest palindrome = "
<< nearest << endl;
return move(ss.str());
}(num));
} // end main
class Solution {
public String nearestPalindromic(String n) {
int order = (int) Math.pow(10, n.length()/2);
Long ans = Long.valueOf(new String(n));
Long noChange = mirror(ans);
Long larger = mirror((ans/order)*order + order+1);
Long smaller = mirror((ans/order)*order - 1 );
if ( noChange > ans) {
larger = (long) Math.min(noChange, larger);
} else if ( noChange < ans) {
smaller = (long) Math.max(noChange, smaller);
}
return String.valueOf( ans - smaller <= larger - ans ? smaller :larger) ;
}
Long mirror(Long ans) {
char[] a = String.valueOf(ans).toCharArray();
int i = 0;
int j = a.length-1;
while (i < j) {
a[j--] = a[i++];
}
return Long.valueOf(new String(a));
}
}
Javascript Solution:
const findNearestPalindrome = n => {
if (!n) return 0;
let lowestPalindorm = lowestPalindromeHelper(n);
let largestPalindrome = largestPalindromeHelper(n);
let closestPalindrome = 0;
closestPalindrome =
Math.floor(n - lowestPalindorm) > Math.floor(largestPalindrome - n)
? largestPalindrome
: lowestPalindorm;
console.log(closestPalindrome);
};
//lowestPalindrome check
const lowestPalindromeHelper = num => {
for (let i = num - 1; i >= 0; i--) {
if (isPalindrome(i.toString())) {
return i;
}
}
};
//largest Palindrome Check
const largestPalindromeHelper = num => {
for (let i = num + 1; i <= Number.MAX_SAFE_INTEGER; i++) {
if (isPalindrome(i.toString())) {
return i;
}
}
};
const isPalindrome = n => {
return (
n ===
n
.split('')
.reverse()
.join('')
);
};
findNearestPalindrome(1234);
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.