Working on below algorithm puzzle of finding minimum number of jumps. Posted detailed problem statement and two code versions to resolve this issue. I have did testing and it seems both version works, and my 2nd version is an optimized version of version one code, which makes i starts from i=maxIndex, other than continuous increase, which could save time by not iteration all the slots of the array.
My question is, wondering if my 2nd version code is 100% correct? If anyone found any logical issues, appreciate for pointing out.
Problem Statement
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
First version code
class Solution {
public:
int jump(vector<int>& nums) {
int i = 0, n = nums.size(), step = 0, end = 0, maxend = 0;
while (end < n - 1) {
step++;
for (;i <= end; i++) {
maxend = max(maxend, i + nums[i]);
if (maxend >= n - 1) return step;
}
if(end == maxend) break;
end = maxend;
}
return n == 1 ? 0 : -1;
}
};
2nd version code
class Solution {
public:
int jump(vector<int>& nums) {
int i = 0, n = nums.size(), step = 0, end = 0, maxend = 0;
int maxIndex = 0;
while (end < n - 1) {
step++;
for (i=maxIndex;i <= end; i++) {
if ((i + nums[i]) > maxend)
{
maxend = i + nums[i];
maxIndex = i;
}
if (maxend >= n - 1) return step;
}
if(end == maxend) break;
end = maxend;
}
return n == 1 ? 0 : -1;
}
};
thanks in advance,
Lin
The best way is always to test it. A human cannot always think about special cases but a automated test can cover the most of speciale cases. If you think that your first version works well, you can compare the result of the first with the second one. Here an exemple:
/*
* arraySize : array size to use for the test
* min : min jump in the array
* max : max jump in the array
*/
void testJumps(int arraySize, int min, int max){
static int counter = 0;
std::cout << "-----------Test " << counter << "------------" << std::endl;
std::cout << "Array size : " << arraySize << " Minimum Jump : " << min << " Max Jump" << max << std::endl;
//Create vector with random numbers
std::vector<int> vecNumbers(arraySize, 0);
for(unsigned int i = 0; i < vecNumbers.size(); i++)
vecNumbers[i] = rand() % max + min;
//Value of first function
int iVersion1 = jump1(vecNumbers);
//Second fucntion
int iVersion2 = jump2(vecNumbers);
assert(iVersion1 == iVersion2);
std::cout << "Test " << counter << " succeeded" << std::endl;
std::cout << "-----------------------" << std::endl;
counter++;
}
int main()
{
//Two test
testJumps(10, 1, 100);
testJumps(20, 10, 200);
//You can even make a loop of test
//...
}
Related
I sorta need help getting the minimum I keep getting thirteen can some
one help me out? The issue I believe is I'm not showing the formula for low n line I'm confused I have tried to switch out the values for the array and I can't figure it out just if someone could explain to m please.
#include <iostream>
using namespace std;
int getHighest(int numArray[], int numElements);
int getLowest(int numArray[], int numelements);
int main()
{
int numbers[4] = { 13, 2, 40, 25 };
cout << "The highest number in the array is " << getHighest(numbers, 4) << "." << endl;
cout << "The lowest number in the array is "<< getLowest(numbers,0) << "." << endl;
return 0;
}
int getHighest(int numArray[], int numElements)
{
int high = numArray[0];
for (int sub = 1; sub < numElements; sub += 1)
if (numArray[sub] > high)
high = numArray[sub];
return high;
}
int getLowest(int numArray[], int numElements)
{
int low = numArray[0];
for (int sub = 0; sub >= numElements; sub--)
if (numArray[sub]< low)
low = numArray[sub];
return low;
}
Concerning getLowest():
There is actually no need to iterate backwards. It could be done like in getHighest(). However, say this is a requirement for teaching…
The test array is
int numbers[4] = { 13, 2, 40, 25 };
// indices: 0 1 2 3
// number of elements: 4
A loop to iterate backwards has to start with index numElements - 1 (3 in this case) and to stop at index 0.
for (int sub = numElements - 1; sub >= 0; sub--)
Nevertheless, this will check the last element which is already assigned before the loop. (getHighest() starts the loop with the 2nd element for this reason: for (int sub = 1;…) Thus, this can be corrected to:
for (int sub = numElements - 2; sub >= 0; sub--)
This is the corrected example:
int getLowest(int numArray[], int numElements)
{
int low = numArray[0];
for (int sub = 1; sub < numElements; ++sub)
{
//std::cout<<"checking: "<<numArray[sub]<<"with"<<low<<std::endl;
if (numArray[sub]< low){
low = numArray[sub];
}
}
return low;
}
The complete working example is here
Also note in your given example you have made a mistake at:
cout << "The lowest number in the array is "<< getLowest(numbers,0) << "." << endl;
Instead of passing 0 as the second argument you should pass 4 as i did here.
Another mistake was the initial value of varaible sub in the for loop. You started with sub = 0 instead of sub = numelements - 1.
That is the for loop should have looked like:
//note in the next line we have sub >=1 instead of sub>=0 becuase you have already stored numArray[0] in variable low
for (int sub = numElements -1; sub >=1; --sub)
{
...other code here
}
I am trying to implement shell sorting algorithm myself. I wrote my own code and didn't watch to any code samples only watch the video of algorithm description
My sort works but very slow (bubble sort 100 items - 0.007 s; shell sort 100 items - 4.83 s), how is it possible to improve it?
void print(vector<float>vec)
{
for (float i : vec)
cout << i << " ";
cout << "\n\n";
}
void Shell_sorting(vector<float>&values)
{
int swapping = 0;
int step = values.size();
clock_t start;
double duration;
start = clock();
while (step/2 >= 1)
{
step /= 2;
for (int i = 0; i < values.size()-step; i++)
{
if ((i + step < values.size()))
{
if ((values[i + step] < values[i]))
{
swap(values[i], values[i + step]);
print(values);
++swapping;
int c = i;
while (c - step > 0)
{
if (values[c] < values[c - step])
{
swap(values[c], values[c - step]);
print(values);
++swapping;
c -= step;
}
else
break;
}
}
}
else
break;
}
}
duration = (clock() - start) / (double)CLOCKS_PER_SEC;
print(values);
cout << swapping << " " << duration;
print(values);
}
A better implementation could be:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec = {
726,621,81,719,167,958,607,130,263,108,
134,235,508,407,153,162,849,923,996,975,
250,78,460,667,654,62,865,973,477,912,
580,996,156,615,542,655,240,847,613,497,
274,241,398,84,436,803,138,677,470,606,
226,593,620,396,460,448,198,958,566,599,
762,248,461,191,933,805,288,185,21,340,
458,592,703,303,509,55,190,318,310,189,
780,923,933,546,816,627,47,377,253,709,
992,421,587,768,908,261,946,75,682,948,
};
std::vector<int> gaps = {5, 2, 1};
int j;
for (int gap : gaps) {
for (int i = gap; i < vec.size(); i++)
{
j = i-gap;
while (j >= 0) {
if (vec[j+gap] < vec[j])
{
int temp = vec[j+gap];
vec[j+gap] = vec[j];
vec[j] = temp;
j = j-gap;
}
else break;
}
}
}
for (int item : vec) std::cout << item << " " << std::endl;
return 0;
}
I prefer to use a vector to store gap data so that you do not need to compute the division (which is an expansive operation). Besides, this choice, gives your code more flexibility.
the extern loop cycles on gap values. Once choosen the gap, you iterate over your vector, starting from vec[gap] and explore if there are elements smaller then it according to the logic of the Shell Sort.
So, you start setting j=i-gap and test the if condition. If it is true, swap items and then repeat the while loop decrementing j. Note: vec[j+gap]is the element that in the last loop cycle was swapped. If the condition is true, there's no reason to continue in the loop, so you can exit from it with a break.
On my machine, it took 0.002s calculated using the time shell command (the time includes the process of printing numbers).
p.s. to generate all that numbers and write them in the array, since i'm too lazy to write a random function, i used this link and then i edited the output in the shell with:
sed -e 's/[[:space:]]/,/g' num | sed -e 's/$/,/'
What I understand already
I understand that median of medians algorithm(I will denote as MoM) is a high constant factor O(N) algorithm. It finds the medians of k-groups(usually 5) and uses them as the next iteration's sets to find medians of. The pivot after finding this will be between 3/10n and 7/10n of the original set, where n is the number of iterations it took to find the one median base case.
I keep getting a segmentation fault when I run this code for MoM, but I'm not sure why. I've debugged it and believe that the issue lies with the fact that I'm calling medianOfMedian(medians, 0, medians.size()-1, medians.size()/2);. However, I thought that this was logically sound since we were supposed to recursively find the median by calling itself. Perhaps my base case isn't correct? In a tutorial by YogiBearian on youtube(a stanford professor, link: https://www.youtube.com/watch?v=YU1HfMiJzwg ), he did not state any extra base case to take care of the O(N/5) operation of recursion in MoM.
Complete Code
Note: Per suggestions, I have added a base case and used .at() function by vectors.
static const int GROUP_SIZE = 5;
/* Helper function for m of m. This function divides the array into chunks of 5
* and finds the median of each group and puts it into a vector to return.
* The last group will be sorted and the median will be found despite its uneven size.
*/
vector<int> findMedians(vector<int>& vec, int start, int end){
vector<int> medians;
for(int i = start; i <= end; i+= GROUP_SIZE){
std::sort(vec.begin()+i, min(vec.begin()+i+GROUP_SIZE, vec.end()));
medians.push_back(vec.at(min(i + (GROUP_SIZE/2), (i + end)/2)));
}
return medians;
}
/* Job is to partition the array into chunks of 5(subject to change via const)
* And then find the median of them. Do this recursively using select as well.
*/
int medianOfMedian(vector<int>& vec, int start, int end, int k){
/* Acquire the medians of the 5-groups */
vector<int> medians = findMedians(vec, start, end);
/* Find the median of this */
int pivotVal;
if(medians.size() == 1)
pivotVal = medians.at(0);
else
pivotVal = medianOfMedian(medians, 0, medians.size()-1, medians.size()/2);
/* Stealing a page from select() ... */
int pivot = partitionHelper(vec, pivotVal, start, end);
cout << "After pivoting with the value " << pivot << " we get : " << endl;
for(int i = start; i < end; i++){
cout << vec.at(i) << ", ";
}
cout << "\n\n" << endl;
usleep(10000);
int length = pivot - start + 1;
if(k < length){
return medianOfMedian(vec, k, start, pivot-1);
}
else if(k == length){
return vec[k];
}
else{
return medianOfMedian(vec, k-length, pivot+1, end);
}
}
Some extra functions for helping unit test
Here are some unit tests that I wrote for these 2 functions. Hopefully they help.
vector<int> initialize(int size, int mod){
int arr[size];
for(int i = 0; i < size; i++){
arr[i] = rand() % mod;
}
vector<int> vec(arr, arr+size);
return vec;
}
/* Unit test for findMedians */
void testFindMedians(){
const int SIZE = 36;
const int MOD = 20;
vector<int> vec = initialize(SIZE, MOD);
for(int i = 0; i < SIZE; i++){
cout << vec[i] << ", ";
}
cout << "\n\n" << endl;
vector<int> medians = findMedians(vec, 0, SIZE-1);
cout << "The 5-sorted version: " << endl;
for(int i = 0; i < SIZE; i++){
cout << vec[i] << ", ";
}
cout << "\n\n" << endl;
cout << "The medians extracted: " << endl;
for(int i = 0; i < medians.size(); i++){
cout << medians[i] << ", ";
}
cout << "\n\n" << endl;
}
/* Unit test for medianOfMedian */
void testMedianOfMedian(){
const int SIZE = 30;
const int MOD = 70;
vector<int> vec = initialize(SIZE, MOD);
cout << "Given array : " << endl;
for(int i = 0; i < SIZE; i++){
cout << vec[i] << ", ";
}
cout << "\n\n" << endl;
int median = medianOfMedian(vec, 0, vec.size()-1, vec.size()/2);
cout << "\n\nThe median is : " << median << endl;
cout << "As opposed to sorting and then showing the median... : " << endl;
std::sort(vec.begin(), vec.end());
cout << "sorted array : " << endl;
for(int i = 0; i < SIZE; i++){
if(i == SIZE/2)
cout << "**";
cout << vec[i] << ", ";
}
cout << "Median : " << vec[SIZE/2] << endl;
}
Extra section about the output that I'm getting
Given array :
7, 49, 23, 48, 20, 62, 44, 8, 43, 29, 20, 65, 42, 62, 7, 33, 37, 39, 60, 52, 53, 19, 29, 7, 50, 3, 69, 58, 56, 65,
After pivoting with the value 5 we get :
23, 29, 39, 42, 43,
After pivoting with the value 0 we get :
39,
Segmentation Fault: 11
It seems all right and dandy until the segmentation fault. I'm confident that my partition function works as well(was one of the implementations for the leetcode question).
Disclaimer: This is not a homework problem, but rather my own curiosity about the algorithm after I used quickSelect in a leetcode problem set.
Please let me know if my question proposed requires more elaboration for MVCE, thanks!
EDIT: I figured out that the recursion partition scheme is wrong in my code. As Pradhan has pointed out - I somehow have empty vectors which lead to the start and end being 0 and -1 respectively, causing me to have segmentation fault from an infinite loop of calling it. Still trying to figure this part out.
MoM always calls itself (to compute pivot), and thus exhibits infinite recursion. This violates the "prime directive" of recursive algorithms: at some point, the problem is "small" enough to not need a recursive call.
Correct Implementation
With the help of Scott's hint, I was able to give a correct implementation of this median of medians algorithm. I fixed it and realized that the main idea that I had was correct, but there were a couple errors:
My base case should be for subvectors in the size of <=5.
There were some small subtleties about whether the last number(variable end), in this case should be considered to be included or as the upper bound less than. In this implementation below I made it the upper bound less than definition.
Here it is below. I also accepted Scott's answer - thank you Scott!
/* In case someone wants to pass in the pivValue, I broke partition into 2 pieces.
*/
int pivot(vector<int>& vec, int pivot, int start, int end){
/* Now we need to go into the array with a starting left and right value. */
int left = start, right = end-1;
while(left < right){
/* Increase the left and the right values until inappropriate value comes */
while(vec.at(left) < pivot && left <= right) left++;
while(vec.at(right) > pivot && right >= left) right--;
/* In case of duplicate values, we must take care of this special case. */
if(left >= right) break;
else if(vec.at(left) == vec.at(right)){ left++; continue; }
/* Do the normal swapping */
int temp = vec.at(left);
vec.at(left) = vec.at(right);
vec.at(right) = temp;
}
return right;
}
/* Returns the k-th element of this array. */
int MoM(vector<int>& vec, int k, int start, int end){
/* Start by base case: Sort if less than 10 size
* E.x.: Size = 9, 9 - 0 = 9.
*/
if(end-start < 10){
sort(vec.begin()+start, vec.begin()+end);
return vec.at(k);
}
vector<int> medians;
/* Now sort every consecutive 5 */
for(int i = start; i < end; i+=5){
if(end - i < 10){
sort(vec.begin()+i, vec.begin()+end);
medians.push_back(vec.at((i+end)/2));
}
else{
sort(vec.begin()+i, vec.begin()+i+5);
medians.push_back(vec.at(i+2));
}
}
int median = MoM(medians, medians.size()/2, 0, medians.size());
/* use the median to pivot around */
int piv = pivot(vec, median, start, end);
int length = piv - start+1;
if(k < length){
return MoM(vec, k, start, piv);
}
else if(k > length){
return MoM(vec, k-length, piv+1, end);
}
else
return vec[k];
}
This is my code for binary search, and n = no of elements in array
// Binary Search
// BUG: not working for n = 2
#include <iostream>
int main() {
const int n = 1;
int newlist[n];
std::cout << "Enter " << n;
std::cout << " elements in increasing order:\n";
for( int i = 0; i < n; ++i ) {
std::cin >> newlist[i];
}
int pos = 0, num;
std::cout << "Enter number:\n";
std::cin >> num;
std::cout << '\n';
int imin = 0, imax = n-1;
int imid = (n - 1)/2;
for( int i = 0; i < n; ++i ) {
imid = (imin + imax) / 2;
if( newlist[imid] == num ) {
pos = imid;
}
else if( newlist[imid] < num ) {
imin = imid+1;
}
else {
imax = imid-1;
}
}
if( pos != 0 ) {
std::cout << "Found at " << pos+1;
}
else {
std::cout << "Not found!\n";
}
return 0;
}
It does work for n > 2, but fails to give correct output for n <= 2, ie, gives Not found! output even for elements that were found.
I think one way would be to have a separate implementation for n <= 2, but that will become cumbersome! Please help.
Set your pos operator to -1 rather than 0. 0 represents your first index and since you output that the element has not been found for pos == 0 condition, your code is failing. You should set pos to -1 initially and check that itself for not found condition, if an element is found at pos = 0, that means the element exists at the first index.
First pos equal to 0 is correct value. Therefore set pos to -1 at the beginning and compare to -1 (or more commonly >= 0) when checking whether it was found.
Secondly, there are few items that should be changed because right now it's not that much binary search:
There is no reason to initialize mid before the loop, it's just temporary variable with the scope in loop block.
The condition for exiting the search is min > max, you don't need any additional counter, as it would run the loop always n times even if the value didn't exist. So change to while (min <= max) { ...
Last but not least, once you find the item, exit the loop immediately by break statement.
I don't think a for-loop is the control structure to go for here, because you want to finish when you've either found the correct item or when imin and imax are non-sensical.
In the implementation given, you don't even stop the loop when you have found the item and just confirm the found item "n-(number of iterations until item was found)" times.
Furthermore, with C++ arrays and vectors being 0-based, having position == 0 as the marker for "not found" is a bad idea; you could instead use an item from http://en.cppreference.com/w/cpp/types/numeric_limits, or n (since the indices go from 0 to n-1).
In theory, you could use pointer arithmetic to make your array 1-based, and I am assuming you haven't; I wouldn't recommend it. However, you're code snipped is missing the actual definition of the list.
I'm trying to write a program for university. The goal of the program is to make a nurse schedule for a hospital. However, i'm really stuck for the moment. Below you can find one function of the program.
The input for the function is a roster which consists of the shift each nurse has to perform on each day. In this example, we have 32 rows (32 nurses) and 28 columns (representing 28 days). Each cell contains a number from 0 to 6, indicating a day off (0) or a certain shift (1 to 6).
The function should calculate for each day, how many nurses are scheduled for a certain shift. For example, on the first day, there are 8 nurses which perform shift 2, 6 shift 3 and so forth. The output of the function is a double vector.
I think the function is mostly correct but when I call it for different rosters the program always gives the first roster gave.
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> nurses_per_shift;
int nbr_nurses_free = 0;
int nbr_nurses_shift1 = 0;
int nbr_nurses_shift2 = 0;
int nbr_nurses_shift3 = 0;
int nbr_nurses_shift4 = 0;
int nbr_nurses_shift5 = 0;
int nbr_nurses_shift6 = 0;
for (int j = 0; j < get_nbr_nurses(); j++)
{
if (roster1[j][i] == 0)
nbr_nurses_free += 1;
if (roster1[j][i] == 1)
nbr_nurses_shift1 += 1;
if (roster1[j][i] == 2)
nbr_nurses_shift2 += 1;
if (roster1[j][i] == 3)
nbr_nurses_shift3 += 1;
if (roster1[j][i] == 4)
nbr_nurses_shift4 += 1;
if (roster1[j][i] == 5)
nbr_nurses_shift5 += 1;
if (roster1[j][i] == 6)
nbr_nurses_shift6 += 1;
}
nurses_per_shift.push_back(nbr_nurses_shift1);
nurses_per_shift.push_back(nbr_nurses_shift2);
nurses_per_shift.push_back(nbr_nurses_shift3);
nurses_per_shift.push_back(nbr_nurses_shift4);
nurses_per_shift.push_back(nbr_nurses_shift5);
nurses_per_shift.push_back(nbr_nurses_shift6);
nurses_per_shift.push_back(nbr_nurses_free);
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
}
Here you can see the program:
Get_shift_assignment() and schedule_LD are other rosters.
void test_schedule_function()
{
calculate_nbr_nurses_per_shift(schedule_LD);
calculate_nbr_nurses_per_shift(get_shift_assignment());
calculate_coverage_deficit();
}
One more function you need to fully understand the problem is this one:
void calculate_coverage_deficit()
{
int deficit = 0;
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> deficit_day;
for (int j = 0; j < get_nbr_shifts(); j++)
{
deficit = get_staffing_requirements()[j] - nbr_nurses_per_shift_per_day[i][j];
deficit_day.push_back(deficit);
}
nurses_deficit.push_back(deficit_day);
}
cout << "Day 1, shift 1: there is a deficit of " << nurses_deficit[0][0] << " nurses." << endl;
cout << "Day 1, shift 2: there is a deficit of " << nurses_deficit[0][1] << " nurses." << endl;
cout << "Day 1, shift 3: there is a deficit of " << nurses_deficit[0][2] << " nurses." << endl;
cout << "Day 1, shift 4: there is a deficit of " << nurses_deficit[0][3] << " nurses." << endl;
}
So the problem is that each time I run this program it always gives me the deficits of the first roster. In this case, this is Schedule_LD. When I first run the function with input roster get_shift_assignment() than he gives me the deficits for that roster.
Apparently the nbr_nurses_per_shift_per_day[][] vector is not overwritten the second time I run the function and I don't know how to fix this... Any help would be greatly appreciated.
Let me try to summarize the comments:
By using global variables to return values from your functions it is very likely, that you forgot to remove older results from one or more of your global variables before calling functions again.
To get around this, return your results from the function instead.
Ex:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<int> nbr_nurses_per_shift_per_day; // Create the result vector
... // Do your calculations
return nbr_nurses_per_shift_per_day;
}
or if you do not want to return a vector:
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1, vector<vector<int>> nbr_nurses_per_shift_per_day)
{
... // Do your calculations
}
But clearly, the first variant is a lot less error-prone (in the second example you can forget to clear nbr_of_nurses again) and most compilers will optimize the return nbr_nurses_per_shift_per_day so the whole vector does not get copied.
The second possible issue is that ´get_nbr_days()´ might return numbers that are larger or smaller than the actual size of your vector. To work around this, use either the size() method of vector or use iterators instead.
Your first function would then look like this:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<vector<int>> nbr_nurses_per_shift_per_day;
for (vector<vector<int>>::iterator shiftsOnDay = roster1.begin(); shiftsOnDay != roster1.end(); ++shiftsOnDay)
{
vector<int> nurses_per_shift(6, 0); // Create vector with 6 elements initialized to 0
for (vector<int>::iterator shift = shiftsOnDay->begin(); shift != shiftsOnDay->end(); ++shift)
{
if (*shift == 0)
nurses_per_shift[5]++;
else
nurses_per_shift[*shift - 1]++; // This code relies on shift only containing meaningful values
}
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
return nbr_nurses_per_shift_per_day;
}