This question already has answers here:
Is there a one-line function that generates a triangle wave?
(8 answers)
Closed 8 years ago.
in a for-loop with % to get a saw function, for example using a period of 5 printing 2 cycles would look like this:
for(auto i = 0; i < 5 * 2; ++i) cout << i % 5 << endl;
Results in:
0
1
2
3
4
0
1
2
3
4
I want a function returns a triangle wave, so for some function foo:
for(auto i = 0; i < 5 * 2; ++i) cout << foo(i, 5) << endl;
Would result in:
0
1
2
1
0
0
1
2
1
0
Is there such a function, or do I need to come up with my own?
Looks like a very similar question was answered here: Is there a one-line function that generates a triangle wave?
Taken from Noldorin answer:
Triangular Wave
y = abs((x++ % 6) - 3);
This gives a triangular wave of period 6, oscillating between 3 and 0.
Now put that in a function:
int foo(int inputPosition, int period, int amplitude)
{
return abs((inputPosition % period) - amplitude);
}
You'd have to make your own:
// Assumes 0 <= i < n
int foo(int i, int n) {
int ix = i % n;
if ( ix < n/2 )
return ix;
else
return n-1-ix;
}
I thought we should at least post the correct answer here before this question is closed cause it is a duplicate.
Eric Bainvile's answer is the correct one.
int foo(const int position, const int period){return period - abs(position % (2 * period) - period);}
However this gives a triangle wave with a range from [0, period] and a frequency of 2 * period and I want a range from [0, period / 2] and a cycle of period. This can be accomplished by just passing half of the period to foo or by adjusting the function:
int foo(const int position, const int period){return period / 2 - abs(position % period - period / 2);}
With such a simple function inlining seems preferable though so our final result will be:
for(auto position = 0; position < 5 * 2; ++position) cout << 5 / 2 - abs(position % 5 - 5 / 2) << endl;
Yielding the requested:
0
1
2
1
0
0
1
2
1
0
Related
Here is the link to the question. Essentially, it asks to find the kth number having digit sum as 10. I have tried multiple solutions and also looked upon solutions online. Specifically this one (also shared below). The one with constant time talks about outliers in Arithmetic Progression and uses it to find the nth number having sum as 10. Obviously, the code is incorrect as it fails for test cases when k=1000 etc.
#include <bits/stdc++.h>
using namespace std;
int findNth(int n)
{
int nthElement = 19 + (n - 1) * 9;
int outliersCount = (int)log10(nthElement) - 1;
// find the nth perfect number
nthElement += 9 * outliersCount;
return nthElement;
}
int main()
{
cout << findNth(5) << endl;
return 0;
}
Eventually, I ended up writing combination of Arithmetic Progression + brute force as below
#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
int main() {
int n;
cin >> n;
int count = 0;
ll i = 19;
for (; ; i += 9) {
int curr = i;
int localSum = 0;
while (curr) {
localSum += curr%10;
curr /= 10;
}
if (localSum == 10) {
count += 1;
}
if (count == n) {
break;
}
}
cout << i << endl;
return 0;
}
I am wondering, if there is no constant time or better algorithm that does not require me to calculate the sum, but my algorithm always hops in a way that I have number whose digit sum is 10?
Here is a Python solution that you can translate into C++.
cached_count_ds_l = {}
def count_digit_sum_length (s, l):
k = (s, l)
if k not in cached_count_ds_l:
if l < 2:
if s == 0:
return 1
elif l == 1 and s < 10:
return 1
else:
return 0
else:
ans = 0
for i in range(min(10, s+1)):
ans += count_digit_sum_length(s-i, l-1)
cached_count_ds_l[k] = ans
return cached_count_ds_l[k]
def nth_of_sum (s, n):
l = 0
while count_digit_sum_length(s, l) < n:
l += 1
digits = []
while 0 < l:
for i in range(10):
if count_digit_sum_length(s-i, l-1) < n:
n -= count_digit_sum_length(s-i, l-1)
else:
digits.append(str(i))
s -= i
l -= 1
break
return int("".join(digits))
print(nth_of_sum(10, 1000))
The idea is to use dynamic programming to find how many numbers there are of a given maximum length with a given digit sum. And then to use that to cross off whole blocks of numbers on the way to finding the right one.
The main logic goes like this:
0 numbers of length 0 sum to 10
- need longer
0 numbers of length 1 sum to 10
- need longer
9 numbers of length 2 sum to 10
- need longer
63 numbers of length 3 sum to 10
- need longer
282 numbers of length 4 sum to 10
- need longer
996 numbers of length 5 sum to 10
- need longer
2997 numbers of length 6 sum to 10
- answer has length 6
Looking for 1000th number of length 6 that sums to 10
- 996 with a leading 0 sum to 10
- Need the 4th past 99999
- 715 with a leading 1 sum to 10
- Have a leading 1
Looking for 4th number of length 5 that sums to 9
- 495 with a leading 0 sum to 9
- Have a leading 10
Looking for 4th number of length 4 that sums to 9
- 220 with a leading 0 sum to 9
- Have a leading 100
Looking for 4th number of length 3 that sums to 9
- 55 with a leading 0 sum to 9
- Have a leading 1000
Looking for 4th number of length 2 that sums to 9
- 1 with a leading 0 sum to 9
- Need the 3rd past 9
- 1 with a leading 1 sum to 9
- Need the 2nd past 19
- 1 with a leading 2 sum to 9
- Need the 1st past 29
- 1 with a leading 3 sum to 9
- Have a leading 10003
Looking for 1st number of length 1 that sums to 6
- 0 with a leading 0 sum to 6
- Need the 1st past 0
- 0 with a leading 1 sum to 6
- Need the 1st past 1
- 0 with a leading 2 sum to 6
- Need the 1st past 2
- 0 with a leading 3 sum to 6
- Need the 1st past 3
- 0 with a leading 4 sum to 6
- Need the 1st past 4
- 0 with a leading 5 sum to 6
- Need the 1st past 5
- 1 with a leading 6 sum to 6
- Have a leading 100036
And it finishes in a fraction of a second.
Incidentally the million'th is 20111220000010, the billionth is 10111000000002000000010000002100, and the trillionth is 10000000100000100000100000000000001000000000000100000000010110001000.
int f(const std::vector<int>& v) {
int result = 0;
for (int i = 0; i < v.size(); ++i) { O(N)
for (int j = v.size(); j >= 0; j -= 2) { O(N/2)
result += v.at(i) * j;
}
}
return result;
}
The inner for loop is O(N/2), however I am wondering why this is because
For example, if v.size() is 10, then
10 >= 0 ✓
8 >= 0 ✓
6 >= 0 ✓
4 >= 0 ✓
2>= 0 ✓
0 >= 0 ✓
-2 Fails
The inner for loop could be executed 6 times with an input size of 10
What am I missing?
EDIT* I understand that only highest magnitude is taken into consideration. This question was more about coming up with the original O(N/2 + 1)
Complexity gives you a way to assess the magnitude of time it would take an input of certain size to complete, not the accurate time it would perform with.
Therefore, when dealing with complexity, you should only consider the highest magnitude, without constant multipliers:
O(N/2 + 1) = O(N/2) = O(N)
In a comment, you said:
I understand this, but I am just curious as to how O(N/2) is obtained
Take a look at the following table:
Size of vector Number of time the inner loop is executed:
0 1
1 1
2 2
3 2
...
100 51
101 51
...
2x x + 1
2x + 1 x + 1
If you take the constant 1 out of that equation, the inner loop is O(N/2).
Let's say I have 15 elements. I want to group them such a way that:
group1 = 1 - 5
group2 = 6 - 9
group3 = 10 - 12
group4 = 13 - 14
group5 = 15
This way I'll get elements in each group as below:
group1 = 5
group2 = 4
group3 = 3
group4 = 2
group5 = 1
As you can see loop interval is decreasing.
I took 15 just for an example. In actual programme it's user driven parameter which can be anything (hopefully few thousand).
Now what I'm looking for is:
Whatever is in group1 should have variable "loop" value 0, group2 should have 1, group3 should have 2 and so on... "loop" is an int variable which is being used to calculate some other stuff.
Let's put in other words too
I have an int variable called "loop". I want to assign value to it such a way that:
First n frames loop value 0 next (n -1) frames loop value 1 then next (n - 2) frames loop value 2 all the way to loop value (n - 1)
Let's say I have 15 frames on my timeline.
So n will be 5 ====>>>>> (5 + 4 + 3 + 2 + 1 = 15; as interval is decreasing by 1)
then
first 5 frames(1 - 5) loop is 0 then next 4 frames(6 - 9) loop is 1 then next 3 frames(10 - 12) loop is 2 then next 2 frames(13 - 14) loop is 3 and for last frame(15) loop is 4.
frames "loop" value
1 - 5 => 0
6 - 9 => 1
10 - 12 => 2
13 - 14 => 3
15 => 4
I've tried with modulo(%). But the issue is on frame 12 loop is 2 so (12 % (5 - 2)) remainder is 0 so it increments loop value.
The following lines are sample code which is running inside a solver. #loop is by default 0 and #Frame is current processing frame number.
int loopint = 5 - #loop;
if (#Frame % loopint == 0)
#loop += 1;
If I understand this correctly, then
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
int n = atoi(argv[1]);
for(int i = 1; i <= n; ++i) {
printf("%d: %f\n", i, ceil((sqrt(8 * (n - i + 1) + 1) - 1) / 2));
}
}
is an implementation in C.
The math behind this is as follows: The 1 + 2 + 3 + 4 + 5 you have there is a Gauß sum, which has a closed form S = n * (n + 1) / 2 for n terms. Solving this for n, we get
n = (sqrt(8 * S + 1) - 1) / 2
Rounding this upward would give us the solution if you wanted the short stretches at the beginning, that is to say 1, 2, 2, 3, 3, 3, ...
Since you want the stretches to become progressively shorter, we have to invert the order, so S becomes (n - S + 1). Therefore the formula up there.
EDIT: Note that unless the number of elements in your data set fits the n * (n+1) / 2 pattern precisely, you will have shorter stretches either at the beginning or in the end. This implementation places the irregular stretch at the beginning. If you want them at the end,
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
int n = atoi(argv[1]);
int n2 = (int) ceil((sqrt(8 * n + 1) - 1) / 2);
int upper = n2 * (n2 + 1) / 2;
for(int i = 1; i <= n; ++i) {
printf("%d: %f\n", i, n2 - ceil((sqrt(8 * (upper - i + 1) + 1) - 1) / 2));
}
}
does it. This calculates the next such number beyond your element count, then calculates the numbers you would have if you had that many elements.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
F is a function that number x has been repeated in an ascending order f(x).
x : 1 2 3 4 5 6 7 8 9 10
f(x): 1 2 2 3 3 3 4 4 4 4
my function gets 'x' and gives 'f(x)' and it has to do it without array but it goes wrong in high numbers.
int main()
{
int n;
cin>>n;
int i=1,a=1;
if(n==1)
cout<<'1';
else{
while(true){
a++;
i=i+a;
if(i>=n)
break;
}
}
cout<<a;
return 0;
}
TL;DR
f(x) = floor(0.5 + sqrt(1 + 8 * (x - 1)) / 2)
Explanation
Well, since this is a mathematical problem, just solve it with math ;)
One thing to notice is the correlation between the table and the triangular numbers:
h(x) = sum(range(1, x)) = x*(x + 1)/2 //triangular number
x 1 2 3 4 5 6 7 8 9 10
f(x) 1 2 2 3 3 3 4 4 4 4
h(f(x)) 1 3 3 6 6 6 10 10 10 10
So how does that help us? Well, we can write a new equation:
h(f(x)) = x | x = max({n | f(n) = f(x)})
And logically for the inverse the following should apply:
h^-1(x) = f(x)
No we've got two options:
Call it a day and just solve the rest via brute-force:
i = 1
sum = 0
while sum < x:
sum += i
i++
return i - 1
Or build our function h^-1(x):
h(x) = y = (x+1)x/2
h^-1(y) = x with h(x) = y
x ^ 2 + x - 2y = 0
solve for x using the quadratic formula:
x = 0.5 +/- sqrt(1 + 8y) / 2
Now this formula still lacks a few things:
we get two results, one of which is negative. We can just throw the negative result away, so +/- turns into +
this formula is 0-based. To be honest, I'm still trying to figure out why. Solution: simply decrement y by 1 to get the proper result
while this formula returns the correct result for the matching numbers, i.e. y = 3 -> x = 3, it returns floating-point numbers for other input, so we'll have to round down appropriately
Putting it together:
f(x) = floor(0.5 + sqrt(1 + 8 * (x - 1)) / 2)
int f(int x) {
return (x * (x + 1)) / 2;
}
int main() {
int n;
cin >> n;
int left = 1, right = n;
while(left < right) {
int mid = left + (right - left) / 2;
int val = f(mid);
if(val >= n) {
right = mid;
}
else {
left = mid + 1;
}
}
cout << left;
return 0;
}
Use binary search. Right now I am in mobile. I will add the explanation later if needed. Let me know if you don't understand anything.
All right, so I have to solve this problem in which the user gives a list of 7 or k numbers and I have to tell how many ways are there to get 21 or n using sums and substractions of these numbers. I have to use all numbers.
For example, user gives the number: (1 3 4 5 9 1 7). I can put all these numbers into an array of length 7 and count how many times do I get 21 usings sums and/or subs of these numbers:
1 +/- 3 +/- 4 +/- 5 +/- 9 +/- 1 +/- 7.
The code for this problem is already made:
count-twenty-one(int* dig, int n, int pos, int sum, int res) {
if (pos==n) {
if(sum==21)
return res++;
}
count-twenty-one(dig, n, pos+1, sum+dig[pos], res)
count-twenty-one(dig, n, pos+1, sum-dig[pos], res)
}
As you can see this makes a DFS (Deep First Search) to find how many ways are there to get 21. Now, the actual problem is how to know how many ways are there to get 21 using combinations of given numbers, and again I have to use all of them. For example, user gives the number:
(0 0 0 0 2 1 0). There's no way I can get 21 using 0 + 0 - 0 + 0 + 2 + 1 + 0. But If I append the 2 and the 1 and sum/sub it with the other 0 I can get 21.
0 + 0 + 0 - 0 + 21 -0 = 21 Let'say the user now gives (2 3 9 8 5 0 7). With this I could for numbers like 23 98 5 7 and try to see how many ways are there to get the desired number. But then again I can have 239 8 507.
So I guess the main problem is to get all posible combinations of numbers from (1 to k) -K is the length of numbers list- and then use count-twenty-one in all of them. How do I do this? I'm using C++ and arrays.
edit:
This problem can be solved by gettin all possible paritions of the given array, then putting al those partitions through count-twenty-one. Any ideas?
edit 2:
The numbers are 'ordered' this means with (2 3 9 8 5 0 7) I can't form combinations like 705 8 93 2
For the brute force approach, following may help: https://ideone.com/jAVRDk
void print(const std::vector<int>& digits,
const std::vector<int>& seps,
const std::vector<std::string>& s) {
std::cout << digits[0];
for (std::size_t i = 0; i != seps.size(); ++i) {
std::cout << s[seps[i]] << digits[i + 1] ;
}
std::cout << std::endl;
}
bool next(std::vector<int>& seps)
{
for (auto it = seps.rbegin(); it != seps.rend(); ++it) {
if (++*it == 3) {
*it = 0;
} else {
return true;
}
}
return false;
}
void foo(std::vector<int> digits)
{
const std::vector<std::string> s = {"", " + ", " - "};
std::sort(digits.begin(), digits.end());
do {
std::vector<int> seps(digits.size() - 1, 0);
do {
print(digits, seps, s);
} while (next(seps));
} while (std::next_permutation(digits.begin(), digits.end()));
}