I am trying to solve a problem that it want the program to output the result of n^84601. (n=0,1,...,10)
Therefore, I try to solve it by using big integer, and it works well in small number, but segfault in bigger ones.
#include <stdlib.h>
#include <iostream>
using namespace std;
const int MX = 100000;
struct BigInt {
int ar[MX];
int len;
BigInt(int n) {
int i = 0;
while (n != 0) {
ar[i] = n % 10;
n /= 10;
i++;
}
len = i;
}
BigInt times(BigInt x) {
BigInt tmp(0);
for (int i = 0; i < len; i++) {
for (int j = 0; j < x.len; j++) {
int r = ar[i] * x.ar[j] + tmp.ar[i + j];
tmp.ar[i + j] = r % 10;
tmp.ar[i + j + 1] += r / 10;
}
}
for (int i = min(len + x.len, MX - 1);; i--) {
if (tmp.ar[i] != 0) {
tmp.len = i + 1;
break;
}
}
return tmp;
}
void print() {
for (int i = len - 1; i >= 0; i--) {
cout << ar[i];
}
cout << endl;
}
};
BigInt poww(BigInt a, int n) {
if (n == 1) {
return a;
}
BigInt x = poww(a, n / 2);
BigInt y = x.times(x);
if (n % 2 == 1) {
y = y.times(a);
}
return y;
}
int main(void) {
ios::sync_with_stdio(false);
int n;
while (cin >> n) {
if (n == 0)
cout << 0 << endl;
else if (n == 1)
cout << 1 << endl;
else
poww(BigInt(n), 86401).print();
}
return 0;
}
When I change the MX in to 10000 and 86401 into 864, it can correctly caculate 2^864. But it will segfault with 2^86401.
You have a stack overflow.
Your BigInt object is quite large: it contains 100001 ints, which is usually 400,004 bytes.
You allocate several of these on the stack (some are unnecessary: you should really pass arguments by const reference).
You have recursion.
A typical stack size limit is 8MB.
Combine above statements together, and you can see that you can have at most 20 BigInts on the stack at one time. Your recursion depth is at least 17, so creating more than one BigInt on the stack for each recursive call is guaranteed to fail.
There are a few solutions:
use more efficient encoding -- currently you are using int to hold one digit, unsigned char would be more appropriate
allocate space for digits on heap instead of on the stack. If you do that, be aware of the rule of five.
I'm trying to print the numbers from 1 to N in lexicographic order, but I get a failed output. for the following input 100, I get the 100, but its shifted and it doesn't match with the expected output, there is a bug in my code but I can not retrace it.
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> result;
for(int i = 1; i <= 9; i ++){
int j = 1;
while( j <= n){
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
j *= 10;
}
}
return result;
}
};
Input:
100
Output:
[1,10,11,12,13,14,15,16,17,18,19,100,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47,48,49,5,50,51,52,53,54,55,56,57,58,59,6,60,61,62,63,64,65,66,67,68,69,7,70,71,72,73,74,75,76,77,78,79,8,80,81,82,83,84,85,86,87,88,89,9,90,91,92,93,94,95,96,97,98,99]
Expected:
[1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47
Think about when i=1,j=10 what will happen in
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
Yes,result will push_back 10(0+10*1),11(1+10*1),12(2+10*1)..
Here is a solution:
#include <iostream>
#include <vector>
#include <string>
std::vector<int> fun(int n)
{
std::vector<std::string> result;
for (int i = 1; i <= n; ++i) {
result.push_back(std::to_string(i));
}
std::sort(result.begin(),result.end());
std::vector<int> ret;
for (auto i : result) {
ret.push_back(std::stoi(i));
}
return ret;
}
int main(int argc, char *argv[])
{
std::vector<int> result = fun(100);
for (auto i : result) {
std::cout << i << ",";
}
std::cout << std::endl;
return 0;
}
You are looping through all 2 digit numbers starting with 1 before outputting the first 3 digit number, so your approach won't work.
One way to do this is to output the digits in base 11, padded out with leading spaces to the maximum number of digits, in this case 3. Output 0 as a space, 1 as 0, 2 as 1 etc. Reject any numbers that have any non-trailing spaces in this representation, or are greater than n when interpreted as a base 10 number. It should be possible to jump past multiple rejects at once, but that's an unnecessary optimization. Keep a count of the numbers you have output and stop when it reaches n. This will give you a lexicographical ordering in base 10.
Example implementation that uses O(1) space, where you don't have to generate and sort all the numbers up front before you can output the first one:
void oneToNLexicographical(int n)
{
if(n < 1) return;
// count max digits
int digits = 1, m = n, max_digit11 = 1, max_digit10 = 1;
while(m >= 10)
{
m /= 10; digits++; max_digit11 *= 11; max_digit10 *= 10;
}
int count = 0;
bool found_n = false;
// count up starting from max_digit * 2 (first valid value with no leading spaces)
for(int i = max_digit11 * 2; ; i++)
{
int val = 0, trailing_spaces = 0;
int place_val11 = max_digit11, place_val10 = max_digit10;
// bool valid_spaces = true;
for(int d = 0; d < digits; d++)
{
int base11digit = (i / place_val11) % 11;
if(base11digit == 0)
{
trailing_spaces++;
val /= 10;
}
else
{
// if we got a non-space after a space, it's invalid
// if(trailing_spaces > 0)
// {
// valid_spaces = false;
// break; // trailing spaces only
// }
val += (base11digit - 1) * place_val10;
}
place_val11 /= 11;
place_val10 /= 10;
}
// if(valid_spaces && (val <= n))
{
cout << val << ", ";
count++;
}
if(val == n)
{
found_n = true;
i += 10 - (i % 11); // skip to next number with one trailing space
}
// skip past invalid numbers:
// if there are multiple trailing spaces then the next run of numbers will have spaces in the middle - invalid
if(trailing_spaces > 1)
i += (int)pow(11, trailing_spaces - 1) - 1;
// if we have already output the max number, then all remaining numbers
// with the max number of digits will be greater than n
else if(found_n && (trailing_spaces == 1))
i += 10;
if(count == n)
break;
}
}
This skips past all invalid numbers, so it's not necessary to test valid_spaces before outputting each.
The inner loop can be removed by doing the base11 -> base 10 conversion using differences, making the algorithm O(N) - the inner while loop tends towards a constant:
int val = max_digit10;
for(int i = max_digit11 * 2; ; i++)
{
int trailing_spaces = 0, pow11 = 1, pow10 = 1;
int j = i;
while((j % 11) == 0)
{
trailing_spaces++;
pow11 *= 11;
pow10 *= 10;
j /= 11;
}
int output_val = val / pow10;
if(output_val <= n)
{
cout << output_val << ", ";
count++;
}
if(output_val == n)
found_n = true;
if(trailing_spaces > 1)
{
i += (pow11 / 11) - 1;
}
else if(found_n && (trailing_spaces == 1))
{
i += 10;
val += 10;
}
else if(trailing_spaces == 0)
val++;
if(count == n)
break;
}
Demonstration
The alternative, simpler approach is just to generate N strings from the numbers and sort them.
Maybe more general solution?
#include <vector>
#include <algorithm>
using namespace std;
// returns true is i1 < i2 according to lexical order
bool lexicalLess(int i1, int i2)
{
int base1 = 1;
int base2 = 1;
for (int c = i1/10; c > 0; c/=10) base1 *= 10;
for (int c = i2/10; c > 0; c/=10) base2 *= 10;
while (base1 > 0 && base2 > 0) {
int d1 = i1 / base1;
int d2 = i2 / base2;
if (d1 != d2) return (d1 < d2);
i1 %= base1;
i2 %= base2;
base1 /= 10;
base2 /= 10;
}
return (base1 < base2);
}
vector<int> lexicalOrder(int n) {
vector<int> result;
for (int i = 1; i <= n; ++i) result.push_back(i);
sort(result.begin(), result.end(), lexicalLess);
return result;
}
The other idea for lexicalLess(...) is to convert integers to string before comparision:
#include <vector>
#include <algorithm>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;
// returns true is i1 < i2 according to lexical order
bool lexicalLess(int i1, int i2)
{
string s1 = boost::lexical_cast<string>(i1);
string s2 = boost::lexical_cast<string>(i2);
return (s1 , s2);
}
You need Boost to run the second version.
An easy one to implement is to convert numbers to string, them sort the array of strings with std::sort in algorithm header, that sorts strings in lexicographical order, then again turn numbers to integer
Make a vector of integers you want to sort lexicographically, name it numbers.
Make an other vector and populate it strings of numbers in the first vector. name it strs.
Sort strs array.4. Convert strings of strs vector to integers and put it in vectors
List item
#include <cstdlib>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
string int_to_string(int x){
string ret;
while(x > 0){
ret.push_back('0' + x % 10);
x /= 10;
}
reverse(ret.begin(), ret.end());
return ret;
}
int main(){
vector<int> ints;
ints.push_back(1);
ints.push_back(2);
ints.push_back(100);
vector<string> strs;
for(int i = 0; i < ints.size(); i++){
strs.push_back(int_to_string((ints[i])));
}
sort(strs.begin(), strs.end());
vector<int> sorted_ints;
for(int i = 0; i < strs.size(); i++){
sorted_ints.push_back(atoi(strs[i].c_str()));
}
for(int i = 0; i < sorted_ints.size(); i++){
cout<<sorted_ints[i]<<endl;
}
}
As the numbers are unique from 1 to n, you can use a set of size n and insert all of them into it and then print them out.
set will automatically keep them sorted in lexicographical order if you store the numbers as a string.
Here is the code, short and simple:
void lexicographicalOrder(int n){
set<string> ans;
for(int i = 1; i <= n; i++)
ans.insert(to_string(i));
for(auto ele : ans)
cout <<ele <<"\n";
}
Can anyone explain me the dynamic algorithm, that finds number of subsets with sum equal to k.
I searched in Google, but cant find any simple explanation! Sorry for my English!
Here is the code:
int numbers[MAX];
int GetmNumberOfSubsets()
{
int dp[MAX];
dp[0] = 1;
int currentSum = 0;
for (int i = 0; i < numbers.length; i++)
{
currentSum += numbers[i];
for (int j = min(sum, currentSum); j >= numbers[i]; j--)
dp[j] += dp[j - numbers[i]];
}
return dp[sum];
}
Your DP solution should be 2-dimensional, 1 dimension for the sum, and 1 dimension for the number of elements.
The recursive formula defining this solution is:
DP(x,i) = 0 x < 0
DP(0,i) = 1
DP(x,0) = 0 x > 0
DP(x,i) = DP(x-numbers[i],i-1) + DP(x,i-1)
And it should be something like:
int dp[MAX+1][sum+1];
int i, x;
for (i = 0; i < MAX+1; i++) {
dp[i][0] = 1;
}
for (x = 1; x < sum+1; x++) {
dp[0][x] = 0
}
for (i = 1; i < MAX+1; i++) {
for (x = 1; x < sum+1; x++) {
dp[i][x] = dp[i-1][x];
if (x >= numbers[i])
dp[i][x] += dp[i][x-numbers[i]];
}
}
return dp[MAX][sum];
(Hope I didn't have minor issues, didn't test it - but it should give you idea how to implement it once recursive formulas are clear)
You can use the following example to find the number of subsets with sum equal to k:
#include <iostream>
using std::cout;
using std::cin;
int count = 0,K;
void noofsubsets(int arr[], int sum, int N){
if(N==0){
if(sum==K)
count++;
return;
}
noofsubsets(arr, sum, N-1);
noofsubsets(arr, sum+arr[N-1], N-1);
}
here is a solution using recursion ...
considering two cases
i) Including first element of an array.
ii) without first array element.
`
def subSetsSumK(arr, v, k) :
if (k == 0) :
for value in v :
print(value, end=" ")
print()
return
if (len(arr)== 0):
return
si=0
v1 = [] + v
v1.append(arr[si])
subSetsSumK(arr[1:], v1, k - arr[si])
subSetsSumK(arr[1:], v, k)
def subSetsSumK(arr, k):
v = []
subSetsSumK(arr,v, k)
# Driver code
arr = [ 2,1,3,2 ]
k_sum = 4
subSetsSumK(arr,k)
I'm writing a program that adds two large integers (up to 20 digits) together. I've had no problems so far in storing the two numbers as strings then sorting them into two arrays.
So far, I have half of the addition part working. When the sum of the two digits does not exceed double digits, it works fine.
The issue arises when the sum of the arrays hits double digits. I'm trying to work in the carry over, but it messes with the digits (adding in where it shouldn't.) In addition to that, I'm not sure how to get the carry to appear ahead of the final digits. For example: 9+9 outputs to 8.
Here's my code (please excuse all the letter variables in the for loops.)
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1;
string str2;
int array1[20];
int array2[20];
int array3[20];
string num3[20];
int i;
int j = 0;
int k;
int l;
int m = 0;
int n;
int o;
int carry = 0;
cout<<"Please enter the first number: "<<endl;
cin>>str1;
for (int i = str1.length() - 1; i >= 0; i--)
{
array1[j] = str1[i];
j++;
}
for (int k = str1.length()-1; k >=0; k--)
{
array1[k] = static_cast<int>(str1[k]) - static_cast<int>('0');
}
cout<<"Please enter the second number: "<<endl;
cin>>str2;
for (int l = str2.length() - 1; l >= 0; l--)
{
array2[m] = str2[l];
m++;
}
for (int n = str2.length()-1; n >=0; n--)
{
array2[n] = static_cast<int>(str2[n]) - static_cast<int>('0');
}
//Where the addition begins
for (int o = 0; o < str1.length(); o++)
{
if (array1[o] + array2[o] > 9)
{
array3[o] = array1[o] + array2[o] + carry;
array3[o] = array3[o] % 10;
carry = 1;
}
else
{
array3[o] = array1[o] + array2[o] + carry;
carry = 0;
}
cout<<array3[o];
}
return 0;
}
I think one thing I have to fix is how this line of code works:
array3[o] = array3[o] % 10;
Which keeps a second digit from appearing in the output. I would imagine if I disabled it once we reach the final numbers in the arrays, it would allow the final carry to show up. Unfortunately, everything I've tried hasn't worked.
Again, thank you!
Try this:
for (int o = 0; o < str1.length(); o++)
{
if (array1[o] + array2[o] + carry > 9)
{
array3[o] = array1[o] + array2[o] + carry;
array3[o] = array3[o] % 10;
carry = 1;
}
else
{
array3[o] = array1[o] + array2[o] + carry;
carry = 0;
}
cout<<array3[o];
}
Modify your for loop for Addition. In condition you need to add carry also
if (array1[o] + array2[o] + carry > 9)
The final for loop will be as below:
for (int o = 0; o < str1.length(); o++)
{
if (array1[o] + array2[o] + carry > 9)
{
array3[o] = array1[o] + array2[o] + carry;
array3[o] = array3[o] % 10;
carry = 1;
}
else
{
array3[o] = array1[o] + array2[o] + carry;
carry = 0;
}
cout<<array3[o];
}
My suggestions:
You can fill up the numbers from the input string in one loop. No need to use two loops.
for (int i = str1.length() - 1; i >= 0; i--)
{
array1[j] = str1[i] - '0';
j++;
}
Similarly for the other loop.
When computing the total you have iterate until the length of the longest string. If the first input is 12 and the second input is 4567, you have to make sure that your iteration stops at 4, not at 2.
The algorithm for computing the sum can be simplified to:
for (int o = 0; o < len+1; o++)
{
array3[o] = array1[o] + array2[o] + carry;
carry = array3[o]/10;
array3[o] %= 10;
}
where len is the maximum of the lengths.
Here's the final code I came up with:
#include <iostream>
#include <string>
using namespace std;
void printNumber(int array[])
{
// Skip the leading zeros.
int i = 19;
for ( ; i >= 0; i-- )
{
if ( array[i] > 0 )
{
break;
}
}
for ( ; i >= 0; i--)
{
cout << array[i];
}
}
int main()
{
string str1;
string str2;
int array1[20] = {0};
int array2[20] = {0};
int array3[20] = {0};
int i;
int j = 0;
int k;
int l;
int m = 0;
int n;
int o;
int carry = 0;
int len = 0;
cout<<"Please enter the first number: "<<endl;
cin>>str1;
len = str1.length();
for (int i = str1.length() - 1; i >= 0; i--)
{
array1[j] = str1[i] - '0';
j++;
}
cout<<"Please enter the second number: "<<endl;
cin>>str2;
if ( len < str2.length() )
{
len = str2.length();
}
for (int l = str2.length() - 1; l >= 0; l--)
{
array2[m] = str2[l] - '0';
m++;
}
//Where the addition begins
for (int o = 0; o < len+1; o++)
{
array3[o] = array1[o] + array2[o] + carry;
carry = array3[o]/10;
array3[o] %= 10;
}
// Print the result.
printNumber(array3);
cout << endl;
return 0;
}
int main()
{
char A[20],B[20],C[22]={0};
int carry,len_a,len_b,x=20,i,j,a,b;
printf("First Number");
gets(A);
printf("Second Number");
gets(B);
len_a=strlen(A);
len_b=strlen(B);
for(i=len_a-1;i>=0;i--)
{
carry=0;
b=(int)B[i]-48;
a=(int)A[len_b-1]-48;
C[x]=C[x]+a+b;
if(C[x]>9)
{
C[x]=C[x]%10;
C[x-1]+=1;
}
x--;
len_b--;
}
int flag=0;
printf("Result :");
for(j=0;j<=20;j++)
{
if(C[j]!=0)
{
printf("%d",C[j]);
flag=1;
}
else if(C[j]==0 && flag==1)
printf("%d",C[j]);
}
if(flag==0)
printf("0");
getch();
return 0;
}
If I were you, would do exactly what I have done here:
inline bigint &bigint::operator+( const bigint & _expr )
{
vector<uint8_t> left = this->_digits;
vector<uint8_t> right = _expr._digits;
vector<uint8_t> sum;
uint8_t carry = 0;
process_operands( left, right ); // makes the two operands have the same length and fills them with leading zeros
for( auto lit = left.cbegin(), rit = right.cbegin(); lit != left.cend(), rit != right.cend(); ++lit, ++rit )
{
uint8_t temp_sum = ( *lit + *rit + carry ) % 10;
carry = ( *lit + *rit + carry ) / 10;
sum.push_back( temp_sum );
}
if( carry ) sum.push_back( carry );
this->_digits = sum;
return *this;
}
To make things look a little bit more clear:
bigint is my class for big integers, and looks something like this:
class bigint
{
private:
vector<uint8_t> _digits;
typedef vector<uint8_t>::size_type size_type;
bigint( vector<uint8_t> & in );
public:
bigint() : _digits() {}
bigint( const string &number );
// ...
};
So you should actually stop using the built-in arrays, since they are error-prone, and because we have better things offered by STL, like std::vector. I am using std::vector<uint8_t> to store the digits of my number, and so, it becomes easier to cycle through the digits: we can use either the range for (for(uint8_t & c : _digits) { }) or the iterators.
Attaching the leading zeros will become easier, since you ony have to do:
_digits.push_back( 0 );
in a for loop.