Intuition behind incrementing the iteration variable? - c++

I am solving a question on LeetCode.com:
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, they use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. [The trivial counting sort cannot be used].
For the input: [2,0,2,1,1,0]; the output expected is: [0,0,1,1,2,2].
One of the highly upvoted solutions goes like this:
public void sortColors(vector<int>& A) {
if(A.empty() || A.size()<2) return;
int low = 0;
int high = A.size()-1;
for(int i = low; i<=high;) {
if(A[i]==0) {
// swap A[i] and A[low] and i,low both ++
int temp = A[i];
A[i] = A[low];
A[low]=temp;
i++;low++;
}else if(A[i]==2) {
//swap A[i] and A[high] and high--;
int temp = A[i];
A[i] = A[high];
A[high]=temp;
high--;
}else {
i++;
}
}
}
My question is, why is i incremented when A[i]==0 and A[i]==1 and not when A[i]==2? Using pen and paper, the algorithm just works to give me the answer; but could you please provide some intuition?
Thanks!

This steps through the array and maintains the constraint that the elements 0..i are sorted, and all either 0 or 1. (The 2's that were there get swapped to the end of the array.)
When A[i]==0, you're swapping the element at i (which we just said was 0) with the element at low, which is the first 1-element (if any) in the range 0..i. Hence, after the swap, A[i]==1 which is OK (the constraint is still valid). We can safely move forward in the array now. The same is true if A[i]==1 originally, in which case no swap is performed.
When A[i]==2, you're essentially moving element i (which we just said was 2) to the end of the array. But you're also moving something from the end of the array into element i's place, and we don't know what that element is (because we haven't processed it before, unlike the A[i]==0 case). Hence, we cannot safely move i forward, because the new element at A[i] might not be in the right place yet. We need another iteration to process the new A[i].

That is, because for 0s and 1s, only items left of the current item are handled and those have already been reviewed / sorted. Only for 2s items from the right end of the array are handled, which haven't been looked at yet.
To be more specific: In this specific example only three different states are handled:
the current item being reviewed equals 0: in this case this sorting algorithm just puts this item at the end of all zeros, which have already been sorted (aka A[low]). Also the item which was at A[low] before can only be a 0 or 1 (since they have already sorted) which means you can just swap with the current item and not break the sequence. Now the interesting part: up until now, every item from A[0] over A[low] to A[i] has been already sorted, so the next item which has to be reviewed will be A[i + 1], hence the i++
the current item equals 1: in this case, no swapping has to be done, since all 0s and 1s has already been put in A[0] to A[i - 1] and all 2s have already been put at the end of the array. That means, the next item to be reviewed is A[i + 1], hence the i++
the current item equals 2: in this case, the current item will be put at the end of the array, next to (i.e., to the left of) all the other already sorted 2s (A[high]). The item, which will be swapped from A[high] to A[i] has not been sorted yet and therefor has to be reviewed in the next step, hence th i = i;

Related

Minimum number of elements required to make two bags of at least k weight?

Suppose you are given a number k and an array of objects having some weight. Now your task is to find the minimum number of objects that you can put in two bags such that each bag weigh at least k.
You can only take the objects as whole no breaking is allowed. Also, if an object is put in one bag it cannot be put into the other bag.
This problem seems simple to me. I have done similar problems when you need to fill just one bag. The idea I use is that you visit each object ask yourself what if I put it in the bag and what if I don't? You do this recursively until your desired weight is reached or you have no more objects. Take minimum when calling your recursive function.
However, I am not able to understand how to keep track of all the objects used up in bag 1 so that I don't include in bag 2.
Few Test cases
Desired weight (k) = 4
Number of objects (N) = 1
[10]
Output: -1 (Not possible)
Desired weight (k) = 2
Number of objects (N) = 3
[2,2,2]
Output: 2
I will focus on what you point out as your actual core problem, how to keep track of objects you used in one bag, the other bag or not at all.
Make a list (array, vector, ... whatever container you prefer) and note for each of the objects where you used it - or not.
index
value
meaning
0
0
not used
1
0
not used
2
0
not used
3
1
used in one bag
4
2
used in other bag
From your question it is not clear to me whether all objects have the same weight or different weights given in the input. If the weights are different, then you most likely already have a container for keeping track of the weight of each object. Modifying that container or using a second, very similar one will help you to also store the "used where" information.
I am intentionally not going into detail, because of
How do I ask and answer homework questions?
I don't know if this answers your question or not, but still...
You can do one thing: Initially make two empty arrays, say Bag_1 and Bag_2. As you recurse through all elements one by one, pop that element out of the array and append it to Bag_1 or Bag_2 whichever gives you the optimal solution. If the process is to be done multiple times, then creating a copy of the original array might help, if the length of the array is reasonable.
Here is the pseudo code for the program without dynamic programing.
sort(a, a+n); // Sort the array of objects having weight
int sum = a[n-1], count = -1; //Initialise sum and count
unordered_set<int>log; // Create an unordered set to store logs (Unordered set will not add repetitive values in the log thus decreasing time complexity)
log.insert(a[n-1]); // insert last element int log initially
for(int i = n-2; i >=0; i--) {
sum += a[i]; //increment the sum
unordered_set<int>temp; //Create a temporary log that will be mapped to main log at the end.
temp.insert(a[i]); //insert the sum to temp log
for (auto it = log.begin(); it != log.end(); ++it) { //loop over all logs seen till now
temp.insert(*it + a[i]); // Add current sum to each of them and insert it to temp log thus creating all possible combinations.
if((a[i] + *it >= k) && (sum - a[i] - *it >= k)) { //Condition to check if bags have been filled with at least k weight.
count = n-i; // update the current count. This will be the ans.
break;
}
if(a[i] >= k && sum - a[i] >= k) {
count = n-i;
break;
}
}
if(count != -1) { //Condition to check if it's not possible to make such a combination.
break;
}
log.insert(temp.begin(), temp.end()); // add all temp to main log.
}
cout << count << endl; //print ans.

Largest rectangles in histogram

I'm working on the below algorithm puzzle and here is the detailed problem statement.
Find the largest rectangle of the histogram; for example, given histogram = [2,1,5,6,2,3], the algorithm should return 10.
I am working on the below version of code. My question is, I think i-nextTop-1 could be replaced by i-top, but in some test cases (e.g. [2,1,2]), they have different results (i-nextTop-1 always produces the correct results). I think logically they should be the same, and wondering in what situations i-nextTop-1 is not equal to i-top
class Solution {
public:
int largestRectangleArea(vector<int>& height) {
height.push_back(0);
int result=0;
stack<int> indexStack;
for(int i=0;i<height.size();i++){
while(!indexStack.empty()&&height[i]<height[indexStack.top()]){
int top=indexStack.top();
indexStack.pop();
int nextTop=indexStack.size()==0?-1:indexStack.top();
result=max((i-nextTop-1)*height[top],result);
}
indexStack.push(i);
}
return result;
}
};
The situations where i-nextTop-1 != i-top occur are when the following is true:
nextTop != top-1
This can be seen by simply rearranging terms in the inequality i-nextTop-1 != i-top.
The key to understanding when this occurs lies in the following line within your code, in which you define the value of nextTop:
int nextTop = indexStack.size() == 0 ? -1 : indexStack.top();
Here, you are saying that if indexStack is empty (following the pop() on the previous line of code), then set nextTop to -1; otherwise set nextTop to the current indexStack.top().
So the only times when nextTop == top-1 are when
indexStack is empty and top == 0, or
indexStack.top() == top - 1.
In those cases, the two methods will always agree. In all other situations, they will not agree, and will produce different results.
You can see what is happening by printing the values of i, nextTop, (i - top), (i - nextTop - 1), and result for each iteration at the bottom of the while loop. The vector {5, 4, 3, 2, 1} works fine, but { 1, 2, 3, 4, 5} does not, when replacing i-nextTop-1 with i-top.
Theory of the Algorithm
The outer for loop iterates through the histogram elements one at a time. Elements are pushed onto the stack from left to right, and upon entry to the while loop the top of stack contains the element just prior to (or just to the left of) the current element. (This is because the current element is pushed onto the stack at the bottom of the for loop, right before looping back to the top.)
An element is popped off the stack within the while loop, when the algorithm has determined that the best possible solution that includes that element has already been considered.
The inner while loop will keep iterating as long as height[i] < height[indexStack.top()], that is, as long as the the height of the current element is less than the height of the element on the top of the stack.
At the start of each iteration of the while loop, the elements on the stack represent all of the contiguous elements to the immediate left of the current element, that are larger than the current element.
This allows the algorithm to calculate the area of the largest rectangle to the left of and including the current element. This calculation is done in the following two lines of code:
int nextTop = indexStack.size() == 0 ? -1 : indexStack.top();
result = max((i - nextTop - 1) * height[top], result);
Variable i is the index of the current histogram element, and represents the rightmost edge of the rectangle being currently calculated.
Variable nextTop represents the index of the leftmost edge of the rectangle.
The expression (i - nextTop - 1) represents the horizontal width of the rectangle. height[top] is the vertical height of the rectangle, so the result is the product of these two terms.
Each new result is the larger of the new calculation and the previous value for result.

Algorithm that sorts a permutation

I am stuck at this problem:
Given a permutation P of {0,1,2,...,n-1}
(Here n = P . length)
Explain why the following algorithm sorts the permutation in increasing order and give a worst case scenario (pseudo-code)
PermutationSort(P)
for i = 0 to P.length - 1
while(P[i] != i)
t = P[i]
exchange P[i] with P[t]
(C++ code)
void PermutationSort(int P[], int len)
{
for(int i = 0; i < len; i++)
while(P[i] != i)
{
int tmp;
tmp = P[i];
P[i] = P[tmp];
P[tmp] = tmp;
}
}
I am totally don't know why it sorts the permutation P.
I've sat on this problem all day and I'm still don't get why it sorts the permutation.
what "exchange P[i] with P[P[i]]" does and why we will ultimately get P[i] = i which will then terminate the inner loop?
Thanks for any hint or help.
First, note that, if you start at any arbitrary element k, and repeatedly apply the permutation P to obtain a chain like (k → P(k) → P(P(k)) → P(P(P(k))) → ...), you will (since the total number of elements in the permutation P is finite, and a permutation never maps two inputs to the same output) eventually end up back at k. The cycle of elements (k →P(k) → P(P(k)) → ... → k) is called the orbit of k under P, and every element of the permutation belongs to exactly one such cycle.
Now, let's see what the inner loop of your algorithm does to the cycle containing the element i.
If P(i ) = i, i.e. if this element is already where it belongs, then the inner loop just does nothing and the outer loop moves on to the next element. If P(i ) ≠ i, however, the inner loop sets t = P(i ), and then modifies the permutation P to swap P(i ) and P(t ).
After the swap, the new value of P(t ) is the old value of P(i ), i.e. t. Thus, the element t is now correctly sorted, while P(i ) now contains the old value of P(t ) = P(P(i )), i.e. the (former) next element in the cycle. If this is i, then there are no more elements left in the cycle, and the inner loop ends; otherwise, the cycle containing i has shrunk by one element, and the inner loop repeats.
Thus, at the end of the inner loop, all the elements that used to be part of the same cycle as i (including i itself) have been moved to their correct locations, and thus removed from the cycle, while the rest of the permutation has not been changed.
Since the outer loop iterates over every element in the permutation, it is also guaranteed to visit every cycle at least once. Of course, we're modifying the permutation in the inner loop, but that's all right, since the inner loop can never create new cycles (of more than one element); it can only break up existing ones.
Thus, the first time each cycle in the original permutation gets visited by the outer loop, the inner loop sorts and breaks up that cycle; on subsequent visits to the same original cycle, that cycle has already been sorted, and so the inner loop simply does nothing.
This observation should also allow you to bound the number of times the inner loop can be executed, and thus to determine the time complexity of the algorithm.

How do I find the mode of a sorted array?

I need to write a function to find the mode of a array. I'm not good at coming up with algorithms however and I'm hoping someone else knows how to do this.
I know the size of the array and the values in each element, and I have the array sorted from least to greatest.
array would be passed to the mode function like
mode = findMode(arrayPointer, sizePointer);
UPDATE:
After reading the comments I've tried this
int findMode(int *arrPTR, const int *sizePTR)
{
int most_found_element = arrPTR[0];
int most_found_element_count = 0;
int current_element = arrPTR[0];
int current_element_count = 0;
int count;
for (count = 0; count < *sizePTR; count++)
{
if(count == arrPTR[count])
current_element_count++;
else if(current_element_count > most_found_element)
{
most_found_element = current_element;
most_found_element_count = current_element_count;
}
current_element = count;
current_element_count=1;
}
return most_found_element;
}
I'm still having problems grasping this algorithm though if anyone can sort me out.
I've never used vectors so don't really understand the other examples.
You have almost everything.
You can take advantage of the fact that the array is sorted.
Just go through the array keeping track of both the current equal consecutive numbers, and the greatest number of equal consecutive numbers you have found until that point (and which number produced it). In the end you will have the greatest number of equal consecutive numbers and which number produced it. That will be the mode.
Note: For a solution which does not require the array to be sorted, see for example one based in the histogram approach in a related question.
set most_found_element to the first element in the array
set most_found_element_count to zero
set current_element to the first element of the array
set current_element_count to zero
for each element e in the array
if e is the same as the current_element
increase current_element_count by one
else
if current_element_count is greater than most_found_element_count
set most_found_element to the current_element
set most_found_element_count to current_element_count
set current_element to e
set current_element_count to one
if current_element_count is greater than most_found_element_count
set most_found_element to the current_element
set most_found_element_count to current_element_count
print most_found_element and most_found_element_count
I thought the names would explain it, but here we go:
When we start, no element has been found the most times
so the "high-score" count is zero.
Also, the "current" value is the first, but we haven't looked at it yet
so we've seen it zero times so far
Then we go through each element one by one
if it's the same as "current" value,
then add this to the number of times we've seen the current value.
if we've reached the next value, we've counted all of the "current" value.
if there was more of the current value than the "high-score"
then the "high-score" is now the current value
and since we reached a new value
the new current value is the value we just reached
Now that we've seen all of the elements, we have to check the last one
if there was more of the current value than the "high-score"
then the "high-score" is now the current value
Now the "high-score" holds the one that was in the array the most times!
Also note: my original algorithm/code had a bug, we have to do an extra check of "current" after the loop ends, as it never finds "the one after the last".
Hints:
Q: How do you define the mode?
A: The number whose count is greatest within the array.
Q: How do you count numbers in an ordered array?
A: Iterate through the array, and while the next item is equal to the previous, increment the count for that value.
Q: If the count of the previous value is less than the count of the current value, then can the previous value be the mode?
A: No
If the input array is sorted, here is the same approach as described in other answers but implemented in a different way, a better and easy to understand way.
Run a loop over the input array.
Keep global mode value and mode count.
Run a sliding window till you find equal elements.
If local equal element count is greater than global mode count, then update global mode and mode count.
Here is working and tested code in C++.
int mode(vector<int> a, int N)
{
int mode = a[0];
int mode_count = 1;
int i = 0;
while (i < N - 1) {
int cur = a[i];
int cur_count = 1;
while (a[i] == a[i + 1]) {
i++;
cur_count++;
}
if (cur_count > mode_count) {
mode_count = cur_count;
mode = a[i];
}
i++;
}
return mode;
}

Is this a shell sort or an insertion sort?

I'm just starting to learn about sorting algorithms and found one online. At first i thought it was a shell sort but it's missing that distinct interval of "k" and the halving of the array so i'm not sure if it is or not. My second guess is an insertion sort but i'm just here to double check:
for(n = 1; n < num; n++)
{
key = A[n];
k = n;
while((k > 0) && (A[k-1] > key))
{
A[k] = A[k-1];
k = k-1;
}
A[k] = key;
}
Also if you can explain why that'd be helpful as well
Shell Sort consists of many insertion sorts that are performed on sub-arrays of the original array.
The code you have provided is insertion sort.
To get shell sort, it would be roughly having other fors around your code changing h (that gap in shell sort) and starting index of the sub-array and inside, instead of moving from k to k-1, you move from k to k+h (or k-h depending on which direction you do the insertion sort)
I think you're right, that does look a lot like an insertion sort.
This fragment assumes A[0] is already inserted. If n == 0, then the k > 0 check will fail and execution will continue at A[k] = key;, properly storing the first element into the array.
This fragment also assumes that A[0:n-1] is already sorted. It inspects A[n] and starts scanning the array backward, moving forward one place every element that is larger than the original A[n] key.
Once the scanning encounters an element less than or equal to the key, it inserts it in that location.
It's called insertion sort because the line A[k] = key inserts the current value in the correct position in the partially sorted array.