Recursion in c++ (generate binary codes) - c++

I am trying to write a program that generates all the binary codes given an input number (for the number of bits). For example, if the user inputs 3, it should generate all the numbers below:
000
001
010
011
100
101
110
111
The function is called generateBinaryCode(), and it has to be recursive (that's the challenge of the question).
The following is my attempt but it doesn't work. Can anyone please offer me some insights?
Thanks in advance.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> generateBinaryCode(int nBits);
int main()
{
int input;
while (true)
{
cout << "Enter an integer (any negative numbers are sentinel): ";
cin >> input;
if (input < 0) break;
for (unsigned i = 0; i < generateBinaryCode(input).size(); i++)
cout << generateBinaryCode(input).at(i) << endl;
}
return 0;
}
vector<string> generateBinaryCode(int nBits)
{
vector<string> result;
int size = result.size();
std::vector<string>::iterator it;
if (nBits == 1) {
result.push_back("0");
result.push_back("1");
} else {
result = generateBinaryCode(nBits - 1);
for (unsigned int i = 0; i < result.size(); i++)
{
result.push_back("0" + result.at(i));
result.at(i) = "1" + result.at(i);
}
}
return result;
}

Your code is very close to correct, but the self-modifying result is going to be problematic. insertion into a vector does many things, among them invalidating iterators currently open on the sequence. But it will also change the result of size() (for obvious reasons, I hope).
The simplest answer is to use a sub list vector, then enumerate that, appending all entries within with '0' and '1', and inserting those results into your return vector. An example of this is below:
std::vector<std::string> getBitStrings(unsigned int n)
{
std::vector<std::string> result;
if (n <= 1)
{
result.push_back("0");
result.push_back("1");
}
else
{ // recurse, then add extra bit chars
std::vector<std::string> sub = getBitStrings(n-1);
for (std::vector<std::string>::const_iterator it = sub.cbegin();
it != sub.cend(); ++it)
{
result.push_back(*it+'0');
result.push_back(*it+'1');
}
}
return result;
}
This is somewhat different than your implementation, in that it expects values between 1 and n for the bit count. Running with n=5, the following is produced:
int main()
{
std::vector<std::string> bs = getBitStrings(5);
std::copy(bs.begin(), bs.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Output
00000
00001
00010
00011
00100
00101
00110
00111
01000
01001
01010
01011
01100
01101
01110
01111
10000
10001
10010
10011
10100
10101
10110
10111
11000
11001
11010
11011
11100
11101
11110
11111
To be honest there are a plethora of ways this can be done, this is just one. I purposely modeled it after your original implementation so as to limit algorithm change. I hope it helps you understand the problem and one way around it.

The main flaw is in the following loop:
for (unsigned int i = 0; i < result.size(); i++)
{
result.push_back("0" + result.at(i));
result.at(i) = "1" + result.at(i);
}
In a nutshell, you don't want to be adding elements to result while iterating over it. What you have right now is an infinite loop (that'll eventually run out of memory).
Also, you don't want to be calling generateBinaryCode() at every iteration of your main loop. Call it once and store the result in a variable.
And finally (and least importantly), entering 0 at the prompt will result in infinite recursion.

simpler and concise solution
void printBin(std::string prefix, int n)
{
if(prefix.size() == n)
{
std::cout <<prefix <<std::endl;
return;
}
printBin(prefix + '0', n);
printBin(prefix + '1', n);
return;
}
int main()
{
int n;
std::cin >> n;
printBin("", n);
return 0;
}

What you are trying to do at this line
result.push_back("0" + result.at(i));
is basically this, and that may be dodgy, and cause of your problem.

Here's a simple one:
(written in C, not C++, but the outline should be the same)
void generateBinaryCode(char* txt, int i, int len)
{
if (len != 0)
{ txt[i] = '0';
makeBinary(txt, i+1, len-1);
txt[i] = '1';
makeBinary(txt, i+1, len-1);
} else
{
puts(txt);
}
}
int main()
{
char str[4] = {0};
generateBinaryCode(str, 0, sizeof(str)-1);
getchar();
return 0;
}

Related

Symmetric Matrix in C++

Checking whether a 2D Matrix is symmetric or not
Task is to output YES if the matrix is symmetric else output NO.
I am not getting the expected result. Can someone please help me out and please let me know what's wrong with this code
#include<iostream>
#include<vector>
using namespace std;
bool rev(int n)
{
int n1,d,rn=0;
n1=n;
while(n>0)
{
d=n%10;
rn=(rn*10)+d;
n/=10;
}
if(n1==rn)
{return true;}
else
return false;
}
bool XAxisSymCheck(vector<int> vect)
{
// Declaring iterator to a vector
vector<int>::iterator ptr;
for (ptr = vect.begin(); ptr < vect.end(); ptr++)
{ if(!rev(*ptr)) // reversing the elements in each element of vector to check whether its symmetric or not .. similar to palindrome
{
return false;
}
}
}
int main()
{int testcase;
cin>>testcase;
for(int k=0;k<testcase;++k)
{vector<int> rows;
bool IsSymmetric=true;
int row;
cin >> row;
// read each row and append to the "rows" vector
for (int r = 0; r < row; r++)
{
int line;
cin >> line;
rows.push_back(line);
}
if(XAxisSymCheck(rows))
{int i,j;
i=0;
j=row-1;
while(i<j) // looping through the elements of vector and checking the first element with last element , second element with the second last element and so on.
{
if(rows[i]!=rows[j])
{
IsSymmetric=false;
break;
}
i++;
j--;
}
}
else
{
IsSymmetric=false;
}
cout << (IsSymmetric ? "Yes" : "No") << endl;
}
return 0;
}
Input:
First line contains T - number of test cases.
T test cases follow.
First line of each test case contains the N - size of matrix.
Next N lines contains binary strings of length N.
Output:
Print YES or NO in a new line for each test case
SAMPLE INPUT
5
2
11
11
4
0101
0110
0110
0101
4
1001
0000
0000
1001
5
01110
01010
10001
01010
01110
5
00100
01010
10001
01010
01110
SAMPLE OUTPUT
YES
NO
YES
YES
NO
Test Case #1: Symmetric about both axes, so YES.
Test Case #2: Symmetric about X-axis but not symmetric about Y-axis, so NO.
Test Case #3: Symmetric about both axes, so YES.
Test Case #4 and #5 are explained in statement.
There are three problems with your code
1) You are never returning true from XAxisSymCheck (this can easily discovered by inspecting the compiler warnings, eg g++ -Wall matrix.cpp)
bool XAxisSymCheck(vector<int> vect) {
vector<int>::iterator ptr;
for (ptr = vect.begin(); ptr < vect.end(); ptr++) {
if(!rev(*ptr, vect.size()))
return false;
}
return true;
}
2) When your XAxisSymCheck fails, you are not setting IsSymmetric to false (at least in the original post before the edit)
for(int k=0;k<testcase;++k) {
vector<int> rows;
bool IsSymmetric = true;
// ....
if (XAsxisSymCheck(rows)) {
// ...
} else {
IsSymmetric = false;
}
cout << (IsSymmetric ? "Yes" : "No") << endl;
}
3) Your reverse check fails, if a line has leading zeros, because the reverse is not multiplicated by 10 often enough.
bool rev(int n,int len) {
int n1,d,rn=0;
n1=n;
for (int i = 0; i < len; i++)
{
d=n%10;
rn=(rn*10)+d;
n/=10;
}
return n1==rn;
}

String binary combinatorics

Is there a simple way to find all binary strings whose digits add up to a value of x points, assuming that all ones are worth 2 points, and all zeros are worth 1 point. Let me explain:
Considering that I receive a number 5, how could I get all possible strings such that 2*(number of ones) + 1*zeros = 5.
All results for 5 down:
00000
10000
0100
0010
0001
101
110
011
(I do know that the number of possible solutions is the fibonacci number of 5+1 (x+1), but I cannot think of a way to find all values).
I was thinking of adding numbers in binary or maybe using a base converter, but I may be missing something here. Thank you in advance.
By a single loop you can generate base strings (in your case "00000", "0001" and "011") then use std::next_permutation():
for( int zeros = n; zeros >= 0; zeros -= 2 ) {
int ones = ( n - zeros ) / 2;
std::string base = std::string( zeros, '0' ) + std::string( ones, '1' );
}
live example
Try sth like this:
#include <iostream>
#include <string>
#include <vector>
void getSums(int sum, std::vector<std::string>& results, std::string currSum) {
if (0 == sum) {
results.emplace_back(currSum.c_str());
return;
} else if (sum < 0) {
return;
} else {
getSums(sum-2, results, currSum+"1");
getSums(sum-1, results, currSum+"0");
}
}
std::vector<std::string> getAllSums(int sum) {
std::vector<std::string> results;
std::string currSum;
getSums(sum, results, currSum);
return results;
}
int main() {
std::vector<std::string> res = getAllSums(5);
for (std::string& r : res) {
std::cout << r << std::endl;
}
}
Or switch to DP and cache results.

Finding the lexicographically largest rotations in the string

I need to find the Lexicographically largest string out of the given input string.
So if the input is
enjoy
the o/p should be
yenjo
The code i tried was....
int n;
cout<<"Enter the number of strings";
cin>>n;
int len[n];
char str[n][1000];
for(int i=0;i<n;i++)
{
cin>>str[i];
len[i]=strlen(str[i]);
}
int num,pos[n];
for(int i=0;i<n;i++)
{
pos[i]=0;
num=int(str[i][0]);
for(int j=1;j<len[i];j++)
{
if(int(str[i][j])>num)
{
num=int(str[i][j]);
pos[i]=j;
}
}
}
int i,j,k;
char temp[1];
for(i=0;i<n;i++)
{
for(j=0;j<pos[i];j++)
{
temp[0]=str[i][0];
for(k=0;k<len[i];k++)
{
str[i][k]=str[i][k+1];
}
strcat(str[i],temp);
str[i][len[i]]='\0';
}
cout<<str[i]<<"\n";
}
return 0;
}
But this code only ckecks for the largest number and not for the number present next to it and hence fails for the i/p
blowhowler
The o/p should be wlerblowho but i get the o/p as whowlerblo.
How can i keep track of each element that preceeds the largest character so as to get the correct output?
For good performance on the average case (actually, O(N)), but still O^2 on the worst (and always correct), you can keep track of possibilities, and keep eliminating them as you go. Basically something like this.
struct PermSum
{
int sum;
int perm;
}
LinkedList<PermSum> L;
for(int i = 0; i != input.size(); ++i) L.append(PermSum{0,i});
int depth = 0;
int max = 0;
const int length = input.size()
while(L.size() > 1 && depth < length)
{
for(l in L)
{
l.sum += input[(l.perm + depth) % length]
if (l.sum > max) max = l.sum
}
for(l in L)
{
if (l.sum < max) L.delete(l)
}
depth ++;
}
if (L.size() == 1)
return L.front().perm
else
return -1
I got a bit lazy in some parts with the c++ code but I'm sure you can figure out for l in L. The key line is the first for loop. The idea is that its adding the lexicographical value at the depth-th letter of the l.perm-th permutation. In this way, it updates all the possibilities, while simultaneously keeping track of the level of the best possibility. You then do a second pass to delete any possibility falling short of the best. It's worth noting that the way I coded this up, it probably uses the reverse of the standard convention for circular permutations. That is, the perm field in my program represents how many spots LEFT you circular shift, whereas usually positive numbers are circular shifting right. You can fix this with a minus sign somewhere.
As for the running time analysis, it's basically the same argument as Quickselect. Each while loop iteration takes time proportional to the length of L. The first iteration, L will always have length = N (where N is the length of the string, the same as the variable length in the code). The next round, we typically only expect 1/26 of the data to get through, the round after that 1/26 again... so we have N(1 + 1/26 + 2/26^2...) which is O(N).
You can just:
1. generate rotations
2. put all rotations in map<>
3. find last element of the map.
Here is the implementation in C++.
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
int main() {
// your code goes here
string str;int len,i=0,j=0,k=0;char temp;
cin>>str;
len = str.length();
map<string,int>m;
while(i<len)
{
temp = str[0];
while(j<len-1)
{
str[j] = str[j+1];
j++;
}
str[j] = temp;
m[str] = k;
k++;
i++;j=0;
}
str = m.rbegin()->first;
cout<<str;
return 0;
}
The problem can be solved in O(n log n) time by appending the string to itself first and build the suffix array out of it. Find the corresponding entry and there your wanted result. Implementation left as an exercise.
//Here the index with greater value is selected,
//if the same char occurs again the next characters
// of prev and curr characters is checked:-Prev=maxIndex,curr=i
#include<bits/stdc++.h>
using namespace std;
int getIndex(char *str){
int max=INT_MIN,maxIndex;
int n=strlen(str);
int j,p;
for(int i=0;i<n;i++)
{
if(str[i]>max)
{
max=str[i];
maxIndex=i;
}
else if(str[i]==max)
{
j=maxIndex+1;
p=(i+1)%n;
while(j<n && p<n && str[j]==str[p]){
j++;
p=(p+1)%n;
}
maxIndex=str[p]>str[j]?i:maxIndex;
}
}
return maxIndex;
}
int main(void)
{
char str[4000008];
scanf("%s",str);
int i=getIndex(str);
for(int j=i;j<strlen(str);j++)
cout<<str[j];
for(int j=0;j<i;j++)
cout<<str[j];
}
Your algorithm, corrected, comes down to:
Set current best rotation to identity (start of rotated string is current index 0).
For each possible rotation (all other starting indices):
Compare to current-best-rotation with something like wrapcmp below.
Set the current-best-rotation if we had a better candidate.
Time-Complexity: O(n*n)
Space-Complexity: in-place
// Function to do ordinal-comparison on two rotations of a buffer
// buffer: The buffer containing the string
// n: The buffers size (string-length)
// a: Index where the first buffer starts pre-rotation
// b: Index where the second buffer starts pre-rotation
int wrapcmp(const void* buffer, size_t n, size_t a, size_t b) {
auto x = (const unsigned char*)buffer;
auto m = n - std::max(a, b);
int ret = memcmp(x+a, x+b, m);
if(ret) return ret;
auto left = n - m;
a = (a + m) % n;
b = (b + m) % n;
m = left - std::max(a, b);
ret = memcmp(x+a, x+b, m);
if(ret) return ret;
a = (a + m) % n;
b = (b + m) % n;
return memcmp(x+a, x+b, left - m);
}
Used on coliru: http://coliru.stacked-crooked.com/a/4b138a6394483447
Putting it into the general algo left as an exercise for the reader.
This was too tempting so I may as well post my effort. Not sure how it rates efficiency wize. It seems to work as far as I tested it:
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
std::string max_rot(const std::string& s)
{
std::string tmp;
std::string max;
std::string::const_iterator m = std::max_element(s.begin(), s.end());
if(m != s.end())
for(char c = *m; (m = std::find(m, s.end(), c)) != s.end(); ++m)
if(max < tmp.assign(m, s.end()).append(s.begin(), m))
max = tmp;
return max;
}
int main()
{
size_t times = 0;
std::string text;
do { std::cout << "\nHow many words? : "; }
while(std::getline(std::cin, text) && !(std::istringstream(text) >> times));
std::vector<std::string> words;
while(times-- && (std::cin >> text))
words.push_back(text);
for(const auto& s: words)
std::cout << max_rot(s) << '\n';
}
By way of explanation. It finds the highest character value in the string and rotates the string to make that character first. If then looks for duplicate highest characters in the remainder of the string keeping track of the highest attempt. There maybe room for optimization.
This challenge is used in an active contest, I request no answer to be provided till 18th Sep 9 PM IST. Because the code is visible, we might have to ban the user from participating in any of our contests going forward.

Heap's algorithm in C++ repeating?

I am trying to implement Heap's algorithm in C++.
However, the algorithm starts to repeat if the string it's permuting gets to a length of 4. Here's the code:
void permute(int n, string str, int *total,string array[]){
if (n==0){
array[*total] = str;
*total += 1;
}
else{
for(int c=0; c<=n;c++){
permute(n-1,str,total, array);
if (n % 2 == 0){
char tmpstr=str[c];
str[c]=str[n];
str[n]=tmpstr;
}
else{
char tmpstr=str[0];
str[0]=str[n];
str[n]=tmpstr;
}
}
}
}
int main() {
int total = 0;
string array[24];
permute(3,"abcd",&total, array);
cout << total << endl;
return 0;
}
And here is the output. It repeats at the 13th line
24
abcd
bacd
cbad
bcad
cabd
acbd
dbca
bdca
cbda
bcda
cdba
dcba
abcd <-- right here
bacd
cbad
bcad
cabd
acbd
dbca
bdca
cbda
bcda
cdba
dcba
Thank you guys and any help is welcome!
While it is always an excellent idea to use the standard function recommended by PaulMcKenzie, you have posted a code with a question about why it doesn't work.
In your for loop, get rid of the line if (n%2 ==0) and its else part:
for(int c=0; c<=n;c++){
permute(n-1,str,total, array);
char tmpstr=str[c];
str[c]=str[n];
str[n]=tmpstr;
}
It should then work.
It looks like you are trying to implement the recursive version of the Heap's algorithm for permutation generation stated in wikipedia and originally given in here. If you want to stay close to it (for example, to have the same order when generating the permutations), all you have to do is pass the str parameter as a reference (you'll have to change the line calling the permute() function to pass a mutable string instead a string constant, tough) and keep the if-then-else clause originally in your program.
Nevertheless, it is interesting the version given by #Christophe. I've tried it with up to n=6 (permutations of 7 elements), and still give all permutations. It'd be interesting to know if this can be proved to hold for any natural number. This point may be moot, however, since the recursive version given in the two references I cited does not implement the original version given by Heap, either, and, as far as I know, hasn't been proved to give all permutations either. The original version given by Heap, written in 1963, did not even use structured programming. It was given as a flowgraph to be implemented with goto's.
Here, have my implementations of recursive and iterative versions:
//recursive
int perm_num = 0;
void heappermute(int v[], int n) {
int i;
if (n == 1) {
//print(v);
++perm_num;
}
else {
for (i = 0; i < n; i++) {
heappermute(v, n - 1);
if (n % 2 == 1) {
swap(&v[0], &v[n - 1]);
}
else {
swap(&v[i], &v[n - 1]);
}
}
}
}
int perm_num_iter = 0;
void heappermuteiterative(int v[], int n) {
int c[30];
for (int i = 0; i <= n; ++i) {
c[i] = 0;
}
++perm_num_iter;
//print(v);
int i = 1;
while (i < n) {
if (c[i] < i) {
if (i % 2 == 0) {
swap(&v[0], &v[i]); // or i-1
}
else {
swap(&v[c[i]], &v[i]); // or i-1
}
++perm_num_iter;
//print(v);
++c[i];
i = 1;
}
else {
c[i] = 0;
++i;
}
}
}
I copied the recursive one from somewhere on the net, and the iterative one is the Wikipedia's one written in C.

Closest Palindrome Number

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);