Related
I'm trying to make a vector adding of two arrays with the same dimensions, but all that I get is a "list index out of range" error. The code I used is:
x = [0, 0, 0]
y = [1, 2, 3]
i = 0
c = []
while (i <= len(x)):
c.append(a[i] + b[i])
i = i + 1
print c
Can you point me where is te problem? Any help or idea will be appreciated.
In python, try to avoid looping over indices when possible. A more pythonic way of doing this is the following list comprehension
c = [sum(items) for items in zip(x, y)]
list comprehensions allow you to operate on items in an iterable and return a list. zip allows you to iterate over multiple iterables at the same time. This is a good pattern to look out for as you keep learning python
You are iterating both the lists for following index values : [0,1,2,3].
As the length of both the lists is 3, iterating it upto index value 3, won't make any sense because index value begins from 0.
In the condition for while loop, you should change the condition from i <= len(x) to i < len(x).
I was trying to solve a question and I got into a few obstacles that I failed to solve, starting off here is the question: Codeforces - 817D
Now I tried to brute force it, using a basic get min and max for each segment of the array I could generate and then keeping track of them I subtract them and add them together to get the final imbalance, this looked good but it gave me a time limit exceeded cause brute forcing n*(n+1)/2 subsegments of the array given n is 10^6 , so I just failed to go around it and after like a couple of hours of not getting any new ideas I decided to see a solution that I could not understand anything in to be honest :/ , here is the solution:
#include <bits/stdc++.h>
#define ll long long
int a[1000000], l[1000000], r[1000000];
int main(void) {
int i, j, n;
scanf("%d",&n);
for(i = 0; i < n; i++) scanf("%d",&a[i]);
ll ans = 0;
for(j = 0; j < 2; j++) {
vector<pair<int,int>> v;
v.push_back({-1,INF});
for(i = 0; i < n; i++) {
while (v.back().second <= a[i]) v.pop_back();
l[i] = v.back().first;
v.push_back({i,a[i]});
}
v.clear();
v.push_back({n,INF});
for(i = n-1; i >= 0; i--) {
while (v.back().second < a[i]) v.pop_back();
r[i] = v.back().first;
v.push_back({i,a[i]});
}
for(i = 0; i < n; i++) ans += (ll) a[i] * (i-l[i]) * (r[i]-i);
for(i = 0; i < n; i++) a[i] *= -1;
}
cout << ans;
}
I tried tracing it but I keep wondering why was the vector used , the only idea I got is he wanted to use the vector as a stack since they both act the same(Almost) but then the fact that I don't even know why we needed a stack here and this equation ans += (ll) a[i] * (i-l[i]) * (r[i]-i); is really confusing me because I don't get where did it come from.
Well thats a beast of a calculation. I must confess, that i don't understand it completely either. The problem with the brute force solution is, that you have to calculate values or all over again.
In a slightly modified example, you calculate the following values for an input of 2, 4, 1 (i reordered it by "distance")
[2, *, *] (from index 0 to index 0), imbalance value is 0; i_min = 0, i_max = 0
[*, 4, *] (from index 1 to index 1), imbalance value is 0; i_min = 1, i_max = 1
[*, *, 1] (from index 2 to index 2), imbalance value is 0; i_min = 2, i_max = 2
[2, 4, *] (from index 0 to index 1), imbalance value is 2; i_min = 0, i_max = 1
[*, 4, 1] (from index 1 to index 2), imbalance value is 3; i_min = 2, i_max = 1
[2, 4, 1] (from index 0 to index 2), imbalance value is 3; i_min = 2, i_max = 1
where i_min and i_max are the indices of the element with the minimum and maximum value.
For a better visual understanding, i wrote the complete array, but hid the unused values with *
So in the last case [2, 4, 1], brute-force looks for the minimum value over all values, which is not necessary, because you already calculated the values for a sub-space of the problem, by calculating [2,4] and [4,1]. But comparing only the values is not enough, you also need to keep track of the indices of the minimum and maximum element, because those can be reused in the next step, when calculating [2, 4, 1].
The idead behind this is a concept called dynamic programming, where results from a calculation are stored to be used again. As often, you have to choose between speed and memory consumption.
So to come back to your question, here is what i understood :
the arrays l and r are used to store the indices of the greatest number left or right of the current one
vector v is used to find the last number (and it's index) that is greater than the current one (a[i]). It keeps track of rising number series, e.g. for the input 5,3,4 at first the 5 is stored, then the 3 and when the 4 comes, the 3 is popped but the index of 5 is needed (to be stored in l[2])
then there is this fancy calculation (ans += (ll) a[i] * (i-l[i]) * (r[i]-i)). The stored indices of the maximum (and in the second run the minimum) elements are calculated together with the value a[i] which does not make much sense for me by now, but seems to work (sorry).
at last, all values in the array a are multiplied by -1, which means, the old maximums are now the minimums, and the calculation is done again (2nd run of the outer for-loop over j)
This last step (multiply a by -1) and the outer for-loop over j are not necessary but it's an elegant way to reuse the code.
Hope this helps a bit.
Alright, so I have a small issue:
def common(a,b,c):
a.sort()
b.sort()
c.sort()
i = 0
j = 0
k = 0
common=False
while i<len(a) and j<len(b):
if a[i] == b[j]:
if b[j] == c[k]:
return True
else:
k = k+1
continue
else:
if i == len(a):
j = j+1
else:
i = i+1
return common
a=[3, 1, 5, 10]
b=[4, 2, 6, 1]
c=[5, 3, 1, 7]
print common(a,b,c)
Basically, it has to tell me if there are common elements in the lists. With 1 it works, but if I replace the 1's with 8's, it doesn't work anymore.
Your 'j' never increase, 1 is working because after sort it is the 1st element and doesn't need j to be increased.
My suggestion is convert your lists to sets and check the common elements using intersection(&)
def common(a,b,c):
common = set(a) & set(b) & set(c)
return True if common else False
a=[3, 8, 5, 10]
b=[4, 2, 6, 8]
c=[5, 3, 8, 7]
print common(a,b,c)
Your current algorithm only works if the smallest value in the b list is common to the other lists. If there's a different common value, you'll never find it, because you'll increment i until it is len(a), then quit.
I think you need to change your logic so that you increment the index of the list that points at the smallest value. If a[i] is less than b[j], you need to increment i. If c[k] is less still, you should increment it instead.
What you've programmed is not doing at all what you expect, so you need to rethink your logic. If you look at your loop, you first check if a[0] matches b[0]. Nope, so add to i. Then you compare a[1] to b[0], nope and so on. If nothing matches b[0], you exit the loop without ever checking the other elements of b. It works with 1's in your lists because after you sort, those happen to be in the first position in all three lists.
In any case, this is pretty clunky. There's a much easier way of doing this via set intersection. See this related question.
I have an assignment where I'm given a string S containing the letters 'R' and 'K', for example "RRRRKKKKRK".
I need to obtain the maximum number of 'R's that string could possibly hold by flipping characters i through j to their opposite. So:
for(int x = i; x < j; x++)
{
if S[x] = 'R'
{
S[X] = 'S';
}
else
{
S[X] = 'R';
}
}
However, I can only make the above call once.
So for the above example: "RRRRKKKKRK".
You would have i = 4 and j = 8 which would result in: "RRRRRRRRKR" and you would then output the number of R's in the resulting string: 9.
My code partially works, but there are some cases that it doesn't. Can anyone figure out what is missing?
Sample Input
2
RKKRK
RKKR
Sample Output
4
4
My Solution
My solution which works only for the first case, I don't know what I'm missing to complete the algorithm:
int max_R = INT_MIN;
for (int i = 0; i < s.size(); i++)
{
for (int j = i + 1; j < s.size(); j++)
{
int cnt = 0;
string t = s;
if (t[j] == 'R')
{
t[j] = 'K';
}
else
{
t[j] = 'R';
}
for (int b = 0; b < s.size(); b++)
{
if (t[b] == 'R')
{
cnt++;
if (cnt > max_R)
{
max_R = cnt;
}
}
}
}
}
cout << max_R << endl;
How about turning this into the Maximum subarray problem which has O(n) solution?
Run through the string once, giving 'K' a value of 1, and 'R' a value of -1.
E.g For 'RKRRKKKKRKK' you produce an array -> [-1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1] -> [-1, 1, -2, 4, -1, 2] (I grouped consecutive -1s and 1s to be more clear)
Apply Kadane's algorithm on the generated array. What you get from doing this is the maximum number of 'R's you can obtain from flipping 'K's.
Continuing with the example, you find that the maximum subarray is [4, -1, 2] with a sum of 5.
Now add the absolute value of the negative values outside this subarray with the sum of your maximum subarray to obtain your answer.
In our case, only -1 and -2 are negative and outside the subarray. We get |-1| + |-2| + 5 = 8
Try to carefully think about your solution. Do you understand, what it does?
First, let’s forget that the input file may contain multiple tests, so let’s get rid of the while loop. Now, we have just two for loops. The second one obviously just counts R’s in the processed string. But what does the first one do?
The answer is that the first loop flips all the letters from the second one (i.e. which has index 1) till the end of the string. We can see that in the first testcase:
RKKRK
it is indeed the optimal solution. The string turns into RRRKR and we get four R’s. But in the second case:
RKKR
the string turns into RRRK and we get three R’s. While if we flipped just the letters from 2 to 3 (i.e. indices 1 to 2) we could get RRRR which has four R’s.
So your algorithm always flips letters from index 1 to the end, but this is not always optimal. What can we do? How do we know which letters to flip? Well, there are some smart solutions, but the easiest is to just try all possible combinations!
You can flip all the letters from 0 to 1, count the number of R’s, remember it. Get back to the original string, flip letters from 0 to 2, count R’s, remember it and so on till you flip from 0 to n-1. Then you flip letters from 1 to 2, from 1 to 3, etc. And the answer is the largest value you remembered.
This is horribly inefficient, but this works. After you get more practice in solving algorithmic problems, get back to this task and try to figure out more efficient solutions. (Hint: if you consider building the optimal answer incrementally, that is by going through the string char by char and transforming the optimal solution for the substring s[0..i] into the optimal solution for s[0..i+1] you can arrive to a pretty straightforward O(n^2) algorithm. This can be enhanced to O(n), but this step is slightly more involved.)
Here is the sketch of this solution:
def solve(s):
answer = 0
for i in 0..(n-1)
for j in i..(n-1)
t = copy(s) # we will need the original string later
flip(t, i, j) # flip letters from i to j in t
c = count_R(t) # count R's in t
answer = max(answer, c)
return answer
Not a homework question.
I was going through the questions here and I came across this question.
Someone has answered it. I have tried a lot to understand the recursion used but I am not able to get it. Could someone explain it to me?
Write a function, for a given number, print out all different ways to make this number, by using addition and any number equal to or smaller than this number and greater than zero.
For example, given a = 5, we have the following seven ways to make up 5:
1, 1, 1, 1, 1
1, 4
1, 1, 1, 2
1, 1, 3
2, 3
1, 2, 2
5
The solution from the site is in C++:
void printSeq( int num , int a[] , int len , int s )
{
if( num <= 0 )
{
for( int j = 0 ; j < len ; j++ )
cout << a[ j ] << "," ;
cout << endl;
return;
}
for(int i = s ; i <= num ; i++)
{
a[ len ] = i;
printSeq( num - i , a , len + 1 , i );
}
}
int main()
{
int a[5];
printSeq(5,a,0,1);
cin.get();
return 0;
}
When facing a problem like this it is often a good idea to take a step back from your editor/IDE and think about the problem by drawing out a simple case on a whiteboard. Don't even do pseudo-code yet, just draw out a flowchart of how a simple case (e.g. a = 3) for this problem would turtle all the way down. Also, don't worry about duplicate combinations at first. Try to find a solution which gives you all the desired combinations, then improve your solution to not give you duplicates. In this case, why not look at the manageable case of a = 3? Let me draw a little picture for you. A green checkmark means that we have arrived at a valid combination, a red cross means that a combination is invalid.
As you can see, we start with three empty subcombinations and then build three new subcombinations by appending a number to each of them. We want to examine all possible paths, so we choose 1, 2 and 3 and end up with [1], [2] and [3]. If the sum of the numbers in a combination equals 3, we have found a valid combination, so we can stop to examine this path. If the sum of the numbers in a combination exceeds 3, the combination is invalid and we can stop as well. If neither is the case, we simply continue to build combinations until we arrive at either a valid or invalid solution.
Since your question seems to be primarily about how to work out a recursive solution for this kind of problems and less about specific syntax and you just happened to find a C++ solution I am going to provide a solution in Python (it almost looks like pseudo code and it's what it know).
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
for number in range(1, a + 1): # try each number from 1 to a
if combosum + number <= a: # only proceed if we don't exceed a
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations c that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Let's test the code!
>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
...
[1, 1, 1]
[1, 2]
[2, 1]
[3]
This seems to work fine, another test for a = 5:
>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]
The solution includes all seven combinations we were looking for, but the code still produces duplicates. As you may have noticed, it is not necessary to take a number smaller than the previous chosen number to generate all combinations. So let's add some code that only starts to build an extcombo for numbers which are not smaller than the currently last number in a combination. If the combination is empty, we just set the previous number to 1.
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
lastnumber = combo[-1] if combo else 1 # last number appended
for number in range(lastnumber, a + 1): # try each number between lastnumber and a
if combosum + number <= a:
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Once again, let's test the code!
>>> combo = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]
The presented solution may not be the most efficient one that exists, but hopefully it will encourage you to think recursively. Break a problem down step by step, draw out a simple case for small inputs and solve one problem at a time.
Leaving the solution aside for moment and looking at the problem itself:
Compare this problem to insertion sort for an array(or any recursive algorithm). In insertion sort at any point during the execution we have a part of the array that is sorted and another part that is unsorted. We pick an element from the unsorted part and find it's place in the sorted part, thereby extending the sorted part, making the problem smaller.
In case of this problem, we have a fixed number of elements we can choose from i.e integers 1 to the number in the problem(let's call it N), to be a part of the sequence that sums up to N.
At any point we have collected some numbers that sum up to less than N(say X), reducing the problem to N-X size, also reducing our choices from 1..N to 1..(N-X) for the next recursion.
The solution does the obvious, making each choice from 1 to (N-X) and proceeding recursively till X=N. Every time the algorithm reaches X=N, means a permutation is found.
Note: One problem I see with the solution is that it needs to know the number of permutations that will be found beforehand.
int a[5];
This could cause problems if that value is unknown.