*Audio knowledgeable people please read!* I am having so much trouble with my audio setup. It's definitely an issue, but I'm not exactly sure what the source of the problem is. I've heard that it could be mic placement, mic hardware (I'm using a SpeechWare FlexyMike), or not equalizing/compressing properly. If you have recommendations or better yet if you are willing to troubleshoot with me, please reach out! I want to get this fixed to improve the quality of my videos.
@@mCoding Would recommend getting a studio mic, like a blue yeti or something on a boom arm, it often has way better quality and control of the sound than normal microphones :)
Oh, I just made a new array that stores the count of each number at that index, i.e. the occurrences of the number '1' would be stored in count[1], then I just find the first one that is 0. I thought that was quite elegant until I saw this. Excellent solution!
Glad you think so! Unfortunately in real code the other solution is likely more useful because this kind of function should really not be modifying its argument... But a problem's a problem!
@@mCoding if you instantiate a second vector with zeros and write the numbers in there you can just scan that for a zero I guess. So it doesn't seem like the inplace overriding is inherent to this algorithm
@@mCoding this actually should not matter. At every point each element of the array is either the original number or its place. Each element only ever changes to be its place if at all. So if two parallel branches jump to the same place, one of them will take the number and modify it, and the other will see that the number is the same and stop. Then you just need to have a number that is points to the first number which no thread dealt with yet and then you can have a pool of however many threads you want doing the work.
I'd solve this using DSU which would use O(n * alpha(n)) time and O(n) extra space. Every number in the array that we care about merges i-1 and i in the DSU, then we just return the size corresponding to the 0th set. This may run worse because of the alpha term + the extra O(n) memory, but I think this would be another cool solution for this problem :)
Hey! This would work with a few caveats. 1. You need to make sure you ignore negative numbers, otherwise the 0th disjoint set could be for a range of negative numbers. 2. You would need to check for the special case that the 0th disjoint set doesn't start at 1, in which case the answer is 1. Another way to deal with this is to force a `0` in there. --- Noting all that, you'd be doing a lot of unnecessary work to compute all the other disjoint sets. There is a better way where you manually maintain what would be 0th disjoint set. If interested, I can share the code for that solution.
Do I get bonus points if I can do it in one line? auto sort_find(std::vector v){ std::sort(v); long long counter; for(auto const & e : v) if(v != ++counter) return v;}
I did that in my very first programming assignment at uni back in 1980 and got marks taken off. Never again thereafter. Putting multiple statements on one line is pointless unless you want to make your code unreadable. Same with trying obscure syntax tricks. The compiler will do a better job than you optimising your code. Your job is to get the logic correct and make it readable (ie, reflect the logic clearly) so that others can more easily spot the errors that you're going to make.
@@cottawalla In school they had you coding in youtube comments? Edit: That was a joke, and I don't mean to take away from anything you said. You're basically right in all counts.
@@IamusTheFox The better example, assuming I get the joke, would have been Twitter comments. That, as they say, would have been "pure luxury" in a Yorkshire accent. We could only dream of 140 characters.
Great video. However, technically speaking, modifying the input array does count as using additional space when the question doesn't ask for it. EDIT: That is what I learned in my algorithm analysis class. I guess it is not the case with LeetCode then.
OK i m guessing im missing something. but wouldnt be enough just to find the minimum of the input? so the extra space is just a long long, you go through the list only once and you check if the element in the list is positive and smaller than the buffered number
If you have input like 1, 2, 3, 5, 6 then your answer should be 4. If you just find a minimum then you will return 1, right? But that's not the correct answer. And neither 2 or 3, for example. The task is to find missing minimal element in the input, not just the minimal element in the input.
I didn't mention in the vid, but the problem statement restricts the input to 32-bit ints, so long long, which is at least 64 bits, is sufficient for this problem.
wouldnt it be faster if you just remove the negative numbers and then create an array that starts at 1 and finishes at the length of nums, then you sum that array, and then you just take the difference from the sum of the input array(with the negative numbers removed) and the sum of the other array maybe im just not getting something
If there is only 1 missing integer then yes, in that case we can solve this using (1+num)*num/2 - (sum of input - value of the negative) and we will have desired number (num being the length of input).
The algorithm is fine in Python. But I already made that video, so I thought I would give viewers at least something new to look at since I already covered this problem in Python.
In C++ something like a=b doesnt just assign b to a, it also returns b, so c != (a=b) assigns the value of b to a and also checks if c != b at the same time. This is a common idiom in C++ that often confuses beginners, but it's an important feature of the language that one needs to learn.
is it forbidden to create an auxilliary array to store some kind of vector of indices? seems like this method does a lot of moving values around. I also don't know very much C++ so maybe what I propose is no faster.
And in practice, the actual runtime of an algorithm like this is likely to be dominated by cache misses. So adding an extra array of indices will almost certainly be slower.
@@OMGclueless there is plenty of jumping around in this code. You could use a 1bit per number index vector, that would be 32 times smaller than the input one, and so maybe it would even be better from a cache perspective. Depending on the cache size the index vector could maybe stay cached during the entire run, and due to the predictable access pattern on the input vector the relevant parts of it could be very cache efficient even if it doesn't fit into the cache as a whole. Should also have less conditional jumps. If I had to bet, a 1bit/number index array would be faster.
I think it looks more like cycle sort. Insertion sort shifts the top elements of the partial result on every insertion. Cycle sort assumes you know the final index of the values, and moves each element only one or zero times.
@flareragnarok Maybe you are misunderstanding my question. I'm asking if, for example, the last for loop could be done incrementing and decrementing at the same time, reducing the time to loop by half.
@@brunch. I asked if it "can be done", not if it would 'reduce the order of complexity of the algorithm'. The code would be faster (even tho a little more complex).
A long long int is not necessarly bigger than int. Sizes should be stored in size_t not int, not long, not unsigned long not unsigned long long or any other crap. When N>INT_MAX, you get UB because i will overflow.
Your suggestion is not correct. This wasn't mentioned in the video, but the problem statement guarantees that -2^31 = 0. The implicit conversion of n-1 to a size_t when plugging it into the array index is also fine because we have guaranteed the value we are converting is nonnegative.
Simpler and faster solution: just sum up the numbers in the array and subtract the result from N(N+1)/2 where N is the size of the array. For example: 3 + 4 + 1 + 5 = 13, 5*(5+1)/2 = 15; 15 - 13 = 2. If the difference is zero then the missing number is N + 1.
I guess it doesn't matter because this is just a competitive problem, but if this was production code your algorithm is kinda bad because you are modifying your input, so you should either take it as copy or as a move value, so the user of the function knows that his data will get consumed. Either way, it still is a algorithm that may be pretty useful on the future, so thanks 😊
Maybe I'm too pedantic about const-correctness, but the interface didn't specify the input is const, and to me that says please eat the input, I don't need it anymore.
Indeed, non-const input is fair game in my book, so it's not really the algorithm's fault. Having said that, this interface is kinda bad for modern standards. A better one would be simply using a vector as a parameter, rather than a vector&. Then the user of the api could choose to either copy or move as they see fit. Again, just to make it clear, the interface is part of the problem description here, not of the actual submission, so it's not the fault of whoever is writing the algorithm.
The audio sounds kinda muffled, not sure how to describe it
muffled
Looking back on earlier videos it's surprising there weren't more problems what with the mic being so far out of position.
*Audio knowledgeable people please read!* I am having so much trouble with my audio setup. It's definitely an issue, but I'm not exactly sure what the source of the problem is. I've heard that it could be mic placement, mic hardware (I'm using a SpeechWare FlexyMike), or not equalizing/compressing properly. If you have recommendations or better yet if you are willing to troubleshoot with me, please reach out! I want to get this fixed to improve the quality of my videos.
@@mCoding Would recommend getting a studio mic, like a blue yeti or something on a boom arm, it often has way better quality and control of the sound than normal microphones :)
@@mCoding @mCoding eq out the low end, add a little reverb heres my attempt:
check my channel for it since youtube is deleting the link
I'm a beginner .Learnt a lot from your last few vids. Keep up the good work :)
Thanks, will do!
That reminds 100 prisoners puzzles where the strategy is to put numbers in the places they are supposed to be.
Oh, I just made a new array that stores the count of each number at that index, i.e. the occurrences of the number '1' would be stored in count[1], then I just find the first one that is 0. I thought that was quite elegant until I saw this. Excellent solution!
Yours is cool too
Nice! The previous solution seemed unsatisfying, this one is super smart!
Glad you think so! Unfortunately in real code the other solution is likely more useful because this kind of function should really not be modifying its argument... But a problem's a problem!
@@mCoding if you instantiate a second vector with zeros and write the numbers in there you can just scan that for a zero I guess. So it doesn't seem like the inplace overriding is inherent to this algorithm
really clever solution. The only thing i can think of to make it potentially faster is using parallelism.
I don't see how this algorithm could be parallelized since it jumps all around the array dependent on the data. Could you elaborate?
@@mCoding this actually should not matter. At every point each element of the array is either the original number or its place. Each element only ever changes to be its place if at all. So if two parallel branches jump to the same place, one of them will take the number and modify it, and the other will see that the number is the same and stop. Then you just need to have a number that is points to the first number which no thread dealt with yet and then you can have a pool of however many threads you want doing the work.
@@caedenw imma be honest, I don't have experience with low level parallelism, but isn't this what atomic operations are for?
I'd solve this using DSU which would use O(n * alpha(n)) time and O(n) extra space. Every number in the array that we care about merges i-1 and i in the DSU, then we just return the size corresponding to the 0th set. This may run worse because of the alpha term + the extra O(n) memory, but I think this would be another cool solution for this problem :)
This solution is O(n) time and O(1) space! But thanks for the alternative solution.
Hey! This would work with a few caveats.
1. You need to make sure you ignore negative numbers, otherwise the 0th disjoint set could be for a range of negative numbers.
2. You would need to check for the special case that the 0th disjoint set doesn't start at 1, in which case the answer is 1. Another way to deal with this is to force a `0` in there.
---
Noting all that, you'd be doing a lot of unnecessary work to compute all the other disjoint sets. There is a better way where you manually maintain what would be 0th disjoint set. If interested, I can share the code for that solution.
Do I get bonus points if I can do it in one line?
auto sort_find(std::vector v){ std::sort(v); long long counter; for(auto const & e : v) if(v != ++counter) return v;}
Yes you do! But the std::sort prevents the algorithm from being linear time as the problem suggests :(
@@mCoding my bad. Just make it consteval? Lol.
I did that in my very first programming assignment at uni back in 1980 and got marks taken off. Never again thereafter.
Putting multiple statements on one line is pointless unless you want to make your code unreadable.
Same with trying obscure syntax tricks. The compiler will do a better job than you optimising your code. Your job is to get the logic correct and make it readable (ie, reflect the logic clearly) so that others can more easily spot the errors that you're going to make.
@@cottawalla In school they had you coding in youtube comments?
Edit: That was a joke, and I don't mean to take away from anything you said. You're basically right in all counts.
@@IamusTheFox The better example, assuming I get the joke, would have been Twitter comments. That, as they say, would have been "pure luxury" in a Yorkshire accent.
We could only dream of 140 characters.
Great video. However, technically speaking, modifying the input array does count as using additional space when the question doesn't ask for it.
EDIT: That is what I learned in my algorithm analysis class. I guess it is not the case with LeetCode then.
OK i m guessing im missing something. but wouldnt be enough just to find the minimum of the input? so the extra space is just a long long, you go through the list only once and you check if the element in the list is positive and smaller than the buffered number
If you have input like 1, 2, 3, 5, 6 then your answer should be 4. If you just find a minimum then you will return 1, right? But that's not the correct answer. And neither 2 or 3, for example. The task is to find missing minimal element in the input, not just the minimal element in the input.
In the for loop, I should be long long right, doesn't this over flow for Large N?
I didn't mention in the vid, but the problem statement restricts the input to 32-bit ints, so long long, which is at least 64 bits, is sufficient for this problem.
wouldnt it be faster if you just remove the negative numbers and then create an array that starts at 1 and finishes at the length of nums, then you sum that array, and then you just take the difference from the sum of the input array(with the negative numbers removed) and the sum of the other array
maybe im just not getting something
If there is only 1 missing integer then yes, in that case we can solve this using (1+num)*num/2 - (sum of input - value of the negative) and we will have desired number (num being the length of input).
Indeed, this assumes *only* one is missing and perhaps no duplicates as well.
why would you make a class?
Is there a reason why this wouldn't work in python ? or why it would be slower then the original solution ?
This should also work in Python, maybe he just chose C++ because it's generally faster than Python.
The algorithm is fine in Python. But I already made that video, so I thought I would give viewers at least something new to look at since I already covered this problem in Python.
@@mCoding For what it's worth, I do come here for the python content haha.
python bad. c good. nuff said
Que es el nombre de este algoritmo? Por que es el
for i in range(1, n+1):
If i not in nums:
print(i); exit(0)
más lento?
El "i not in nums" tiene que buscar en la toda lista (coste n) n veces para saber si "i" está en ella. Lo que da un coste total de n^2
what is that curr != (next=nums[curr-1]) ?
could you please do the assignment annd comparison in 2 different statements , i can't understannd this
In C++ something like a=b doesnt just assign b to a, it also returns b, so c != (a=b) assigns the value of b to a and also checks if c != b at the same time. This is a common idiom in C++ that often confuses beginners, but it's an important feature of the language that one needs to learn.
Sorry if i'm being annoying, but, if N reaches a number that is covered by "long long", wouldn't "i" modulo itself if it reaches over "int" distance?
is it forbidden to create an auxilliary array to store some kind of vector of indices? seems like this method does a lot of moving values around. I also don't know very much C++ so maybe what I propose is no faster.
Indeed, the problem had an O(1) space requirement.
And in practice, the actual runtime of an algorithm like this is likely to be dominated by cache misses. So adding an extra array of indices will almost certainly be slower.
@@mCoding love it, great work then
@@mCoding just hard code an uint32_max length vector, should only require 8 gigs and is O(1) in memory!
@@OMGclueless there is plenty of jumping around in this code. You could use a 1bit per number index vector, that would be 32 times smaller than the input one, and so maybe it would even be better from a cache perspective. Depending on the cache size the index vector could maybe stay cached during the entire run, and due to the predictable access pattern on the input vector the relevant parts of it could be very cache efficient even if it doesn't fit into the cache as a whole. Should also have less conditional jumps. If I had to bet, a 1bit/number index array would be faster.
isnt this basically a modification to an insertion sort algorithm?
I think it looks more like cycle sort.
Insertion sort shifts the top elements of the partial result on every insertion.
Cycle sort assumes you know the final index of the values, and moves each element only one or zero times.
Can't both of your "for loops" be done front (incrementing as you did) and backwards (decrementing)?
@flareragnarok Maybe you are misunderstanding my question. I'm asking if, for example, the last for loop could be done incrementing and decrementing at the same time, reducing the time to loop by half.
@@brunch. I asked if it "can be done", not if it would 'reduce the order of complexity of the algorithm'. The code would be faster (even tho a little more complex).
A long long int is not necessarly bigger than int.
Sizes should be stored in size_t not int, not long, not unsigned long not unsigned long long or any other crap.
When N>INT_MAX, you get UB because i will overflow.
Your suggestion is not correct. This wasn't mentioned in the video, but the problem statement guarantees that -2^31 = 0. The implicit conversion of n-1 to a size_t when plugging it into the array index is also fine because we have guaranteed the value we are converting is nonnegative.
Code has bugs, Submitted your code on same problem on leetcode, it failed test cases.
I tried resubmitting it 2 times and mine still passes. Perhaps you copied it in incorrectly. Note that you need to include the vector header.
Simpler and faster solution: just sum up the numbers in the array and subtract the result from N(N+1)/2 where N is the size of the array. For example: 3 + 4 + 1 + 5 = 13, 5*(5+1)/2 = 15; 15 - 13 = 2. If the difference is zero then the missing number is N + 1.
This is from leetcode ?
Why didnt mention the problem number ?
I think search engines are good enough that you can find it :)
@@mCoding Yeah, I found it in my first try... :-)
cool channel !
I guess it doesn't matter because this is just a competitive problem, but if this was production code your algorithm is kinda bad because you are modifying your input, so you should either take it as copy or as a move value, so the user of the function knows that his data will get consumed. Either way, it still is a algorithm that may be pretty useful on the future, so thanks 😊
Maybe I'm too pedantic about const-correctness, but the interface didn't specify the input is const, and to me that says please eat the input, I don't need it anymore.
Indeed, non-const input is fair game in my book, so it's not really the algorithm's fault. Having said that, this interface is kinda bad for modern standards. A better one would be simply using a vector as a parameter, rather than a vector&. Then the user of the api could choose to either copy or move as they see fit.
Again, just to make it clear, the interface is part of the problem description here, not of the actual submission, so it's not the fault of whoever is writing the algorithm.
For 10k subs maybe you can get a mic that doesn't suck ;)
Last week I only had 100 subs but I get your drift! New mic shipping as we speak.
@@mCoding Damn, nice growth!
Me trying to find int main()🧐
можно еще оптимизировать на 1 такт процессора!
Something is wrong with the audio sadly.
HELP
Your mouth makes the sound, not your eyes.