splitting a number and storing in int array - c++

Is there a way to split a number and store digits in an int array?
I am looking for a way to remove some digits from a number (for a divisible algorithm proof).
for example, if I have a number 12345, I need to perform this operation:
1234 - 5 = 1229
Is there a way to do this?

Use n % 10 to get the last digit and n / 10 to get the others. For example, 5=12345%10, 1234=12345/10.
Convert integer to array:
int array[6];
int n = 123456;
for (int i = 5; i >= 0; i--) {
array[i] = n % 10;
n /= 10;
}
In general, vectors are preferred in C++, especially in this case since you probably don't know in advance the number of digits.
int n = 123456;
vector<int> v;
for(; n; n/=10)
v.push_back( n%10 );
Then v contains {6,5,4,3,2,1}. You may optionally use std::reverse to reverse it.

I am going to give you an answer in sudo code.
int [] makeArrayFromInt (int input){
arr = new int [floor(log(input)/log(10)) + 1]
int index = 0
while(input>0){
arr[index]=input%10
input=input/10
index++
}
return arr
}
The basic idea is to use mod 10 to get the value in a particular digits place and divide by 10 to get to the next digit. Repeat this process until dividing by 10 gives you zero, as this is when you have reached the end of your number. Floor(log(input)/log(10)) + 1 is a trick to find out how many digits a number possesses.

Related

Can someone please explain this bit manipulation code to me?

I am new to competitive programming. I recently gave the Div 3 contest codeforces. Eventhough I solved the problem C, I really found this code from one of the top programmers really interesting. I have been trying to really understand his code, but it seems like I am too much of a beginner to understand it without someone else explaining it to me.
Here is the code.
void main(){
int S;
cin >> S;
int ans = 1e9;
for (int mask = 0; mask < 1 << 9; mask++) {
int sum = 0;
string num;
for (int i = 0; i < 9; i++)
if (mask >> i & 1) {
sum += i + 1;
num += char('0' + (i + 1));
}
if (sum != S)
continue;
ans = min(ans, stoi(num));
}
cout << ans << '\n';
}
The problem is to find the minimum number whose sum of digits is equal to given number S, such that every digit in the result is unique.
Eq. S = 20,
Ans = 389 (3+8+9 = 20)
Mask is 9-bits long, each bit represents a digit from 1-9. Thus it counts from 0 and stops at 512. Each value in that number corresponds to possible solution. Find every solution that sums to the proper value, and remember the smallest one of them.
For example, if mask is 235, in binary it is
011101011 // bit representation of 235
987654321 // corresponding digit
==> 124678 // number for this example: "digits" with a 1-bit above
// and with lowest digits to the left
There are a few observations:
you want the smallest digits in the most significant places in the result, so a 1 will always come before any larger digit.
there is no need for a zero in the answer; it doesn't affect the sum and only makes the result larger
This loop converts the bits into the corresponding digit, and applies that digit to the sum and to the "num" which is what it'll print for output.
for (int i = 0; i < 9; i++)
if (mask >> i & 1) { // check bit i in the mask
sum += i + 1; // numeric sum
num += char('0' + (i + 1)); // output as a string
}
(mask >> i) ensures the ith bit is now shifted to the first place, and then & 1 removes every bit except the first one. The result is either 0 or 1, and it's the value of the ith bit.
The num could have been accumulated in an int instead of a string (initialized to 0, then for each digit: multiply by 10, then add the digit), which is more efficient, but they didn't.
The way to understand what a snippet of code is doing is to A) understand what it does at a macro-level, which you have done and B) go through each line and understand what it does, then C) work your way backward and forward from what you know, gaining progress a bit at a time. Let me show you what I mean using your example.
Let's start by seeing, broadly (top-down) what the code is doing:
void main(){
// Set up some initial state
int S;
cin >> S;
int ans = 1e9;
// Create a mask, that's neat, we'll look at this later.
for (int mask = 0; mask < 1 << 9; mask++) {
// Loop state
int sum = 0;
string num;
// This loop seems to come up with candidate sums, somehow.
for (int i = 0; i < 9; i++)
if (mask >> i & 1) {
sum += i + 1;
num += char('0' + (i + 1));
}
// Stop if the sum we've found isn't the target
if (sum != S)
continue;
// Keep track of the smallest value we've seen so far
ans = min(ans, stoi(num));
}
// Print out the smallest value
cout << ans << '\n';
}
So, going from what we knew about the function at a macro level, we've found that there are really only two spots that are obscure, the two loops. (If anything outside of those are confusing to you, please clarify.)
So now let's try going bottom-up, line-by-line those loops.
// The number 9 appears often, it's probably meant to represent the digits 1-9
// The syntax 1 << 9 means 1 bitshifted 9 times.
// Each bitshift is a multiplication by 2.
// So this is equal to 1 * (2^9) or 512.
// Mask will be 9 bits long, and each combination of bits will be covered.
for (int mask = 0; mask < 1 << 9; mask++) {
// Here's that number 9 again.
// This time, we're looping from 0 to 8.
for (int i = 0; i < 9; i++) {
// The syntax mask >> i shifts mask down by i bits.
// This is like dividing mask by 2^i.
// The syntax & 1 means get just the lowest bit.
// Together, this returns true if mask's ith bit is 1, false if it's 0.
if (mask >> i & 1) {
// sum is the value of summing the digits together
// So the mask seems to be telling us which digits to use.
sum += i + 1;
// num is the string representation of the number whose sum we're finding.
// '0'+(i+1) is a way to convert numbers 1-9 into characters '1'-'9'.
num += char('0' + (i + 1));
}
}
}
Now we know what the code is doing, but it's hard to figure out. Now we have to meet in the middle - combine our overall understanding of what the code does with the low-level understanding of the specific lines of code.
We know that this code gives up after 9 digits. Why? Because there are only 9 unique non-zero values (1,2,3,4,5,6,7,8,9). The problem said they have to be unique.
Where's zero? Zero doesn't contribute. A number like 209 will always be smaller than its counterpart without the zero, 92 or 29. So we just don't even look at zero.
We also know that this code doesn't care about order. If digit 2 is in the number, it's always before digit 5. In other words, the code doesn't ever look at the number 52, only 25. Why? Because the smallest anagram number (numbers with the same digits in a different order) will always start with the smallest digit, then the second smallest, etc.
So, putting this all together:
void main(){
// Read in the target sum S
int S;
cin >> S;
// Set ans to be a value that's higher than anything possible
// Because the largest number with unique digits is 987654321.
int ans = 1e9;
// Go through each combination of digits, from 1 to 9.
for (int mask = 0; mask < 1 << 9; mask++) {
int sum = 0;
string num;
for (int i = 0; i < 9; i++)
// If this combination includes the digit i+1,
// Then add it to the sum, and append to the string representation.
if (mask >> i & 1) {
sum += i + 1;
num += char('0' + (i + 1));
}
// If this combination does not yield the right sum, try the next combination.
if (sum != S)
continue;
// If this combination does yield the right sum,
// see if it's smaller than our previous smallest.
ans = min(ans, stoi(num));
}
// Print the smallest combination we found.
cout << ans << '\n';
}
I hope this helps!
The for loop is iterating over all 9-digit binary numbers and turning those binary numbers into a string of decimal digits such that if nth binary digit is on then a n+1 digit is appended to the decimal number.
Generating the numbers this way ensures that the digits are unique and that zero never appears.
But as #Welbog mentions in comments this solution to the problem is way more complicated than it needs to be. The following will be an order of magnitude faster, and I think is clearer:
int smallest_number_with_unique_digits_summing_to_s(int s) {
int tens = 1;
int answer = 0;
for (int n = 9; n > 0 && s > 0; --n) {
if (s >= n) {
answer += n * tens;
tens *= 10;
s -= n;
}
}
return answer;
}
Just a quick way to on how code works.
First you need to know sum of which digits equal to S. Since each digit is unique, you can assign a bit to them in a binary number like this:
Bit number Digit
0 1
1 2
2 3
...
8 9
So you can check all numbers that are less than 1 << 9 (numbers with 9 bits corresponding 1 to 9) and check if sum of bits if equal to your sum based on their value. So for example if we assume S=17:
384 -> 1 1000 0000 -> bit 8 = digit 9 and bit 7 = digit 8 -> sum of digits = 8+9=17
Now that you know sum if correct, you can just create number based on digits you found.

Minimum Possible Integer After at Most K Adjacent Swaps On Digits

Given a string num representing the digits of a very large integer and an integer k.
You are allowed to swap any two adjacent digits of the integer at most k times.
Return the minimum integer you can obtain also as a string.
Example 1:
Input: num = "4321", k = 4
Output: "1342"
Explanation: The steps to obtain the minimum integer from 4321 with 4 adjacent swaps are shown.
Input: num = "36789", k = 1000
Output: "36789"
Explanation: We can keep the number without any swaps.
Example 4:
Constraints:
1 <= num.length <= 30000
num contains digits only and doesn't have leading zeros.
1 <= k <= 10^9
Here, is the code
class Solution {
public:
string minInteger(string num, int k) {
int n=num.length();
string min=num;
if (min.compare(num)>0)
min=num;
if (k<1)
return 0;
for (int i=0;i<n-1;i++){
for (int j=i+1;j<n;j++){
if (num[i]>num[j]){
swap(num[i],num[j]);
minInteger(num,k-1,min);
swap(num[i],num[j]);
}
}
}
return min;
}
};
My output ,
Input: num = "4321", k = 4
Output: "1234"
So,basically its returning a string with ascending order of digits which is not desired .
How am I supposed to correct this ?
Problem statement says you can swap only adjacent digits while you try to swap arbitrary two digits in your code.
Instead of those two loops you should have just one that tries to swap digits at position i and i+1.
I think you should just use one loop to swap adjacent digits. In your code you are swapping any two digits. Maybe something like this:
for(int i = 0; i < n-1; ++i) {
if(num[i+1] < num[i]){
swap(num[i+1], num[i]);
// do your stuff
swap(num[i+1], num[i]);
}
}
I hope it helps.

Given number N eliminate K digits to get maximum possible number

As the title says, the task is:
Given number N eliminate K digits to get maximum possible number. The digits must remain at their positions.
Example: n = 12345, k = 3, max = 45 (first three digits eliminated and digits mustn't be moved to another position).
Any idea how to solve this?
(It's not homework, I am preparing for an algorithm contest and solve problems on online judges.)
1 <= N <= 2^60, 1 <= K <= 20.
Edit: Here is my solution. It's working :)
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
string n;
int k;
cin >> n >> k;
int b = n.size() - k - 1;
int c = n.size() - b;
int ind = 0;
vector<char> res;
char max = n.at(0);
for (int i=0; i<n.size() && res.size() < n.size()-k; i++) {
max = n.at(i);
ind = i;
for (int j=i; j<i+c; j++) {
if (n.at(j) > max) {
max = n.at(j);
ind = j;
}
}
b--;
c = n.size() - 1 - ind - b;
res.push_back(max);
i = ind;
}
for (int i=0; i<res.size(); i++)
cout << res.at(i);
cout << endl;
return 0;
}
Brute force should be fast enough for your restrictions: n will have max 19 digits. Generate all positive integers with numDigits(n) bits. If k bits are set, then remove the digits at positions corresponding to the set bits. Compare the result with the global optimum and update if needed.
Complexity: O(2^log n * log n). While this may seem like a lot and the same thing as O(n) asymptotically, it's going to be much faster in practice, because the logarithm in O(2^log n * log n) is a base 10 logarithm, which will give a much smaller value (1 + log base 10 of n gives you the number of digits of n).
You can avoid the log n factor by generating combinations of n taken n - k at a time and building the number made up of the chosen n - k positions as you generate each combination (pass it as a parameter). This basically means you solve the similar problem: given n, pick n - k digits in order such that the resulting number is maximum).
Note: there is a method to solve this that does not involve brute force, but I wanted to show the OP this solution as well, since he asked how it could be brute forced in the comments. For the optimal method, investigate what would happen if we built our number digit by digit from left to right, and, for each digit d, we would remove all currently selected digits that are smaller than it. When can we remove them and when can't we?
In the leftmost k+1 digits, find the largest one (let us say it is located at ith location. In case there are multiple occurrences choose the leftmost one). Keep it. Repeat the algorithm for k_new = k-i+1, newNumber = i+1 to n digits of the original number.
Eg. k=5 and number = 7454982641
First k+1 digits: 745498
Best number is 9 and it is located at location i=5.
new_k=1, new number = 82641
First k+1 digits: 82
Best number is 8 and it is located at i=1.
new_k=1, new number = 2641
First k+1 digits: 26
Best number is 6 and it is located at i=2
new_k=0, new number = 41
Answer: 98641
Complexity is O(n) where n is the size of the input number.
Edit: As iVlad mentioned, in the worst case complexity can be quadratic. You can avoid that by maintaining a heap of size at most k+1 which will increase complexity to O(nlogk).
Following may help:
void removeNumb(std::vector<int>& v, int k)
{
if (k == 0) { return; }
if (k >= v.size()) {
v.clear();
return;
}
for (int i = 0; i != v.size() - 1; )
{
if (v[i] < v[i + 1]) {
v.erase(v.begin() + i);
if (--k == 0) { return; }
i = std::max(i - 1, 0);
} else {
++i;
}
}
v.resize(v.size() - k);
}

Generate a random number with no repeating digits?

I'd like to generate a random number with each digit being in range from 0-9 and not repeating itself. Assume finite length of 4.
1234 qualifies, each composite digit is unique.
1123 does not, 1 is repeated
How can this be done please?
To generate the digits:
std::vector<int> vec = {0,1,2,3,4,5,6,7,8,9}; // or initialize from array if not c++11
std::random_shuffle(vec.begin(), vec.end());
vec.resize(4);
And to join the digits into a single number:
int number = 0;
for (auto i = vec.begin(); i != vec.end(); ++i) {
number = 10 * number + (*i);
}
I believe you are talking about generating permutations.
Try something like this:
int used[10] = {0};
int n = 0;
int number = 0;
while( n < 10 ) {
int d = rand() % 10;
if( used[d] ) continue;
used[d] = 1;
number = number * 10 + d;
n++;
}
Not the most efficient... It simply tracks what digits have been used, and rerolls any time a used digit is encountered.
The above does have the side-effect that zero is technically not used if it's the first number chosen. You could explicitly prevent this, or simply accept that some numbers will be 9 digits long.
If you'd rather avoid needless use of std::vector and the memory allocations it brings, excessive randomisation calls presumably used within random_shuffle, there's a simpler approach if you play with some math.
If you can count how many valid (i.e. acceptable) sequences exist, C, and you can devise a bijective function that maps from this counter to each valid sequence instance then things become trivial. Generate a random integer in the range [0,C), plug that into your function which returns the valid output.
If I understand your example correctly, you want to generate a random 4 digit sequence ABCD (representing an integer in the range [0,9999]) where digits A, B, C and D are different from one another.
There are 5040 such valid sequences: 10 * 9 * 8 * 7.
Given any integer in the range [0, 5039], the following function will return a valid sequence (i.e. one in which each digit is unique), represented as an integer:
int counter2sequence(int u) {
int m = u/504;
u %= 504;
int h = u/56;
u %= 56;
int t = u/7;
u %= 7;
const int ih = h;
const int it = t;
if (ih >= m) ++h;
if (it >= ih) ++t;
if (t >= m) ++t;
if (u >= it) ++u;
if (u >= ih) ++u;
if (u >= m) ++u;
return ((m*10 + h)*10 + t)*10 + u;
}
E.g.
counter2sequence(0) => 0123
counter2sequence(5039) => 9876

Convert integer to array

I would like to convert an integer into an array, so that it looks like the following:
int number = 123456 ;
int array[7] ;
with the result:
array[0] = 1
array[1] = 2
...
array[6] = 6
Perhaps a better solution is to work backwards:
123456 % 10 = 6
123456 / 10 = 12345
12345 % 10 = 5
12345 / 10 = 1234
just use modular arithmetic:
int array[6];
int number = 123456;
for (int i = 5; i >= 0; i--) {
array[i] = number % 10;
number /= 10;
}
You can extract the last digit of the number this way:
int digit = number % 10;
number /= 10;
Note that you should also check whether number is positive. Other values require additional handling.
Here what I came up with, the integerToArray function returns a vector that is converted from the integer value. you can test it with the main function as well:
#include <iostream>
#include <vector>
using namespace std;
vector <int> integerToArray(int x)
{
vector <int> resultArray;
while (true)
{
resultArray.insert(resultArray.begin(), x%10);
x /= 10;
if(x == 0)
return resultArray;
}
}
int main()
{
vector <int> temp = integerToArray(1234567);
for (auto const &element : temp)
cout << element << " " ;
return 0;
}
//outputs 1 2 3 4 5 6 7
Take the log10 of the number to get the number of digits. Put that in, say pos, then, in a loop, take the modulo of 10 (n % 10), put the result in the array at position pos. Decrement pos and divide the number by 10. Repeat until pos == 0
What did you want to do with the sign if it's negative?
#include <cmath>
#include <vector>
std::vector<int> vec;
for (int i = log10(input); i >= 0; i--)
{
vec.push_back(input / int(std::pow(10, i)) % 10);
}
Might be a good approach, I think
The easiest way I can imagine now is:
char array[40];
int number = 123456;
memset(array, 0x00, sizeof(array));
sprintf(array, "%d", number);
Additionally you can convert each digit to int just subtracting the char value by 0x30.
EDIT: If this is a homework, your teacher you probably ask you to write the program using % operator though (example 12 % 10 = 2). If this is the case, good homework ;-)
You can use modulus to determine the last digit.
And you can use division to move another digit to the last digit's place.
You can't simply "convert" it. The integer is not represented in software in decimal notation. So the individual digits you want don't exist. They have to be computed.
So, given an arbitrary number, how can you determine the number of ones?
We could divide by ten, and then take the remainder: For 123, the division would give 12, and then there's a remainder of 3. So we have 3 ones. The 12 tells us what we have past the ones, so it can be our input for the next iteration. We take that, divide by 10, and get 1, and a remainder of 2. So we have 2 in the tens place, and 1 left to work with for the hundreds. Divide that by 10, which gives us zero, and a remainder of 1. So we get 1 in the hundreds place, 2 in the tens place, and 3 in the ones place. And we're done, as the last division returned zero.
See SO question Language showdown: Convert string of digits to array of integers? for a C/C++ version (as well as other languages).
if this is really homework then show it your teacher - just for fun ;-)
CAUTION! very poor performance, clumsy way to reach the effect you expect and generally don't do this at home(work) ;-)
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
typedef std::vector< int > ints_t;
struct digit2int
{
int operator()( const char chr ) const
{
const int result = chr - '0';
return result;
}
};
void foo( const int number, ints_t* result )
{
std::ostringstream os;
os << number;
const std::string& numberStr = os.str();
std::transform(
numberStr.begin(),
numberStr.end(),
std::back_inserter( *result ),
digit2int() );
}
int main()
{
ints_t array;
foo( 123456, &array );
std::copy(
array.begin(),
array.end(),
std::ostream_iterator< int >( std::cout, "\n" ) );
}
If you wanted to turn it into a string then it would be really easy, just do what everyone else is saying about using the % operator:
Let's say num = 123, we can do this:
string str;
while (num > 0)
{
str = (num % 10) + str; //put last digit and put it into the beginning of the string
num = num /10; //strip out the last digit
}
Now you can use str as an array of chars. Doing this with an array is a hassle because putting things in the beginning of an array requires you to shift everything else. What we can do is, instead of putting each digit into a string, we can put it into a stack. It will put it in a backwards order like this: 3 2 1. Then we can pop off the top number one by one and put that into an array in the correct order. You array will look like this: 1 2 3. I will leave the implementation to you since this is homework.
#Broam has a good solution, but like he stated, it's for working backwards. I think the OP or whoever comes looking into this thread will want it forwards and that's why I'm posting this. If you have a better solution, please reply, I'm interested as well.
To convert an integer to array, you can do the steps below:
Get the total number of digits in a number to which we want to convert to
array.For this purpose, we will use count_digits() function which will return total no of digits after ignoring leading zeros.
digits = count_digits(n);
Now we will dynamically allocate memory for our resulting array, just like
int* arr = new int[count_digits(n)]
After allocating memory, we will populate the array using the for loop below
int digits = count_digits(num);
for (int i = digits; i > 0; i--){
arr[i-1] = num % 10;
num = num / 10;
}
After performing the steps above, we will be able to convert an integer to array. Remember, num is the number that we want to convert into array and digits is the variable which gives us the number of digits in a given number ignoring leading zeros.