Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Team 7 faces a horrible foe. He can only be defeated with a special
quadruple combination attack of strength ( 1 <=S <= 10^9 ).
Naruto, Sasuke, Sakura and Kakashi must attack simultaneously to
perform the combo. Each of them can choose from N ( 1 <= N <=1000 ) attacks, having strengths si each ( 0 <= i < N, 1 <= si <=10^9). The strengths of individual attacks add up to form the
strength of the combo.
Is there a valid combination that they can use? Note that the same
attacks are available to all of them.
You are required to write a function which takes input as follows – An
integer N as number of attacks, an integer vector s[] as the
strengths of N attacks and an integer S as the required strength
of the combo. Set the output variable to the number of distinct valid
combos.
Two combinations are different if they differ in strength of at least
one attack used.
Input: 1 {1} 4
Output: 1 ===>{1,1,1,1}
Input: 2 {1,2} 5
Output: 1 ===> {1,1,1,2}
Below is my code its only passes 3 test cases out of 10. I don't know the test cases as it was some online code submission.
My Algorithm:
1) Create a hash with indexes as sum of pairs from input array and value as individual elements contributing to sum
2) Iterate over the hash and look if for i in hash there is k-i
3) Count above indexes and return count/2 as we are counting for both H(i) and H(k-i)
Please review the code and tell me what scenarios you think code will not produce right o/p.
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
const int noOfPalyers = 4;
int validCombo(int input1,int input2[],int input3)
{
//Write code here
int count = 0;
std::vector<int> vec;
int size =input1*noOfPalyers;
for(int i = 0; i < input1; i++)
{
for(int j = 0; j < noOfPalyers;j++)
{
vec.push_back(input2[i]);
}
}
std::vector< std::set< std::pair<int, int> > > vecHash;
//vecHash.reserve(size*size);
for(int i =0; i < (size*size); i++)
{
vecHash.push_back(std::set< std::pair<int, int> >());
}
for(int i =0; i < size; i++)
{
for(int j =1; j < size; j++)
{
int key = vec[i] + vec[j];
if(vec[i]<= vec[j])
vecHash[key].insert(std::make_pair(vec[i], vec[j]));
else
vecHash[key].insert(std::make_pair(vec[j], vec[i]));
}
}
for(int i = 0; i < input3; i++)
{
if(vecHash[i].size() > 0 && i < input3)
{
if(vecHash[input3-i].size() > 0)
{
std::set< std::pair<int, int> >::iterator iter, iter2;
for(iter=vecHash[i].begin(); iter!=vecHash[i].end();++iter)
{
for(iter2=vecHash[input3-i].begin(); iter2!=vecHash[input3-i].end();++iter2)
{
std::cout<<(*iter).first<<","<< (*iter).second<<",";
std::cout<<(*iter2).first<<","<< (*iter2).second;
std::cout<<"\n";
count++;
}
}
}
}
}
return (count ==1 ? count: count/2);
}
int main()
{
int i = 3;
int arr[] = {1,2,3};
int j = 7;
int arr1[] ={1};
std::cout <<"o/p == " << validCombo(i, arr, j)<< "\n";
std::cout <<"o/p == " << validCombo(1, arr1, 4);
//getch();
return 0;
}
UPD. My God, now I've understood your comment :) and see that you tried to solve it the same way I wrote. Anyway, I hope you'll find some pieces of my explanation useful. First of all, you don't use hash functions (I know identity function is a hash func, but not the good one in our case). Also I didn't understand your count logic... I think you need to read Two combinations are different if they differ in strength of at least one attack used. part again and check your count logic.
There're just my first thoughts. Hope it could be helpful.
==================================
You know, this problem is about having particular sum of 4 numbers from the set. Let's imagine we have just 2 heroes (so 2 terms in our sum):
a + b = S,
where a, b are attack's strengths from set of N numbers (let's name it T). The number of different a + b sums is N^2. Simple calculating all of these sums and then searching those ones equal to S doesn't give us good solution. This problem can be solved with better complexity.
If we could find a fast function such that:
F(a) = F(S - b)
we would precalculate all F(S - b), then looped over all a's and found which ones satisfy equality above. You mentioned hash. Hash functions can do this. We need such hash func to map all numbers from set T to range [0, N]. Because we just have no more than N different a's.
But we have a little problem here:
F(a) = F(S - b) just means a can be equal to S - b. Fortunately, it's not a big problem,
because the main power is: F(a) != F(S - b) means a != S - b.
Ok, as you see we have algorithm to solve a + b = S problem with amortized O(N) complexity. Sounds good and promising, right? :)
==================================
Now come back to your problem:
a + b + c + d = S
My idea to precalculate all f(a + b) with O(N^2) and store them like this (warning! just pseudocode):
vector<int> hash = new vector<int>(with size N)
foreach (a in T)
foreach (b in T)
{
int x = OurHashFunc(a + b); // a + b <= 2 * 10^9 so it never overflows int
if (hash[x] == null)
hash[x] = new vector<pair<int,int>>
hash[x].push_back(new pair<int, int>(a, b));
}
We keep pairs (a,b) to be able to restore terms of initial sum. Then if our OurHashFunc is additive then transform our initial problem like this:
a + b + c + d = S // apply hash func =>
f(a + b) + f(c + d) = f(S) // rename =>
x + y = Z // wow, I bet I've already seen this equation ;)
Now 4-terms sum problem had reduced to 2-terms sum problem with an O(N^2) overhead.
I think this reduction can be continued: 2^k-terms sum problem should have avg O(N^k) solution.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Good Evening everyone. I am not really sure as to whether it is against the rules to ask questions like these on this platform (If it is, kindly tell me). The question is of a "practice competition". I could complete 5 of 10 test cases but I am not sure what is wrong in this. Please suggest any correction/logic/hint... And Time Complexity must be less than O(n^2) (According to the input given)
The approach I tried is:
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
signed long int t, n;
scanf("%d", &t);
for (int i = 1; i <= t; i++) {
int count = 0;
scanf("%d", &n);
if (n <= 10)
count = n;
else {
// count = 9;
string s;
s = to_string(n);
int len = s.length();
int x = n / (pow(10, len - 2));
int h = x / 11;
string y = to_string(x);
if (y.length() <= 2)
x = 0;
count = (9 * (len - 1)) + x + h;
}
printf("%d\n", count);
}
return 0;
}
Please suggest whatever you feel is helpful. Thank you so much.
For the problem, given that the work area you are dealing with is relatively small (the number of beautiful numbers less than 10^9 can be reasonably handled with a table of those values), here is a version of a solution that uses a pre-generated table of all of the beautiful numbers in sorted order.
Once the table is set up, it is just a matter of doing a binary search to determine the number of beautiful numbers there are that occur before the input value. The position of the closest beautiful number in the table is the number of beautiful numbers we need.
The binary search is done by utilizing the <algorithm> function std::upper_bound. This function will return an iterator to the item that is greater than the search item. Then to get the position, std::distance is used (we subtract 1, since std::upper_bound will give us the item that is greater than the searched item).
The generation of the table can be done at compile-time (by hand, just initializing an array), or if you're lazy, generated at runtime with a simple loop. Here is one such solution:
#include <algorithm>
#include <vector>
#include <iostream>
std::vector<int> values;
int generate_value(int digit, int numTimes)
{
int total = 0;
for (int i = 0; i < numTimes; ++i)
total = 10 * total + digit;
return total;
}
// I'm lazy, so let the program generate the table for me
void generate_values()
{
size_t curIdx = 0;
values.push_back(0);
for (int i = 1; i <= 9; ++i)
{
for (int j = 1; j <= 9; ++j)
values.push_back(generate_value(j, i));
}
values.push_back(1111111111);
}
// does a binary search and returns the position of the beautiful number
int beautiful(int num)
{
if (num == 0)
return 1;
// get iterator to closest number equaling the beautiful number
auto iter = std::upper_bound(values.begin(), values.end(), num);
// get distance from beginning of vector
return std::distance(values.begin(), iter) - 1;
}
int main()
{
generate_values();
std::cout << beautiful(18) << "\n";;
std::cout << beautiful(1) << "\n";;
std::cout << beautiful(9) << "\n";;
std::cout << beautiful(100500) << "\n";;
std::cout << beautiful(33) << "\n";;
std::cout << beautiful(1000000000) << "\n";;
}
Output:
10
1
9
45
12
81
The size of the table is in total, 83 entries, thus a binary search of this table will take no more than log(83) checks to find the value, which is at most 7 probes in the table.
This is not a complex problem.
Assuming your input is correct so we don’t have to do any checking we observe:
If number n is single digit the number of beautiful numbers is b = n.
If number n is double digit and the first digit is f, then the number of beautiful numbers b = 9 + x, where x is a number of all beautiful double digit numbers smaller than n,
If number n is triple digit and the first digit is f, then the number of beautiful numbers b = 2 x 9 + x, where x is a number of all beautiful triple digit numbers smaller than n.
And so on and on
Thus we can extrapolate: If number n has d digits, than the number of beautiful numbers
s = (d-1) * 9 + x,
where x is a number of beautiful d-digit numbers smaller than or equal to n.
So your problem was reduced to finding x. And this can be reduced even further. Take for instance number n = 44437. The important number here is first digit f. It is trivial to see that all 5 digit beautiful numbers that begin where single digits are less then f are ok. In our example 11111, 22222, 33333 are ok, while 444444 and larger are not.
So all you need to do is to check if beautiful number fffff is smaller than or equal to n. And this can be done with simple traversal of input string.
So your solution would be:
s = (d-1) * 9 + (f-1) + supersecretsauce,
where:
s - solution
n – your input number of age
d – number of digits, assuming your input is always correct is length(n)
f – first digit of your number n
supersecretsauce – 1 if fff…f is smaller or equal than n, 0 if bigger.
And even the traversal of input string can be optimized, but I leave that to you.
Oh yeah... and the time complexity of this solution O(n) = length(n) = log10(n).
A couple of things about the early set up.
1) From the input example you gave, it appears the t and each n need to be input sequentially, but your code prints the number of beautiful numbers before the next input is received. I would suggest reading in t first, then looping through an array of size t to get all the inputs first.
2) The constraints aren't tested. I would test the t and each value in the array mentioned before that the constraints are met, and either have the user try again if they aren't, or simply abort.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have seen this, but this is not what I am looking for.
The problem is same that is to find the largest palindrome which is the product of two three digit numbers.
Since my program was not working so I made a little change, instead of finding the largest palindrome which is the product of two three digit numbers I have written the program to find the largest palindrome which is the product of two two digit numbers.
Kindly see the program:
#include <iostream>
using namespace std;
int main() {
int i, j, n, s, m, w;
for (i = 99; i > 9; i--) {
for (j = 99; j > 9; j--)
n = i * j;
s = n;
while (n != 0) {
w = 0;
m = n % 10;
w = w * 10 + m;
n = n / 10;
}
if (s == w)
cout << s << endl;
break;
}
return 0;
}
The problem with this program is that it is neither showing any error nor giving any result.
So kindly help me to find the problem in my program.
Right now you are missing the curly braces for the j-loop. The current code is doing 99! * i.
Then you would have to focus on storing the largest palindrome value instead of just printing all those values to the screen (this is considering your implementation, it is not the most efficient one by any means).
Some modified version of your code:
#include <iostream>
using namespace std;
int main() {
int max_product = 0;
for (int i = 99; i > 9; i--) {
for (int j = i; j > 9; j--) {
int product = i * j;
if (product < max_product)
break;
int number = product;
int reverse = 0;
while (number != 0) {
reverse = reverse * 10 + number % 10;
number /= 10;
}
if (product == reverse && product > max_product) {
max_product = product;
}
}
}
cout << "Solution: " << max_product << endl;
return 0;
}
You have various problems:
Need one more pair of {, }. After the for-loop of j. The only instruction the for-loop of j is executing is: n = i * j; with the braces the rest of the instruction (testing if it's a palindrome) are out of the loop.
the variable w the reverse of the number to test for palindrome is reset his value to 0 in every execution of while (n != 0) loop resulting in incorrect reverse value (and never find the palindrome).
The max palindrome product of 2 two digits number don't have to be the first one found with this 2 for-loop, eg: suppose that there is 2 valid solutions i = 98, j = 2 and i = 70, j = 65 in this case i*j would be in first solution = 196 in the second = 4550 and when you found the first you could not stop the search. In your code using the break don't do what I think you are waiting for (stop the search), only stop the search with the actual i value.
Some notes about the modified code:
The two for-loop don't need to be from 99..9, in this case you are testing a lot of product two times (eg: 98*99, are testing when i == 98 and j == 99 and i == 99 and j == 98), you could restrict j to be always less or equal to i.
Using max_product to maintain the maximum palindrome product found. And use that info in the inner loop (if (product < max_product)) for early exit when no better solution could be found.
I met a very simple interview question, but my solution is incorrect. Any helps on this? 1)any bugs in my solution? 2)any good idea for time complexity O(n)?
Question:
Given an int array A[], define X=A[i]+A[j]+(j-i), j>=i. Find max value of X?
My solution is:
int solution(vector<int> &A){
if(A.empty())
return -1;
long long max_dis=-2000000000, cur_dis;
int size = A.size();
for(int i=0;i<size;i++){
for(int j=i;j<size;j++){
cur_dis=A[j]+A[i]+(j-i);
if(cur_dis > max_dis)
max_dis=cur_dis;
}
}
return max_dis;
}
The crucial insight is that it can be done in O(n) only if you track where potentially useful values are even before you're certain they'll prove usable.
Start with best_i = best_j = max_i = 0. The first two track the i and j values to use in the solution. The next one will record the index with the highest contributing factor for i, i.e. where A[i] - i is highest.
Let's call the value of X for some values of i and j "Xi,j", and start by recording our best solution so far ala Xbest = X0,0
Increment n along the array...
whenever the value at [n] gives a better "i" contribution for A[i] - i than max_i, update max_i.
whenever using n as the "j" index yields Xmax_i,n greater than Xbest, best_i = max_i, best_j = n.
Discussion - why/how it works
j_random_hacker's comment suggests I sketch a proof, but honestly I've no idea where to start. I'll try to explain as best I can - if someone else has a better explanation please chip in....
Restating the problem: greatest Xi,j where j >= i. Given we can set an initial Xbest of X0,0, the problem is knowing when to update it and to what. As we contemplate successive indices in the array as potential values for j, we want to generate Xi,j=n for some i (discussed next) to compare with Xbest. But, what i value to use? Well, given any index from 0 to n is <= j, the j >= i constraint isn't relevant if we pick the best i value from the indices we've already visited. We work out the best i value by separating the i-related contribution to X from the j-related contribution - A[i] - i - so in preparation for considering whether we've a new best solution with j=n we must maintain the best_i variable too as we go.
A way to approach the problem
For whatever it's worth - when I was groping around for a solution, I wrote down on paper some imaginary i and j contributions that I could see covered the interesting cases... where Ci and Cj are the contributions related to n's use as i and j respectively, something like
n 0 1 2 3 4
Ci 4 2 8 3 1
Cj 12 4 3 5 9
You'll notice I didn't bother picking values where Ci could be A[i] - i while Cj was A[j] + j... I could see the emerging solution should work for any formulas, and that would have just made it harder to capture the interesting cases. So - what's the interesting case? When n = 2 the Ci value is higher than anything we've seen in earlier elements, but given only knowledge of those earlier elements we can't yet see a way to use it. That scenario is the single "great" complication of the problem. What's needed is a Cj value of at least 9 so Xbest is improved, which happens to come along when n = 4. If we'd found an even better Ci at [3] then we'd of course want to use that. best_i tracks where that waiting-on-a-good-enough-Cj value index is.
Longer version of my comment: what about iterating the array from both ends, trying to find the highest number, while decreasing it by the distance from the appripriate end. Would that find the correct indexes (and thus the correct X)?
#include <vector>
#include <algorithm>
#include <iostream>
#include <random>
#include <climits>
long long brutal(const std::vector<int>& a) {
long long x = LLONG_MIN;
for(int i=0; i < a.size(); i++)
for(int j=i; j < a.size(); j++)
x = std::max(x, (long long)a[i] + a[j] + j-i);
return x;
}
long long smart(const std::vector<int>& a) {
if(a.size() == 0) return LLONG_MIN;
long long x = LLONG_MIN, y = x;
for(int i = 0; i < a.size(); i++)
x = std::max(x, (long long)a[i]-i);
for(int j = 0; j < a.size(); j++)
y = std::max(y, (long long)a[j]+j);
return x + y;
}
int main() {
std::random_device rd;
std::uniform_int_distribution<int> rlen(0, 1000);
std::uniform_int_distribution<int> rnum(INT_MIN,INT_MAX);
std::vector<int> v;
for(int loop = 0; loop < 10000; loop++) {
v.resize(rlen(rd));
for(int i = 0; i < v.size(); i++)
v[i] = rnum(rd);
if(brutal(v) != smart(v)) {
std::cout << "bad" << std::endl;
return -1;
}
}
std::cout << "good" << std::endl;
}
I'll write in pseudo code because I don't have much time, but this should be the most performing way using recursion
compare(array, left, right)
val = array[left] + array[right] + (right - left);
if (right - left) > 1
val1 = compare(array, left, right-1);
val2 = compare(array, left+1, right);
val = Max(Max(val1,val2),val);
end if
return val
and than you call simply
compare(array,0,array.length);
I think I found a incredibly faster solution but you need to check it:
you need to rewrite your array as follow
Array[i] = array[i] + (MOD((array.lenght / 2) - i));
Then you just find the 2 highest value of the array and sum them, that should be your solution, almost O(n)
wait maybe I'm missing something... I have to check.
Ok you get the 2 highest value from this New Array, and save the positions i, and j. Then you need to calculate from the original array your result.
------------ EDIT
This should be an implementation of the method suggested by Tony D (in c#) that I tested.
int best_i, best_j, max_i, currentMax;
best_i = 0;
best_j = 0;
max_i = 0;
currentMax = 0;
for (int n = 0; n < array.Count; n++)
{
if (array[n] - n > array[max_i] - max_i) max_i = n;
if (array[n] + array[max_i] - (n - max_i) > currentMax)
{
best_i = max_i;
best_j = n;
currentMax = array[n] + array[max_i] - (n - max_i);
}
}
return currentMax;
Question:
Given an int array A[], define X=A[i]+A[j]+(j-i), j>=i. Find max value of X?
Answer O(n):
lets rewrite the formula: X = A[i]-i + A[j]+j
we can track the highest A[i]-i we got and the highest A[j]+j we got. We loop over the array once and update both of our max values. After looping once we return the sum of A[i]-i + A[j]+j, which equals X.
We absolutely don't care about the j>=i constraint, because it is always true when we maximize both A[i]-i and A[j]+j
Code:
int solution(vector<int> &A){
if(A.empty()) return -1;
long long max_Ai_part =-2000000000;
long long max_Aj_part =-2000000000;
int size = A.size();
for(int i=0;i<size;i++){
if(max_Ai_part < A[i] - i)
max_Ai_part = A[i] - i;
if(max_Aj_part < A[j] + j)
max_Ai_part = A[j] - j;
}
return max_Ai_part + max_Aj_part;
}
Bonus:
most people get confused with the j>=i constraint. If you have a feeling for numbers, you should be able to see that i should tend to be lower than j.
Assume we have our formula, it is maximized and i > j. (this is impossible, but lets check it out)
we define x1 := j-i and x2 = i-j
A[i]+A[j]+j-i = A[i]+A[j] + x1, x1 < 0
we could then swap i with j and end up with this:
A[j]+A[i]+i-j = A[i]+A[j] + x2, x2 > 0
it is basically the same formula, but now because i > j the second formula will be greater than the first. In other words we could increase the maximum by swapping i and j which can't be true if we already had the maximum.
If we ever find a maximum, i cannot be greater than j.
I have a sorted std::vector<int> and I would like to find the longest 'streak of consecutive numbers' in this vector and then return both the length of it and the smallest number in the streak.
To visualize it for you :
suppose we have :
1 3 4 5 6 8 9
I would like it to return: maxStreakLength = 4 and streakBase = 3
There might be occasion where there will be 2 streaks and we have to choose which one is longer.
What is the best (fastest) way to do this ? I have tried to implement this but I have problems with coping with more than one streak in the vector. Should I use temporary vectors and then compare their lengths?
No you can do this in one pass through the vector and only storing the longest start point and length found so far. You also need much fewer than 'N' comparisons. *
hint: If you already have say a 4 long match ending at the 5th position (=6) and which position do you have to check next?
[*] left as exercise to the reader to work out what's the likely O( ) complexity ;-)
It would be interesting to see if the fact that the array is sorted can be exploited somehow to improve the algorithm. The first thing that comes to mind is this: if you know that all numbers in the input array are unique, then for a range of elements [i, j] in the array, you can immediately tell whether elements in that range are consecutive or not, without actually looking through the range. If this relation holds
array[j] - array[i] == j - i
then you can immediately say that elements in that range are consecutive. This criterion, obviously, uses the fact that the array is sorted and that the numbers don't repeat.
Now, we just need to develop an algorithm which will take advantage of that criterion. Here's one possible recursive approach:
Input of recursive step is the range of elements [i, j]. Initially it is [0, n-1] - the whole array.
Apply the above criterion to range [i, j]. If the range turns out to be consecutive, there's no need to subdivide it further. Send the range to output (see below for further details).
Otherwise (if the range is not consecutive), divide it into two equal parts [i, m] and [m+1, j].
Recursively invoke the algorithm on the lower part ([i, m]) and then on the upper part ([m+1, j]).
The above algorithm will perform binary partition of the array and recursive descent of the partition tree using the left-first approach. This means that this algorithm will find adjacent subranges with consecutive elements in left-to-right order. All you need to do is to join the adjacent subranges together. When you receive a subrange [i, j] that was "sent to output" at step 2, you have to concatenate it with previously received subranges, if they are indeed consecutive. Or you have to start a new range, if they are not consecutive. All the while you have keep track of the "longest consecutive range" found so far.
That's it.
The benefit of this algorithm is that it detects subranges of consecutive elements "early", without looking inside these subranges. Obviously, it's worst case performance (if ther are no consecutive subranges at all) is still O(n). In the best case, when the entire input array is consecutive, this algorithm will detect it instantly. (I'm still working on a meaningful O estimation for this algorithm.)
The usability of this algorithm is, again, undermined by the uniqueness requirement. I don't know whether it is something that is "given" in your case.
Anyway, here's a possible C++ implementation
typedef std::vector<int> vint;
typedef std::pair<vint::size_type, vint::size_type> range;
class longest_sequence
{
public:
const range& operator ()(const vint &v)
{
current = max = range(0, 0);
process_subrange(v, 0, v.size() - 1);
check_record();
return max;
}
private:
range current, max;
void process_subrange(const vint &v, vint::size_type i, vint::size_type j);
void check_record();
};
void longest_sequence::process_subrange(const vint &v,
vint::size_type i, vint::size_type j)
{
assert(i <= j && v[i] <= v[j]);
assert(i == 0 || i == current.second + 1);
if (v[j] - v[i] == j - i)
{ // Consecutive subrange found
assert(v[current.second] <= v[i]);
if (i == 0 || v[i] == v[current.second] + 1)
// Append to the current range
current.second = j;
else
{ // Range finished
// Check against the record
check_record();
// Start a new range
current = range(i, j);
}
}
else
{ // Subdivision and recursive calls
assert(i < j);
vint::size_type m = (i + j) / 2;
process_subrange(v, i, m);
process_subrange(v, m + 1, j);
}
}
void longest_sequence::check_record()
{
assert(current.second >= current.first);
if (current.second - current.first > max.second - max.first)
// We have a new record
max = current;
}
int main()
{
int a[] = { 1, 3, 4, 5, 6, 8, 9 };
std::vector<int> v(a, a + sizeof a / sizeof *a);
range r = longest_sequence()(v);
return 0;
}
I believe that this should do it?
size_t beginStreak = 0;
size_t streakLen = 1;
size_t longest = 0;
size_t longestStart = 0;
for (size_t i=1; i < len.size(); i++) {
if (vec[i] == vec[i-1] + 1) {
streakLen++;
}
else {
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
beginStreak = i;
streakLen = 1;
}
}
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
You can't solve this problem in less than O(N) time. Imagine your list is the first N-1 even numbers, plus a single odd number (chosen from among the first N-1 odd numbers). Then there is a single streak of length 3 somewhere in the list, but worst case you need to scan the entire list to find it. Even on average you'll need to examine at least half of the list to find it.
Similar to Rodrigo's solutions but solving your example as well:
#include <vector>
#include <cstdio>
#define len(x) sizeof(x) / sizeof(x[0])
using namespace std;
int nums[] = {1,3,4,5,6,8,9};
int streakBase = nums[0];
int maxStreakLength = 1;
void updateStreak(int currentStreakLength, int currentStreakBase) {
if (currentStreakLength > maxStreakLength) {
maxStreakLength = currentStreakLength;
streakBase = currentStreakBase;
}
}
int main(void) {
vector<int> v;
for(size_t i=0; i < len(nums); ++i)
v.push_back(nums[i]);
int lastBase = v[0], currentStreakBase = v[0], currentStreakLength = 1;
for(size_t i=1; i < v.size(); ++i) {
if (v[i] == lastBase + 1) {
currentStreakLength++;
lastBase = v[i];
} else {
updateStreak(currentStreakLength, currentStreakBase);
currentStreakBase = v[i];
lastBase = v[i];
currentStreakLength = 1;
}
}
updateStreak(currentStreakLength, currentStreakBase);
printf("maxStreakLength = %d and streakBase = %d\n", maxStreakLength, streakBase);
return 0;
}
I've been able to solve the following problem using std::next_permutation (c++) etc,
but I'm now thinking about it in a more general and would very much like to form an
expression as this type of problem seems to lend itself - though I'm not having any luck as of yet.
Here is the question:
Given a running race with N contestants, what is the probability that exactly M contestants will finish in a position that is the same as the number on their shirt.
Where M <= N.
What I've done so far:
There will be N! ways the race can end,
I've tried fiddling with a small variant of the problem consisting of either 3 or 4 contestants with
the required number of people meeting the condition as being 2. in both cases for 2 people finishing in the particular order the probability is 1/2
I'd like to know if there's already some kind of expression that handles all the cases?
Some code:
#include <cstdio>
#include <algorithm>
#include <vector>
int main(int argc, char* argv[]) {
if (argc != 3) return 1;
int n = atoi(argv[1]);
int m = atoi(argv[2]);
if (m > n) return 1;
std::vector<int> lst(n);
for (int i = 0; i < n; ++i) lst[i] = i;
unsigned int total = 0;
unsigned int perm_count = 0;
do {
int cnt = 0;
for (int i = 0; i < n; ++i) if (lst[i] == i) ++cnt;
if (cnt == m)
++total;
++perm_count;
}
while (std::next_permutation(lst.begin(),lst.end()));
printf("Probability of (%d,%d) = %8.7f\n",n,m,(1.0 * total / perm_count));
return 0;
}
Update: The expression is called a Partial Derangement:
http://mathworld.wolfram.com/PartialDerangement.html
Note1: The formula is correct, if one assumes that the fully ordered permutation does not count.
Note2: I've changed the question slightly to make it more clear, hence also changed to code - this should reconsile with comments made by ShreevatsaR.
The number of permutations of a set with n elements containing m fixed points is
D(n,m) = \frac{n!}{m!}\sum_{k=0}^{n-m}\frac{(-1)^k}{k!} http://bit.ly/aaKqUq
(see http://en.wikipedia.org/wiki/Random_permutation_statistics#Number_of_permutations_that_are_derangements)
Therefore, the probability is D(n,m)/n!, i.e.
d(n,m) = \frac{1}{m!}\sum_{k=0}^{n-m}\frac{(-1)^k}{k!} http://bit.ly/aVqSkA
There are two definitions you need to solve this in closed form:
The number of ways to permute N people is N! (N factorial), or N * N-1 * N-2 * ... * 1. These are called permutations.
The number of ways to choose M people from N is called (N choose M), and it equals N! / (M! (N-M)!) - these are called combinations. (If this is new to you, do a Google search for "permutations and combinations".)
I'm working on a closed-form solution...