Understanding the C++ Skeleton
- #include <bits/stdc++.h>: Includes all standard libraries (like
math.h,string.h) in one go, saving time. - using namespace std: Allows direct use of
cout,cininstead of writingstd::cout,std::cineach time. - Functions:
- void: Performs an action (e.g., printing) but returns nothing.
- return type (int, double, etc.): Returns a value. Example:
int sum(int a, int b) { return a + b; }
Introduction to Pairs
- Definition:
pair<int, int> p = {1, 3};stores two values together. - Access:
p.firstreturns 1,p.secondreturns 3. - Nesting: Store 3+ values by nesting:
pair<int, pair<int, int>> p = {1, {3, 4}};- Access:
p.first→ 1,p.second.first→ 3,p.second.second→ 4.
- Access:
- Pair Array: Can store pairs in an array:
pair<int, int> arr[] = {{1, 2}, {3, 4}, {5, 6}};Accessarr[1].secondgives 4.
Containers (The Core of STL)
Vectors
A dynamic array that can resize automatically.
Declaration & Initialization
vector<int> v; // Empty vector
v.push_back(1); // Adds 1 at the end
v.emplace_back(2); // Faster alternative to push_back
vector<int> v(5, 100); // 5 elements, each 100
vector<int> v(5); // 5 elements with garbage/0
vector<int> v1(v); // Copy v into v1
- Vector of Pairs:
vector<pair<int, int>> vec;Usevec.push_back({1, 2});orvec.emplace_back(1, 2);(auto-wraps as pair)
Accessing Elements
- Index:
v[0],v[3](like an array). - Iterator: Points to memory addresses.
vector<int>::iterator it = v.begin(); // Points to first element cout << *(it); // Prints value at that address it++; // Moves to next element it = it + 2; // Jumps 2 positionsv.end()→ points right after the last element.v.rend()andv.rbegin()→ reverse iterators (rarely used).
- Shortcut:
v.back()→ last element.
Printing a Vector
- Traditional loop:
for(int i = 0; i < v.size(); i++) cout << v[i] << " "; - Using iterators:
for(auto it = v.begin(); it != v.end(); it++) cout << *(it) << " "; - For-each loop:
for(auto it : v) cout << it << " ";
Deletion (erase)
vector<int> v = {10, 20, 12, 23, 35};
v.erase(v.begin() + 1); // Removes 20 → {10, 12, 23, 35}
// Erase range: [start, end) – end is NOT included
v.erase(v.begin() + 2, v.begin() + 4); // Removes 12, 23 → {10, 20, 35}
Insertion (insert)
vector<int> v(2, 100); // {100, 100}
v.insert(v.begin(), 300); // {300, 100, 100}
v.insert(v.begin() + 1, 2, 10); // {300, 10, 10, 100, 100}
// Insert another vector:
vector<int> copy(2, 50); // {50, 50}
v.insert(v.begin(), copy.begin(), copy.end()); // {50, 50, 300, 10, 10, 100, 100}
Other Useful Functions
v.size()→ number of elements.v.pop_back()→ deletes last element.v.swap(v2)→ swaps entire vectors.v.clear()→ empties the vector.v.empty()→ returns true if empty.
Lists
A dynamic container with front operations (doubly linked list internally).
- Declaration:
list<int> ls; - Key difference:
ls.push_front(5);adds to beginning cheaply (vectors require costlyinsert). - Other functions (
begin,end,size,clear,empty) work exactly like vectors.
Deque
Similar to lists and vectors, supports push_front, push_back, pop_front, pop_back, front, back, etc.
Stacks (LIFO – Last In, First Out)
stack<int> st;
st.push(1); st.push(2); st.push(3);
st.emplace(5); // Alternative to push
cout << st.top(); // Prints 5 (last element)
st.pop(); // Removes 5
cout << st.top(); // Now prints 3
cout << st.size(); // 3
cout << st.empty(); // 0 (false)
- Only functions:
push,pop,top. No indexing. - Time complexity: All operations are O(1).
Queues (FIFO – First In, First Out)
queue<int> q;
q.push(1); q.push(2); q.push(4);
q.back() += 5; // Adds 5 to 4 → now 9
cout << q.back(); // Prints 9
cout << q.front(); // Prints 1
q.pop(); // Removes 1
cout << q.front(); // Now prints 2
- Time complexity: All operations O(1).
Priority Queue (Max-Heap by Default)
- Default: Largest element at top.
priority_queue<int> pq;
pq.push(5); pq.push(2); pq.push(8); pq.push(10);
cout << pq.top(); // 10
pq.pop(); // Removes 10
cout << pq.top(); // 8
- Min-Heap: Store smallest at top.
priority_queue<int, vector<int>, greater<int>> pq; pq.push(5); pq.push(2); pq.push(8); pq.push(10); cout << pq.top(); // 2 - Time complexity:
pushandpopO(log n),topO(1).
Sets (Sorted + Unique)
Stores elements in sorted order, no duplicates.
set<int> s;
s.insert(1); s.emplace(2); s.insert(2); // 2 not stored again
s.insert(4); s.insert(3); // Now {1, 2, 3, 4}
Key Functions
s.find(3)→ returns iterator to 3. If not found, returnss.end().s.erase(5)→ erases element 5 (maintains sorted order).s.count(1)→ returns 1 (since unique), returns 0 if not present.s.erase(iterator)→ erases by address.s.erase(start_iterator, end_iterator)→ erases a range ([start, end)).- Time complexity: All operations O(log n).
- lower_bound / upper_bound: See linked video explanation.
Multiset (Sorted, Allows Duplicates)
multiset<int> ms;
ms.insert(1); ms.insert(1); ms.insert(1); // Stores all 3 ones
ms.erase(1); // Erases ALL occurrences
// Erase only one occurrence:
ms.erase(ms.find(1)); // Erases only one 1
ms.erase(ms.find(1), ms.find(1) + 2); // Erases two 1s
ms.count(1)returns the number of occurrences (3 in first example).
Unordered Set (Unique, Not Sorted)
- Properties: Unique values, randomized order.
- Time complexity: Average O(1), worst-case O(n).
- Note:
lower_boundandupper_boundfunctions do NOT work.
Maps (Key-Value Pairs, Unique + Sorted Keys)
Stores unique keys in sorted order, mapped to a value.
- Declaration:
map<key_type, value_type> m; - Examples:
map<int, int> mpp; mpp[1] = 2; // Stores key 1 with value 2 mpp.insert({2, 4}); // Key 2, value 4 mpp.emplace(3, 1); // Key 3, value 1 map<pair<int, int>, int> mpp2; // Key is a pair mpp2[{2, 3}] = 10; // Stores pair(2,3) mapping to 10 - Keys must be unique; values can repeat.
- Internally stored as sorted key-value pairs.
For a more comprehensive reference, see the Comprehensive Overview of Data Structures and Algorithms Using Python or the Comprehensive Guide to Core Data Structures and Algorithms. To solidify your understanding, check the Comprehensive C++ Basics and Interview Prep with Striver's Resources. For deeper insight into specific techniques, explore Understanding Data Structures Through C Language: A Comprehensive Guide and Mastering Two Pointer & Sliding Window Techniques in DSA Interviews.
Hey everyone, welcome back to Take It Forward. So, in this video we are going to learn about C++ STL. What is STL? STL
is basically standard template library. Now, in order to write codes in C++ assume you're you're going to use a
container or an algorithm. A lot of times what happens is you don't need to predefine the container or write the
long long codes for that container or for an algorithm. So, STL is basically a compilation of algorithms, containers,
iterators, functions in a minimized version so that you don't have to write lengthy lines of code and you can use
that STL and you can get access to a container or to an algorithm. So, in this video I'll be teaching you all the
STL that is actually required to get started with DSA. So, please make sure you watch this video till the end to
understand or to learn C++ STL in depth. So, without wasting any time, let's get started. So, let's understand the
skeleton of a C++ code. So, you can see this is the entire skeleton of a code and the first line is hash include
bits/stdc++.h. Generically, this is nothing but a library. And
you would have learned about something like math.h. So, in order to
include all the algorithms in math library, you have to hash include math.h. Similarly, in order to include
all the libraries in string, you have to give string.h. Similarly, if you are wanting to add anything, you have to
actually write hash include the library.h name for short. Now, imagine you're writing an algorithm or a program
where you require a bunch of libraries. So, you cannot actually waste a lot of time in including all the libraries
individually. So, what C++ tells us, "Okay, hey listen, I have all the libraries in inside this stdc++.h.
So, just include this one and all the libraries are automatically included and I don't need to individually add them."
Now, this is the int main where you actually write the entire lines of code. Now, what is this actually for? Using
namespace std. Now, imagine just for a case, imagine I write seen of A and A is an integer. So, this works.
But, if you just omit this line, this will actually give error. Now, if you don't add this line, you actually
have to write std double colon seen of A or std double colon see out of A. This basically takes an input into A. This
basically prints the A into the screen. So, if you don't write using namespace std, this
you have to write every time. So, that's a again hectic process. So, that is the reason what we do is we write using
namespace std and we omit this. But, if you want to know about more in depth, you can definitely read a lot of
articles. I'll be leaving a link of an article in the description below. You can check that out.
So, before moving to the STL part, let's understand functions. So, there are a couple of functions. One is the void.
So, if you write void and probably print and over here you give see out, let's say my name Raj and I call the print
function. So, what happens is this print function calls and this will output Raj in the screen. Now, this is a void
function. What does a void function means? It will not return you anything. Okay, so that is one kind of function
and the other kind of function is a return type function. Assume I write int of sum A int of B and I say, "Can you
please return A plus B?" And over here I say, "int S equal to sum, can you just do a sum of one and B?" So, what happens
is it calls this function, passes one into A, passes five into B and returns A plus B. Yes, and it returns A plus B.
So, you get A plus B. That is basically one plus five, six into the S. And now if you do a see out of S, what happens
is this actually prints six into the screen. You need to understand this. Now, this is a return
type function, right? Now, this can be a double, this can be anything. Like you can use any data type as you wish to.
So, these are the basic stuffs about the C++ skeleton of a code. Okay. So, before moving to the next part of the video,
I'd love to thank the sponsor of this video, which is Coding Ninjas. Now, Coding Ninjas is India's leading EdTech
platform. You can definitely check out the courses at Coding Ninjas. Now, why Coding
Ninjas? Because in case the courses are well structured so that after the learning keep out there could be no And
also the courses are very well curated because these courses are prepared by people who have been at IITs as well as
Stanford and by the people who have been at Amazon, Facebook and Google. Now, if you don't believe it, you can check out
the Facebook as well as the Google rating of Coding Ninjas. The best thing about them that I find
personally is the doubt resolution time. Like the average doubt resolution time in the last one year has been 10
minutes. Like if you're raising a doubt, it gets solved within 10 minutes. So, that's the amazing like that's the most
amazing thing that they do provide. So, if you're looking out to buy any of the courses, you can check out the link in
the description. You can easily get an additional 20% discount on whatever price that is being going on. So, guys
make sure you check out Coding Ninjas. The link will be in the description. Now, it's time that we move into the
actual part that is the C++ STL. So, you need to understand that C++ STL is divided into four parts. First being
algorithms, second being containers, third being functions, fourth being iterators. So, as of now we will be
learning about containers. It can be vector, it can be queue, set, map and a lot of other things. And we during the
course of learning containers, I'll be also teaching you what are iterators. So, these couple of things we'll be
learning at first. After that I'll be talking about different algorithms and different functions that do exist in C++
STL. So, before moving on to containers, you have to actually learn about pairs. Now, what is pairs? Pairs is a part of
utility library. Okay. Now, imagine I say that I want to store a couple of integers. I want to store one and I want
to store three. So, the only way that you can do is you can store it in a pair. Now, how is pair defined? You
define the pair stuff and then you say the first stuff that you want to store is of integer data type. The second
stuff that you want to store is of integer data type. Then you enclose them into curly braces. So, what happens is
this actually stores everything into a variable P. So, this variable P is now having one {comma} three. So, that is
the meaning of this particular line. So, that's how you define. Now, in place of this int, you can also have something
like double, string, character. The data type can be anything. Okay. Now, if P is storing something like one {comma}
three. Now, if I'm accessing P, it's actually a pair. What if I want to access this one? What if I want to
access this three? So, it's very simple. What do you say is you just write P.first. P.first and that will go and
access this particular one. And if you write P.second, that will go and access this particular three. So, that is as
simple as it can get. So, if you're printing P P.first, one gets printed. If you're printing P.second, three gets
printed. I hope this is clear. Now, imagine you're wanting to store So, as of now, you know that if you declare an
integer data type or a string data type or a character data type, you can always store a single variable. Like if I want
to store int A equal to two, that's fine. And I also know if I want to store two variables, I can use something like
pair. But, what if the question comes up and they say that I want to store three variables, four variables, five
variables? Can you do it? Yes, we can do it. We can use the nested property of pair. Yes, we can use the nested
property of pair. Imagine I say you that you're going to store one, three, four. So, what do you say is, "Okay, I have
one pair and I know this pair can store two guys. So, this is the first guy and this is the second guy in a pair. So,
what I'll say is the second guy can be of a pair data type. Thereby, the second guy stores two guys in itself." That is
how you can do it if you're wanting to store three variables. Got it? Like pair of integer, then in the second guy you
say that I'm going to store a pair in itself. So, basically one {comma} and the second guy is a pair. So, again a
curly brace and three {comma} four. So, that's how you can also store three. And eventually, if they're asking you to
store four variables, you can go nested, nested, nested, nested that you can improvise. Okay. So, that's how you
actually store more than two variables in a pair. But, now if you want to access this one, now if you remember
well enough, I told you pair contains two guys, right? And this guy was called first. If you remember well enough, this
guy was called first and this guy was called second. Correct? Now, but this second guy now stores two guys. So, can
I say this guy is nothing but first you get second, then second's first. So, second's first is what this particular
guy is. And what is this guy? This is nothing but the second.second. So, this is second.second.
As simple as that. So, this is how you can easily access. So, if I ask you what is P.first, it's one. If I ask you what
is P.second.second, it's actually four. If I ask you P.second.first, it's actually three.
This will be the output if I write see out. Okay. Now, what if I declare
Now, as of now you'd have been declaring arrays like integer array, right? Or character array. Or something like a
string array. But, can I declare a pair array? Yes, you can declare a pair array.
The data type can be anything. Pair can also be data type. Now, this is the index zero. This is the index one. This
is the index two now. So, you are storing pairs in your array indexes as of now. So, pair can be treated as a
data type. It generally lies inside the utility library. Yes, it lies inside the utility library. Okay. Now, if I'm if
I'm trying to access array one, so that's basically this. dot second. Now, of this guy, which is the second, that's
five. So, if I'm trying to print this, this is going to print five. So, this is the entire knowledge of pair that is
required in order to get started with data structures and algorithms. In the next part, we'll be learning about
vectors. So, the first container that we will be learning is vectors. Please understand every possible function about
vectors because these functions will be similar in all the other containers like Q, list, map, set. So, please please
make sure you understand all the functions in vector in depth. So, till now, if I ask you to store five values,
the normal thing you would have done was you would have declared an array of size five, and that will be giving you access
to five possible indexes, right? If you remember well enough, this gives access to five possible indexes. The first one
being zero, the second one being one, two, three, four. Now, but afterwards, if you want to modify it, like if I want
that I want to enter one more element, I cannot modify the size of this array because this array has been declared of
size five, and I cannot modify the size because arrays are constant in size. So, this is where something like vector
comes in. Vector is a container which is dynamic in nature. Like you can always increase the size of the vector whenever
you wish to. So, if there is a requirement where you do not know the size of a particular data structure that
will be required, that's when you think of a vector, and that is the best place to use vector. So, vector is a container
only, okay, which stores elements in a similar fashion as the array does, okay? In order to declare vector, it's very
simple. You just give the vector name, then you give the data type. It can be integer, double, char, string, anything.
And then you declare the data type name. Like over here, it's V. It can be Raj, it can be Striver, it can
be vec, it can be ABCD, it can be anything, okay? So, right after that, there's a function as push back. So, if
you're saying push back of one, what it does is this line basically does is it creates an empty container. Remember
this. It creates an empty container. In the next line, it says push back of one. So, this empty container says, "Okay,
I'm empty. So, I'm going to take one into it." So, push back of one will do this. I'm going to take one into it.
Now, there is another function as emplace back. What do you mean by emplace back? It's a similar to push
back. It is similar to push back. So, the moment you do emplace back two, it dynamically increases its size and
inserts two at the back. It dynamically increases its size and pushes two in the back. Now, generically, emplace back is
faster than push back. Now, you can find the reasoning why in Quora. I'll be leaving the link in the description,
okay? Now, this is how you can define vector. Now, can we define vector of a pair data type? You can again define
vector of a pair data type, as I said. So, what you just need to do is you need to change the data type declaration
inside this. So, if you just change it, you can always But over here, there's a trick. As I said, there are a couple of
ways in which you can insert elements into vector. One was push back, the other one was emplace back. So, if
you're using push back, you have to insert like one {comma} two. You have to give the curly braces in order to
enter like in order to insert a particular pair. But if you're using emplace back and you write without curly
braces one {comma} two, emplace back automatically assumes it to be a pair and takes it as an input and inserts
into the vector that you have defined. So, that is how emplace back is different from push back in terms of
syntax. Now, what if I want to declare a container with a lot of elements already filled? So, imagine this is the size.
Now, this is how you can also declare something of a size. Like this is the size that you can give. So, what happens
is a container containing 100, like containing five instances of 100, is already defined. Yes, a container
containing five instances of 100 is already defined, where this is the zeroth index, this is the first index,
this is the second index, this is the third index, and this is the fourth index. So, a container of size five is
already defined with five instances of 100. What if I don't want to declare with 100? You can just declare of this.
If you do this, what happens is a container of size five with five instances of zero or any garbage value
is declared. Now, this depends on the compiler, okay? That's how you can easily do it. So, similarly, if I do
something like V1 of 520, this will declare a container of five instances of 20, okay? Now, what if I want to copy
this container into some other vector? So, you just need to declare another vector V2, and you need to pass on this
particular vector V1. So, V2 will be the similar container, but a copy of it, like a copy of it, not the same one. It
will be another container of five instances of 20. So, this is how generically the declaration is. If you
know these kind of declarations, it does work. You don't need to declare any further. Now, you might be thinking, but
Striver, what we what if we uh define the size of the vector to be five? Can we increase it afterwards? Yes. Even
after this, you try this line push back one. After this line, if you try this, it increases its size and
inserts one at the back. Yes, even if you try this line after this, it will increase its size and expand to a size
of six. So, it is allowed. It's dynamic in nature. You can always increase the size
of vector even if you are predefining the size to be five. Remember this. Now, how do you access elements in a vector?
One of the easiest ways is imagine your vector is like having 20, 10, 15, five, and seven. Imagine this is what your
vector as of now as the container as of now as, and this is the zeroth index, as I told you. This is the first index,
second index, third index, and fourth index. The best way to access them is you can say V1. So, if you say similar
to array, if you say V1, it means 10. This actually means 10. If you say V3, it actually means five. So, you can
actually access it in the similar fashion as you do for an array, okay? That's how you can access it. That's one
of the ways. Like you can write directly V0, or you can write V.at. Generically, uh people don't use this, so you can
just avoid it. You can simply uh use the stuff that you use in array, okay? What's the other way? The other way is
an iterator. Yes, the other way isn't iterator. Now, I was telling you that through uh through the lecture, we will
be learning about containers and iterators. So, let's understand iterators.
What is an iterator? Imagine the vector like let's take the same vector only, 15 and six and seven.
Imagine this was the vector, okay? Now, if I write like for iterator, you have to write this. Whatever Whatever data
type you have taken, vector, that data type, double colons, and you have to write iterator, and this
can be anything. This can be IT, this can be BIT, this can be anything. This is just a name.
But the syntax is the data structure data type double colon iterator this. And you write
V.begin. So, iterator basically means it points to the memory address because these guys
would be stored somewhere in the memory. Like it this 20 would have been somewhere stored in the memory, right?
And that memory can have any address. That address can be 8567 something something. Memory address can
be anything. This 10 will be right after that. This 15 will be right after that, right? So, all these possible values are
actually stored in memory. So, what we do is if you write V.begin, it actually points to that memory. It points
directly to the memory, right? Not to the element. It points to the memory. Understand that. V.begin means it's
pointing to here, but on the memory, okay? So, if you're trying to print V.begin, you're printing
the memory address, not the element. And in order to access, like if you have read about C++, in order to access
anything that is in the memory, you just write star. Like if I write star
V.begin, understand this. V.begin is going to give you the memory, this portion. And the moment you write
star, the element inside this is accessed. Now, let's understand again. If I'm
writing V.begin, this is actually pointing to the memory where 20 is, okay?
The next time I'm doing, I'm saying, "Hey iterator, can you just move ahead?" So, this begin does is this goes here.
So, now the iterator, instead of begin, is right at the next memory address because I've shifted the memory, and
inside all of these are contiguous memory locations. All of these are contiguous memory locations. So, if you
are shifting it plus plus, it moves to the next memory. Again, if you do IT plus plus, moves to the next memory.
After that, if you're doing star of IT, what will happen? What will happen? As of now, it was 20. So, if you do star of
IT, this actually prints 10 because it has shifted to 10, and I'm saying star, access the value at that memory. So, you
get 10. I hope that makes sense, okay? What if right after this, I do an IT plus two? So, basically, I'm saying
shift it by two positions to this portion. Shift it directly by two positions to this portion which has a
six. Now, if I try to print this, it will print six. So, this is how you can easily use the iterator. Iterator is
nothing but points to the memory where the element is lying. I hope that makes sense, okay?
So, we are talking about iterators. Now, you must be thinking, do we have any other iterators apart from begin? We do
have. We have something like end, reverse end, and reverse begin, okay? Now, imagine I have something like 10,
20, 30, 40 as the vector, okay? So, this is what the vector is. So, if I'm saying vector.end,
like where does this point to? Remember this, end will not point to
this portion. End will not point to this portion. Instead of that, end will point to somewhere
right after 40. The memory location that is after 40. Now, if you on this iterator do an IT minus minus, then this
iterator will move to 40. Then only this will move to 40. So, end points to a memory location that is right after the
last element. Please understand. This is very very important in terms of iterator.
So, you understood about end, but what about something like reverse end? Now, these couple of things are never used,
but just just know it like it's never ever used. What is reverse end? Reverse end basically means I'm going to
reverse this. I'm going to reverse this. So, apparently the reverse is 40 at first, then 30, then 20, then 10.
So, now the end is 10. So, right after end. So, that's this position is where it will be pointing. That's this
position is where it will be pointing. Reverse end. End means right after, right? And
reverse begin will be pointing to this. Reverse begin will be pointing to this. Now, there is a specific thing about
this. It moves in the reverse way. Now, if I try to do IT plus plus on this, if I do IT plus plus, IT as of now is
pointing here. IT plus plus will move here. Yes. And after this, IT plus plus will
move here. So, it's a reverse iterator. You have to think it in the reverse way. Like, if you just think this array in
the reverse, it's 40, vector rather, 40 30 10 20 10. And now, if I talk about end, this is end. And if I talk about
begin, this is begin. And if I say begin plus plus, it moves to 30. So, it's that way. Reverse.
Everything is in the reverse order. Never used. Do you need to know? Just know it for
the sake of knowing, but no one is going to ask you. We have discussed about V of zero, V of at of zero. What is V.back?
As the name recommends, if the vector is having something like this, V.back means
the element which is at 30. Is the element which is at 30. That is the meaning of
this. Now, if I'm if I'm wanting to print the vector, there are a couple of ways.
Imagine I have 10 20 30 as the vector, and I want to print it. The simplest way is I know the indexes are 0 1 2. So, I
can directly loop from 0 1 2. Like, I can just go across and say key I'll loop from 0 1 2 and print it. That's a very
simple way. The other thing is I say, I'm going to do it iterator wise because I know this guy is begin. So, I write
begin, and I know the last guy is end. Right after the last guy is end. So, I'm going to run the iterator till it does
not reaches the last guy. And I'm going to do an IT plus plus. The first time I get 10,
next I move it, I get 20, next I move it, I get 30, and I will print every time star of IT. And this is how you can
print the entire vector. This is how you can print the entire vector. But but but, there is a shortcut. Now, you must
not be like No one wants to write these long syntaxes because STL means short. Like, standard template library,
but it means everything in a very simpler fashion. So, STL gives you something like auto.
So, if you write auto, it automatically assigns it to a vector iterator. You don't have to say that this is a vector
iterator. You You don't need to define the data type. It automatically defines the data type. Now, even if you write
integer A equal to five, so you're defining A to be of integer data type. Even if you write something
like auto of A equal to five, computer automatically says that this is an integer. So, this A will be of
integer data type. So, if you write auto, the data type is automatically assigned according to the data.
According to the data, the data type is automatically assigned. Like, if this would have been something like Raj
string, and I would have written auto of A, A would have been automatically string.
So, auto means auto assignation. So, that's that's the beauty of C++. If for some time you don't know the data
type, you can just write auto. C++ will take care of it, and it will automatically assign the data type for
you. The other way to print the vector is using the for each loop. So, if I use
this for each loop, which is IT on V. So, it basically means if the vector is 10 20 and 30, I'm saying IT. First time
IT is here, next time IT is here, next time IT is here. And you can simply print the IT. Auto means on the data
type, please iterate on the data type. First iterates on the 10. Not an Not an iterator. Not Not an iterator. This
means over here int because it is of integer data type. Automatically iterate 10, then 20, then 30, and automatically
prints it entirely. So, that's about how to declare a vector, how to use iterator in a vector, how to print a vector. Now,
let's understand the deletion in a vector. So, imagine I want to delete something.
So, there is something as an erase function. And if I had the vector like 10 20 12 23, I say begin. Plus one.
Now, in order to use the erase function, there are couple of things. Either you give the iterator that like
the location of the address, the location of the address that you want to delete. That this is the address
that I want to delete. Please Please delete this address. So, I'm saying, okay.
Begin plus one. What does this mean? Begin plus one means 20. So, if you just do erase of this
address, so the vector will be now 10 12 13. Vector will be reshuffled. The vector will be reshuffled into 10 12 and
13. That is how the reshuffling will go on. So, that is one way to erase. So, we have understood how to erase single
element. But what if I have a vector like 10 20 30 and 40 and 50? And I say, Striver,
I want to delete these couple of elements. I don't want to go single. Do you have something? I say, yes, I have.
And that's like erase. And I say, give me the starting address, and give me the end address after the
element. Very important. End address after the element. So, starting If I want to
delete 20, can I say that's nothing but begin plus one? I can say because right after begin,
that is where 20 is. I want to delete 30. That is begin plus two. What I said,
right after what you want to delete. So, that's begin plus three. That's begin plus three. Three is
pointing to here. So, I want to delete this portion, but you have to give this end after After the guy that you want to
delete. After, right? Right after 30, you have to give the address. So, apparently it will start, and this is
something like this end is not included. The start is included. Got it? So, please make sure you give something as
which is not included right after one, right after that. Okay? So, that's how you can easily delete it.
Okay, so for this example, we have 10 20 12 23 35. What do you mean by plus two? That means 12. What do you mean by plus
four? Plus two plus three plus four. So, plus four is here. So, apparently this and this will get deleted, and you
will be left out with 10 20 and 35. I hope that makes sense. Now, we're going to learn about insert
function. Insert. Again, you If you want to insert something, it's very simple. First of all, if you declare this, this
creates 100 like two instances of 100 in a container. Now, if I want to insert uh 300 right at the start. Right at the
start. So, I say dot begin, and please insert 300. So, this does is This inserts right at the beginning.
Okay, 300. Now, imagine you had like 10 20 30 40. Okay? And I want to insert something here. I want to insert a five
here. So, do you write? This is the first position. This is the first position. So, instead of begin, you have
to write begin on the first position, can you please insert five? So, if you write this, this five will go here and
get inserted right at the first position. That's how you do insert. Now, that was for single element. You
inserted single element. What if I say that you have 10 20 30 40 as the vector. I want to
two fives. Imagine I want to insert two fives. How do you do that? So, you say
I want to insert at the first position. The number of elements that I want to insert.
And the number that I want to insert. So, this will do is This will take five and five and insert it right after 10.
So, this makes it 10 five five 20 30 40. So, if I say over here, you had 30 100 100. So, I'm saying begin plus one,
which is right after 300. Two positions. Like, two two occurrences of 10. Two occurrences of 10 inserted. Understood?
Very simple. So, that's how the insert function does work for this. Now, what if you have a vector, and you want to
insert it into some other vector? Now, imagine I say that, okay, I have a vector like For this example, we have 50
50. So, I had a 50 and 50 vector. Okay. Now, this vector is named as copy. So, this is the line that declares that.
Okay. Now, I already had this vector. 30 10 10 100 100. And now, I want to insert this 50 50 somewhere. So, at that
somewhere, I give that address, and I say, please enter this entire vector.
Please enter this entire vector. So, it will easily take this entire vector and enter it. If
you want to have a portion of this vector, you can give that starting portion, and you can give this after end
portion, and that will also do it. Again, not required. What is required is erase and this portion. This is hardly
required. If you just know erase and insert about a single element does, okay? So, that's how you can easily do
about vector. Now, what are the other functions in vector? V.size will give you how many elements are there in the
vector as of now. Dot pop back. If this is the vector, pops out the last element. Dot swap is
very simple. If this is a vector V1, this is a vector V2, it swaps the vector as the name recommends. V.clear doesn't
matter how big your vector is. Trims it down to an empty vector. Trims it down to an empty vector. Erases everything,
okay? And V.empty says, does your vector, like if your vector also has a a minimum of one element, it says not
empty. Not empty. But if the vector has nothing, it will say true, empty. So,
these are the functions that are generically required in a vector. So, the next container that we will be
learning is list. Now, list is exactly similar to vector, but the only stuff in list is it is it gives you front
operations as well. Now, list is a container, again dynamic in nature. Same way of declaration. You can push back
two, you can emplace back four. So, this is the list that will happen if you push back two and four. And after that, if
you say push front, this front goes over here, five. Like it directly pushes it into the front. In vector, you had to
use the insert operation. And if you're inserting somewhere, that does take a lot of time. Like insert function in a
vector is very costly. Like we will we will read about time complexities in further data structure algorithmic
lectures, but as of now, just remember an insert in a vector is costlier. And in list, since the internal operation is
a doubly linked list. Like a doubly linked list is maintained for a list. And for a vector, a singly linked list
is maintained. So, thereby something like push front is very very cheap in terms of complexity, time complexity
wise, when you compare it to a vector, okay? And there is emplace front as well. All of the functions, begin,
r.end, reverse end, size, clear, empty, all of the functions are similar to vector. So, I'll not be explaining that,
okay? That is about list. Now, the next container that we will be talking about is deque. Again, similar to list and
vector, you just declare it, push back, push front, pop back, pop front, back, front, and all of the functions are
similar. I'm not going to explain those as well. It is exactly similar to list and vector.
So, the next container that we will be learning is stack. Now, stack is something
as LIFO. LIFO means last in. Remember this. Last in, first out. The guy who went in last
is the guy who will come out at first. So, generically you can just imagine a stack to be a data structure like this.
And this is how you declare a stack. Stack, the data type, and the variable name, okay? So, I've declared the
variable name like this. I'm saying push one. So, I push one. I'm saying push two. I push two. I say push three. I
push three. I'm again saying push three. I push three. I say emplace is similar to push. So, I say push five. Now, these
are the push operations. Right after that, if someone says stack.top, so as I said, who's the last guy who went in?
The last guy that went in, you know, is nothing but five. So, this will print five. Yes, this will print five. Now,
realize this over here, indexing access is not allowed. You cannot say this is index
zero, this is index one. Something like this, you cannot say. In stack, there are only three functions.
One is push, one is pop, the other one is top. All other there like size, uh clear are there, but these are the
generic three functions that you have to deal with. So, if I'm saying top, it gives you five, but the five is still in
the stack. The five is still in the stack. Now, the moment I say pop, it deletes this from the stack. Now, five
is not in the stack. Now, if I'm saying top, right before five was there? Three. So, it prints three. Now, if I'm at this
moment saying stack.size, there are four elements. So, I print four. I'm saying stack, is the stack empty? The answer is
false. It has four elements. Now, if I'm saying swap it to some other stack, I declare another stack one
and I say, can you please swap it? So, swap is very understandable. Both both the guys will swap. So, I hope push
is clear, pop is clear. Pop means delete. Top means just tell me what is at top. You don't need to delete. Just
tell me what is at the top. So, that is how the stack STL works like. Now, talking about complexity wise in
stack, all the operations are big O of one operations. Everything happens in constant time. So, let's learn about the
next container now. Now, the next container that we will be learning is a queue data structure. Now, a queue data
structure is similar to stack, but over here it is FIFO. Okay? FIFO means first in. The guy who
gets in first comes out first. Stack was last in, okay? Now, you can
you can just think it in this way. Like if you if you're forgetting names, you can say like you go into a platform, and
if you're buying a ticket, what do you generally do? The person comes in, the first person who comes in stands, and
the next person who comes in and stands. So, the first guy who gets the ticket, this guy. Then this guy gets the ticket.
And if someone is coming, it's a queue that that happens. So, that that is where the concept comes in, first in,
first out. So, if I'm saying push one, I push one. Push two, I push two. Push four. So, I pushed one, two, and four.
And the next line I'm saying queue.back plus equal to. But back will mean four. It does not means this guy. Back will
mean four only. So, over here I'm saying add plus five. This makes it nine. I'm now saying queue.back. So, if I'm saying
queue.back, it prints the last guy, nine, okay? I'm saying queue.front, prints one. Just prints, does not
deletes. If I'm saying queue.pop, deletes, deletes, deletes the front guy, first in guy. Queue.front is now two.
So, it prints two. It is similar. And now, all the operations are much more similar to stack size and all these
things. That's how queue works. Again, all the operations are happening in constant time. The next thing that we
will learn is priority queue. Now, as the name recommends, priority. The guy who has the largest value stays at the
top. It's similar to queue, but there is some something that happens inside which
you'll learn probably after couple of years when you are appearing for interviews. But as of now, just
understand the logic, okay? So, remember, if you're declaring priority queue like this, the maximum
element stays at the top, or the largest element. If you're using character, the largest character. If you're using
integer, the largest integer. If you're using the string, the lexicographically largest string will stay at the top.
Okay, so I'm saying queue. dot push five. So, you push in five. I say queue.push two. So, you push in two. I
say queue.push eight. So, you push in eight. Now, I say queue.push 10. So, you push in 10, okay? Now, the moment I say
pq.top, out of all these elements, which one is the largest?
10. So, it prints 10. And that is the guy who will be at the top. Now, if you're trying to insert something like
three, three, the three will go right here. The three will go right here.
And this is not a linear data structure. Inside of it, a tree data structure is maintained, which you'll learn in the
later half. Now, understand one thing, the data is not stored in a linear fashion in like inside. At inside, a
tree is maintained, okay? Which probably you'll learn someday. Okay? So, as of now, if I say pq.pop, the topmost
element is popped. 10 is popped. If I say again, now pq.top, who is the topmost? Eight, yes. So, this is how the
priority queue works. Again, push, top, and pop. Main functions. The other
ones are size and empty. Size and empty is very simple. And swap is also very simple. So, these are the functions.
What if I want a priority queue which stores the minimum element at the top? Then this is how the syntax is. Priority
queue, data type, vector,
and this greater int you have to write. And if you give this data type, and now if you push five, five is there. If you
push two, two is there. And if you push eight, eight is there. If you push 10, 10 is there. But this time if you try to
access pq.top, two will come out. So, that's how you maintain a very simple minimum priority queue. And generically,
it's known as min heap. And this is known as max heap. Remember this. The terms that you learn in DS algo as you
move forward. What is the time complexity of push? Push happens in logarithmic of n.
Top happens in big O of one. And the pop, which is the deletion, again happens in logarithmic of n. So, this is
how it happens. If you don't know what is logarithmic of n, no issues. Just keep this in your mind. As you move
forward, you will understand in DS algo. Now, the next container is very very interesting, and that is nothing but the
set container. Now, what is set? Just remember one thing. It stores everything in the sorted order, and stores unique.
Just remember these couple of points, and you know what is a set. Everything in the sorted, and just unique. Just two
points, and you're done. Let's understand. So, imagine this is the container, okay? And
I say insert one. So, you insert one. Imagine you say emplace two. So, you insert two. Imagine you say insert two.
Unique. So, will it store two again? No, it does not. No, it does not. It does not stores
two. If I say insert four, will it? Yes. If I say insert three, it will. But it will insert it here.
Again, a very important thing. Sorted. Stores in a sorted order. At first, it will have one. Then it will have two.
Then it will have three. Then it will have four. Everything in the sorted fashion. So it stores everything in the
sorted fashion. So this is how the set will be storing. Again, a container. Is it a linear container? No, a tree is
maintained. So I'm just explaining you this via this bucket, but inside of this there is an entire tree which is
maintained. Again, which you'll learn as you move forward. So insert and place works in a similar
fashion. Sorted and unique. Okay. Now there are functions. If I say set.find three, and this is the set. So
it will return an iterator. Remember this. Returns an iterator which points to this three, which points to this
three. It returns an iterator which points to this three. Okay. So basically this is an iterator. Remember iterator?
Points to the address. Perfect. Now if I say set.find six. Is six here? No. If an element is not in
the set, please hear me out properly. If an element is not here in the set, it will always return set.end.
That means an iterator which points to right after the end. Imagine the set as having 1 2 4 5. And
you did set.find three. Okay. And you don't have a three. So you will have an iterator end. This
is the iterator which points after five. After five. That's where dot find will return the iterator to be. It points
afterwards. Okay. And after this there is set.erase. Very simple. Erases this guy five. Erases this guy five out of
it. Like if this is the set, if this is the set, it will delete five. It will simply delete five. You don't have to
think anything. Deletes five and maintains the sorted order. Deletes five and maintains the sorted order. Now
as I said, set is nothing but unique and sorted. So if you're trying to count, if it exists, if it exists, it will only
have one occurrence because it does contain unique. And if it does not exist, it will have zero. So if one is
there in the set, it will give you one. Like one occurrence. If it does not, it will give you zero. As simple as that.
Okay. You can also erase. Like you can either give the element to be erased. Like you
can give the element to be erased. Or you can give that, okay, this is the address or the iterator. Please go and
erase this iterator. As simple as that. Now in vector, we did learn about erase start, comma, end.
Similar thing also works over here. If you want to erase everything, yes, if you want to erase everything between two
and four. Imagine you had something like this. So two is here. Four is here. If you get the first guy, if you get the
second guy. So if you do find, you'll get the two's iterator. If you do find a four, you'll get the four's iterator. So
deletes two and three. Remember this, it deletes two and three, not four. Four is this bracket. And this is this. Please
remember this. Now in set, there are other functions like size, empty, swap. Everything is similar to vector. There
is begin. All of these are similar to vector. So I will not be explaining them. The most important are find,
count, and insert. These are the most important ones and as well as erase. Now they have something as a lower bound and
an upper bound. So I will be linking a video in the description which explains lower bound in depth and upper bound in
depth. So please go back and watch lower bound and upper bound. Once you have seen that, you will actually understand
how does this lower bound and upper bound work in a set. It's the exact same that will be taught in the video which
is in the description. So please make sure you watch it. Now in set, everything happens in logarithmic time
complexity. If you're inserting, it takes logarithmic. If you're erasing, it takes logarithmic. Everything happens in
a logarithmic time complexity. Again, if you don't know log in, no issues. Please remember this in your head. Now we did
learn about a set and I said sorted and unique. That means it will just contain one occurrence of two. You can insert
thousands of occurrences of two, but it will just store one occurrence of two. But there is something as multiset. If
you define multiset, it only obeys sorted and it will not obey unique. It will store multiple occurrences. Like if
you try to insert 1 1 1, stores all the occurrences. And if you try to erase one, but all the occurrences are erased
this time. But if you do erase one, it erases everyone. And this time count will count you the number of ones in the
multiset. But if you want to delete, imagine your multiset is containing three ones. And I
just want to delete one occurrence of one. Or two occurrences of one. Or three occurrences of one. So what I can do is,
I can just find out the first occurrence of one. So I'll just do multiset.find because I know find points to the
iterator. I'll say erase that iterator. Instead of saying erase element, because if I say, understand, if I say erase
element, it erases all the elements. But if I say erase address, it only erases that portion. It only erases that
portion. And I want to erase like two two ones. So I say find one and go till two.
Go till two, so it will erase both of them. Both of them. So either erase element, erase address, or erase
starting address and right after the end. That's it. The iterators. And rest all functions are same as set. Stores
everything in the sorted, but not unique. Stores multiple occurrences. Like 1 1 1 2 3 3 4. It can store
multiple occurrences as well. So that is the definition of multiset. Now we did learn about set. We did learn about
multiset. Now there is something as unordered set. Everything is similar to set. The only thing that is omitted,
like it stores unique. The only thing omitted is it does not store in the sorted order. We don't know how it will
store. It has randomized order. It has randomized order. Like if I put in one, after that I put in five, after that I
put in two, after that I put in three, after that I put in six. It can have this order. It can have any order in the
world. But it will just have unique elements. Like if I try to insert one again, it will say I have one. I have
one. And in most of the cases, the time complexity is big O of one. Everything. Like all the operations are
same. Insert, erase. All the operations are same, but only the lower bound and upper bound function does not work. All
the operations work, but the lower bound and the upper bound functions do not work. Remember this. All operations are
similar to set and they do not store everything in sorted order. So all the operations are generically in a big O of
one constant time. But in the worst case, which happens once in a millennium. Like if the data is pro like
possibly given in such a way that they want you to explore the worst case, which does not happen,
then the unordered set goes for a big O of n linear time. It goes for the worst case. Again, does not happens every day.
Happens once in a blue moon. The time complexity goes till big O of n. You can just write them down in notes. You will
understand these things when you move across or when you grow in experience. That's how the unordered set works. So
the next container that we will be learning is a map container. Okay. Now you can think this as something like
just take a task where I say in your college, there will be like there might be multiple people with Raj name. But
how do you distinguish them set? By roll numbers, right? One Raj might have a roll number of 23. The other Raj
might have a roll number of 25. The other Raj might have of 28. So you know this one guy is of roll number 23. The
other guy is of roll number 25. The other guy is of roll number 28. So generically this is in in your class,
this is stored like this. Roll number one, roll number two, roll number three, and so on. If there are 50 people, you
store it like this. So map, you can think this as a as a data structure or a container which says the roll number is
my key. And over here the value can be the name. So this is what the data structure
means. You store unique keys because you can't have 23 roll number twice. You can have it just once. So the keys are
unique. The keys are unique, but the values can be like over here there can be a Raj. Over here
there can be a Raj. So there is one guy with key three who is Raj. There is one guy with key 50 who is Raj. There can be
duplicate values, but it has to be a unique key. So you can think map as a container which stores everything in
respect of key and values. And very important thing,
this key can be of any data structure. It can be integer, sorry, any data type. It can be integer. It can be double. It
can be pair. It can be anything. Similarly, this value can be anything. So how do you define map? This is key.
This is value. Key is integer. Value is integer. Over here, key is an integer. And they're
saying value is two integers. Over here they're saying key is two integers and value is one integer. So you can define
it as you wish to. That is on you. This is how you define. Okay. Now if I'm defining the map to be this for an
example. Assume you are defining the map to be this. Now I say 1 equal to 2. It means on the key one,
can you please store two? So this is what it stores internally in the map. Internally in the map, it stores 1, 2.
Next I say I I want to store it like this. Emplace 3 one. So it stores three is the key and the value to three is
one. It does the similar thing. Stores it into the map.
Again I say insert, you can also use insert. Two comma four. Goes and stores two comma four.
And this is how you can store all these three variables. Okay? So in this way you can actually store for this
particular declaration. And remember one thing map stores unique keys. Very, very important. Map stores unique keys in
sorted order. Something similar to set data structure. Map stores unique keys in sorted order. Something similar to
set data structure. Okay? Now this is the declaration. The second declaration. For this declaration, sorry, uh this
declaration. This is the key. So you have declared the key like this and the value is a single integer. So this is
it. For this it will be storing like, okay, key is two comma three. So this is stored and the value corresponding value
is 10. Perfect. So this can be stored like this. That's how it generically stores. Okay? I hope
that makes a lot of sense. I told you that everything is stored in a sorted order. So this will at first store one
comma two, then it will store two comma four, then it will store three comma one. This three lines will be storing
like this. So again, if you want to explore or if you want to iterate on the map one is you start from begin iterator
and you go on till end iterator, similar in the vector. All you do is you say IT, you run a for each loop. First time IT
is here, so it stores in a pair. Next time IT is here, stores in a pair. Next time IT is here, stores in a pair. If it
is storing in a pair, this is IT.first and this is IT.second. So first time prints one two. Next time goes here,
prints two four. Next time goes here, prints three one. So we try to do the see out. This is how you can actually
traverse in a map and everything is stored in a sorted order of key. In a sorted order of key, not value. Sorted
order of key, remember this. Sorted key is how it stores. No duplicates, all uniques. Okay?
Now if I want to access map of one, if I want to access map of one, it says a value two. It says a value two because
at one you're storing two. But if it tries to access five, will it find five? There is no five. So what happens is it
says null. But if you want to print it, it actually goes and prints zero or null. Okay? Because it does not exist.
So if it's if something does not exist, it gives you zero. Okay? So this is how you can easily access for a key. Now if
you want to know the iterator, imagine you want to know where the key two lies, the address of it. So again the find
function will come over here and say map.find three. So this is where you get it. The iterator.
And in order to access this you give a star. So this accesses this. And if you want the value, dot second. Got it? It
gives you the iterator to the this three comma one. Okay? This IT is this.
So if you give a star it's the element and if you give a second, it is the one. That's how you
can easily access this as well. Now over here, if you try to do dot find five and five is not there, it points to
nothing but dot end. End means after the map. After the map. Okay? Make sense? And again the lower bound and upper
bound functions, if you have seen the video in the description, you can understand how lower bound and upper
bound works. Okay? And all the other functions like erase, swap, size, empty are same. So I'm not going to explain it
again. Next thing is multimap. Similar to map. Only thing is you can store duplicate
keys. You can store duplicate keys. Something similar to set and multiset as I told you, right? Duplicate keys but
everything in the sorted order. This time you can store like one comma two and then you can come across and again
store like one comma three. Right? So you can store duplicate keys over here. Unordered map. Again, unordered map is
similar. Only this portion will go across. It will not store in sorted. It will be randomized. It will be
randomized but it will it will not have duplicate as well. It will just have unique keys. Unordered map will have
unique keys but it will not be sorted. And the difference is like the map works in logarithmic of time and the
unordered map in the in almost all cases works in constant time. In the worst case it goes for big of n. Again this
worst case happens once in a blue moon, not always. In almost all the cases big of one is
what appears. So as of now I can say that I have completed containers and iterators. Now this is not required. Not
required. No need to learn it. Just omit this. Now I'll be telling you all the important algorithms like which are
mandatory like you should know. And all the other algorithms which I will not teach you will eventually learn while
you code but that are not like those are not important. So as of now you can just leave it. Eventually with time if it's
required, learn at that moment. No need to learn it now. So let's move across to learn some
algorithms. Now if I say you that, hey listen, I give you an array of size like one five three two.
Okay? Of size four. And I want you to sort it. So you will be like let's apply bubble sort, merge sort, selection sort
so and so. But in C++ STL if you just write the line sort a comma
it's a four size. So this actually means the first position. The first position of the first iterator.
The starting iterator. And this means the last iterator. A plus four actually means this portion.
Then portion. The last iterator. Again similar to something like start. Start is included and end is not
included. So you write the starting iterator which is a which actually points to this and a plus four which
actually points to this. So all the elements are sorted.
Right after this line it will have one two three five. So you don't have to actually use merge sort, bubble sort,
selection sort. It sorts that into one line. And if you're using vector, the starting
is begin. This is the ending. The starting iterator and the ending iterator. So in
this way you can sort any container. Not map. All like all not map. I'm talking about vectors and
arrays over here. Okay? Now what if I just wanted like I had something like one three
two five. And rather let's keep it like five two. Okay? And I wanted just this portion to
be sorted. So I know a plus two because this is a plus two for sure. And I know a plus
four. Right after this is a plus four. So only this portion will be sorted. So this is how only this portion will be
sorted. Perfect. What if I want to sort them in descending order? Imagine you have like
one three five and two. I want to sort them in descending order. So it's very simple. Give the starting iterator. Give
the ending iterator. The portion that you want to sort. And just write greater int. Yes. Just write greater int. And
this is nothing but a comparator. An inbuilt comparator which automatically sorts it. Like I'll teach you
comparator. Automatically will sort it in the descending order like this. In a descending order. You just need to write
greater int and it automatically sorts it into a descending order. Now what if I want to sort it in some other fashion
because as of now we know how to sort it in increasing. We know how to sort it in decreasing. But what if I want to sort
it in my my way? Because going across you will see that this my
way is being used a lot. For an example we have declared a pair array. And these are the pairs one two, two one, four
one. Okay? And I want you to sort according to second element. Like I want you to sort it in in order of increasing
second element. Please understand. I want you to sort it according to increasing second element. Okay? And if
the second element is same then sort according to the first element but in decreasing. But in decreasing.
What do I mean by that? So as of now can I say the second element is two, one
and one? So this two comma one and four comma one are the guys who should appear right at
the first. Okay? Because the second elements are one and one. And after that I can say after that one comma two will
appear because because of this portion. So can I say that I sorted according to the second element?
But I still have a problem. Now these couple of guys are having same second element.
Now if they have the same second element I want you to sort it according to the first element but in descending which
means I want you to have four comma one at first and then two comma one.
That means among them among them I want you to sort it according to descending. So first four then two. And then you can
write. So first sort it according to the second and if there is a group which is having the same second then among them
sort it according to the first. So this is my way. This is my way. Like I it's it's it's something like a combination
of increasing as well as decreasing. So this is where generically you write the first iterator
the last iterator and a comp. And a comp. Remember this. And a comp. Now
this is nothing but a self-written comparator. A self-written comparator. And this comparator is
nothing but a boolean function. It's nothing but a boolean function. So I've written this but I'll I'll just teach
you how to write it. It's very simple. You write Boolean comparator. And this is the function, okay? This has
to return a true and a false. This has to return a true and a false. Now, go back and see what is the data type that
you that you just had. And the data type, if you see, was pair of int. Just copy paste. And have couple of guys,
pair one and pair two. That's it. Have couple of guys. This is the first thing that you'll do. Have couple of guys.
Now, please understand this that this is pair one and this is pair two. So, forget about the array. Forget about the
array. And now think of these two instances where you have two pairs. Where you have two pairs. This is P1.
This is P2. While writing comparator, just focus. What have you been said? Sorted
according to the second element. So, you say, "Okay. Okay." If
my P1.second is already smaller than second.
That means it's true. We are assuming We are assuming that the pair one lies before P2.
Lies before P2. That is what the assumption is. The pair one lies before P2. And that is okay if the second guy
is lesser than this second guy. I'm okay. They should actually. So, they are in the correct order. This comparator
says are two guys in the correct order or not? And I'm saying they are in the correct order. They are in the correct
order because this guy is smaller than this guy. And that is what I was said. So, if they are, they are in the correct
order. But, but I know one thing. If it's the opposite,
if this is the case, I will say they are not in the correct order. Because if I
have two guys, okay? And imagine this is five and this is four. And I'm saying P1 occurs before
P2. This is wrong. This is wrong. If this second is actually greater than this, I know this is wrong. So, I say
they are not in the correct order. So, what happens is comparator internally says P1 and P2 are not in the correct
order. Can you please swap them? So, apparently, four comes before five. This is what happens. So, they do internal
comparisons and they swap. So, I told them false. They're not. So, they will swap internally.
But, do we have any other conditions we have? What if they are same? Because that's the only condition that
is left. That is the only condition because if if these two conditions do not happen, I
know we will come to a point that they are same. I don't need to write a if because that's the only condition that
is left. They are same. Now, if they are same, we'll again try to
evaluate. I know if they are same, this is P1 and this is P2.
And this time it is descending. So, this guy is greater than this guy. It's okay. Otherwise, it's not.
So, can I say if P1.first is actually greater than P2.first, it's okay. Because this is
what I was looking for. Else, I say it's not. If they equal, it's fine. I I if even if
I swap or do not swap, it's okay. So, can I say if it's greater, it's okay. That's what I'm looking for. And if it's
not, that's false. Please swap it. If it's not, I need it in descending. Can you please just swap it? So, you just
analyze everything whenever you try to write a comparator. Always analyze everything in terms of two pairs. Don't
think in terms of arrays. Just pick up Yes, I repeat. You just need to do one thing. Just pick up one pair. Just take
another pair and try to analyze P1 and P2. That is your job. So, we have learned about comparators. So, anytime
there is my way my way sorting, you can write the comparators. Just need to write this and you should be done. Just
focus on the data type and try to just have evaluate two data types and write it. Nothing different. Okay. So, this is
again one more STL which is very important, which is built-in popcount. So, if number is seven, what is the
binary of seven? It's 111. That's the binary of seven. So, if I say built-in popcount, it says, "Okay, this has three
bits as one." Technically, uh number seven means 000000
Like these are the 32 bits inside the computer. In 32 bits, it's 000000 and 111. So, built-in popcount says,
"How many ones are there? Or how many set bits are there?" So, it will return three set bits. If this number would
have been six, which is nothing but 110. Six is nothing but 110. So, built-in popcount would have returned
two, the number of set bits, okay? If the number is long long, then built-in popcount becomes built-in
popcount LL. Built-in popcount LL if the number is long long. Integer will not suffice that. Perfect.
Now, the last thing is not the last second last thing is next permutation. And if I write a string as 123
and I want to have all the permutations of it all the permutations. So, what I can say is, "Okay, listen.
I'm going to have the string. And I know I know the next permutation is 132.
I know the next permutation like if I talk about dictionary order, 213. The next permutation is
231. The next is 312. The next is 321. Can I say
these are the dictionary like these are the six permutations that you can have. 3! is six.
So, if you want to print them, what you do is you first print the first string. Then you say, "Can you have the next
permutation, please? Can you have the next permutation?" And it takes you the string which was this
becomes 132. And now you print it. Again, the string now becomes 213 and
you print it. Again, the string becomes 231 you print it. Again, the string becomes 312 and you print it. Again, the
string becomes 321 and you print it. Right after this, it goes to null. It says no more permutations. It returns
a false. If there are no more permutation, it returns a false. And when it returns a false, the while loop
breaks. And this is how you can print all permutations of a string. Here's the catch. What if the string was
231? Then it would have started from 231. And the
next permutation of 231 is 312. And the next is 321. So, it would have just printed like
first tens, then this, then this. Right after this, no permutations. So, it's very important that if you want to print
all the permutations, you start from the sorted guy. Like you just start from the sorted guy. And you can easily sort it.
You know the STL now. In this fashion, you start from the sorted guy. And that's how you can
easily print it. Now, the last one is max element. Imagine you have an array like 1 10 5 6
and you want the maximum element. So, if you give max element, start iterator, end iterator, it gives
you the address. And if you give the star, it gives you the element. Similarly, min
element is also there. Right? So, these are the algorithms that are generically used in DS algo in your
day-to-day life. All the other algorithms are there, but they are not widely used and you will not be
requiring them. So, whatever STL I've taught in this video is more than enough to get started with C++. So, just in
case you have understood everything, it's an honest request that get into the comment section and just write one line
comment because that is the only thing that keeps you motivated to make these kind of content. And if you're probably
if the first time on this channel, please do consider subscribing because I have a lot of content regarding trees,
graphs, dynamic programming, DSA that might help you in your longer run. So, please make sure you subscribe to this
channel as well. And you can like this video. And yeah, please please do comment because that keeps me going.
With this, I'll be wrapping up this video. Let's meet in some other video. Till then, bye-bye. Take care. See you.
Whenever your heart is broken, don't ever forget you're golden. I will find the light in the
#include <bits/stdc++.h> is a convenience header that includes all standard C++ libraries (like <iostream>, <vector>, <algorithm>) in a single line, saving time during competitive programming or fast prototyping. using namespace std; allows you to use names from the std namespace directly (e.g., cout instead of std::cout), making code more concise, though it's often avoided in large projects to prevent naming conflicts.
A pair is a simple container that holds two values, accessed via p.first and p.second. To store more than two values, you can nest pairs, e.g., pair<int, pair<int, int>> p = {1, {3, 4}}; where p.first is 1, p.second.first is 3, and p.second.second is 4. You can also create arrays of pairs for multiple sets of two values.
A vector is a dynamic array with O(1) random access and amortized O(1) insertion/removal at the end, but costly O(n) insertion/removal at the front or middle. A list is a doubly linked list that offers cheap insertion/removal anywhere (especially with push_front) but no direct indexing. A deque combines features, supporting O(1) O(1) operations at both ends (push_front, pop_back, etc.) and random access, though not as cache-friendly as vector.
Use the erase method with two iterators defining the range [start, end), where end is exclusive. For example, given vector<int> v = {10, 20, 12, 23, 35};, calling v.erase(v.begin() + 2, v.begin() + 4); removes elements at indices 2 and 3 (values 12 and 23), leaving {10, 20, 35}. The range's complexity is O(n) due to element shifting.
For stack and queue, push, pop, and top (or front/back) all operate in O(1) time. For priority_queue (default max-heap), push and pop have O(log n) complexity due to heap restructuring, while top is O(1). These characteristics make them efficient for their respective LIFO, FIFO, and priority-based access patterns.
A set stores unique elements in sorted order; inserting a duplicate has no effect. A multiset also maintains sorted order but allows duplicate elements. For example, ms.insert(1); ms.insert(1); inserts two 1s. Additionally, ms.erase(1) erases all occurrences of 1, while ms.erase(ms.find(1)) erases only one occurrence. Most operations are O(log n) for both.
You can declare a map with a pair as key directly: map<pair<int, int>, int> mpp; and insert elements like mpp[{2, 3}] = 10; or mpp.insert({{2,3}, 10});. Access works similarly: mpp[{2,3}] returns 10. A std::vector cannot be a key because std::map requires keys to be comparable using operator<, and std::vector does not provide a default operator< (though you could define one manually).
Keep this summary
Save it to LunaNotes and it becomes a real note in your library — editable, searchable, and ready to turn into flashcards or a diagram. Free to start.
Save to LunaNotesOr summarise for another video.
32K+ people have turned 65K+ videos into notes
“Very useful tool. I'm using it for the last couple weeks and I'm loving it so far. Makes learning on YouTube a great experience.”
This summary and transcript were automatically generated using AI with the Free YouTube transcript summary tool by LunaNotes.
Related summaries
Comprehensive Guide to Core Data Structures and Algorithms
Explore foundational concepts in data structures, computational complexity, and advanced algorithms. This guide covers arrays, linked lists, stacks, queues, priority queues, union-find, trees, hash tables, Fenwick trees, suffix arrays, balanced BSTs, and indexed priority queues, with insights on implementation and performance optimization.
MTH104 Finite Sets, Classes, & Power Sets Explained
Learn the definition of finite sets and key theorems for counting elements in unions, intersections, and complements. This lecture also covers classes of sets, subclasses, and power sets with clear examples for MTH104 students.
Comprehensive Guide to Data Structures: Arrays to Graphs Explained
Explore fundamental concepts of data structures from arrays, lists, stacks, queues to trees and graphs. Learn definitions, real-world examples, implementation strategies, and algorithmic insights for efficient data organization and manipulation.
Permutations & Combinations S1 Intro | Factorials, Restrictions, Arrangements
This introductory video launches a comprehensive series on permutations and combinations for A-Level Math S1. It clearly explains the core difference between permutations (order matters) and combinations (order doesn't), then covers fundamental concepts like factorial notation, arranging objects with repeats, and solving problems with restrictions (items together/apart, fixed positions) using worked examples.
8 Essential LeetCode Patterns to Solve Coding Problems Efficiently
After solving over 500 LeetCode problems, the key insight is to focus on repeating patterns rather than individual solutions. This video outlines 8 fundamental patterns—including sliding window, subset, modified binary search, and two-pointer—that can simplify complex coding challenges and improve problem-solving speed.
Most viewed summaries
A Comprehensive Guide to Using Stable Diffusion Forge UI
Explore the Stable Diffusion Forge UI, customizable settings, models, and more to enhance your image generation experience.
Kolonyalismo at Imperyalismo: Ang Kasaysayan ng Pagsakop sa Pilipinas
Tuklasin ang kasaysayan ng kolonyalismo at imperyalismo sa Pilipinas sa pamamagitan ni Ferdinand Magellan.
Mastering Inpainting with Stable Diffusion: Fix Mistakes and Enhance Your Images
Learn to fix mistakes and enhance images with Stable Diffusion's inpainting features effectively.
Pamamaraan at Patakarang Kolonyal ng mga Espanyol sa Pilipinas
Tuklasin ang mga pamamaraan at patakaran ng mga Espanyol sa Pilipinas, at ang epekto nito sa mga Pilipino.
How to Install and Configure Forge: A New Stable Diffusion Web UI
Learn to install and configure the new Forge web UI for Stable Diffusion, with tips on models and settings.
Found this summary useful?
Take it with you. One click puts it in your own LunaNotes library.
Save to LunaNotes