Skip to content

Commit

Permalink
Added editorials for summer contest 2021
Browse files Browse the repository at this point in the history
  • Loading branch information
souravtecken committed May 9, 2021
1 parent 09e896b commit b09bb46
Show file tree
Hide file tree
Showing 15 changed files with 9,607 additions and 2,341 deletions.
37 changes: 37 additions & 0 deletions editorials/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,42 @@
"title": "Astronaut Pairs",
"difficulty": "medium",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge/challenges/astronaut-pairs"
},
"MJJJO": {
"id": "MJJJO",
"title": "Mojo Jojo and Bubbles",
"difficulty": "easy",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/mjjjo"

},
"LZYFX": {
"id": "LZYFX",
"title": "The Quick Brown Fox",
"difficulty": "easy",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/the-quick-brown-fox-1"
},
"SCHAS": {
"id": "SCHSA",
"title": "Annual Day Assembly",
"difficulty": "medium",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/annual-day"
},
"GRPSTU": {
"id": "GRPSTU",
"title": "Grouping Students",
"difficulty": "medium",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/grouping-students-1"
},
"CNODE1": {
"id": "CNODE1",
"title": "Control Tower",
"difficulty": "hard",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/control-tower"
},
"NDMST": {
"id": "NDMST",
"title": "Non Dominant Sets",
"difficulty": "hard",
"problem_url": "https://www.hackerrank.com/contests/alcoding-summer-challenge-2021/challenges/non-dominant-sets"
}
}
18 changes: 18 additions & 0 deletions editorials/problems/CNODE1/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Tags: Heaps

The node with the minimum cumulative distance would be the one right in the centre.
That node would essentially be the median node based on its distance value.

The problem's now reduced to keeping track of the median of a list that's being updated.

Given a list, sorted in ascending order, if we were to know the largest element of the left half of the list, and the smallest element of the right half, we could determine the median of that list.

Implementation

To achieve what's required, we could maintian two heaps, a max heap for the left half, and a min heap for the right.
Each number could be added into one of the two heaps, and the sizes of the heaps could be balanced to make sure they're storing two halves of the current sequence.

Initialize a max-heap left, and a min-heap right
1. If the number is greater than the top of left, it belongs to right, otherwise it belongs to left
2. In case the difference in size of the two heaps exceeds 2, the top of either right or left could be shifted to the other heap. (This way, it's guarranteed the size of the two heaps would be equal if there are an even number of elements in the current sequence, or the sizes would differ by exactly 1 in case the sequence size is odd.)
3. Since the heaps are always balanced relative to each other, the top of the larger heap will always correspond to the median of the sequence.
42 changes: 42 additions & 0 deletions editorials/problems/CNODE1/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include<bits/stdc++.h>
using namespace std;

void addNode(priority_queue<pair<int, int> >& left,
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int> > >& right, int x, int v) {
pair<int, int> node = { v, x };
if(node > left.top())
right.push(node);
else
left.push(node);
if (left.size() > right.size() + 1) {
right.push(left.top());
left.pop();
} else if (right.size() > left.size() + 1) {
left.push(right.top());
right.pop();
}
}

int main() {
int d, x, v;
cin >> d;
cin >> x >> v;

priority_queue<pair<int, int> > left;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int> > > right;

left.push({ v, x });

for(int i = 0; i < d; ++i) {
cin >> x >> v;
addNode(left, right, x, v);
cin >> x >> v;
addNode(left, right, x, v);
if (left.size() > right.size())
cout << left.top().second << "\n";
else
cout << right.top().second << "\n";
}

return 0;
}
18 changes: 18 additions & 0 deletions editorials/problems/GRPSTU/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
We can look at the problem as a graph problem, where each student is a node and each friendship is an edge.

Here the problem requires a bipartite graph check where each group ruby and emerald can be considered as colors to be assigned to nodes. We need to check if the given graph is bipartite.

One way to do this is to run a dfs from a node and assign a color to it. Then all its children must be assigned an opposite color.
While runnning the dfs, if we have already visited a child, we must check if it has the same color as its parent.
If it does, then it is impossible to color the graph in a bipartite fashion.

The next observation to be made is that, if a graph is bipartite there are 2 ways to color the graph.
One is with the starting node as ruby and all its children as emerald and vice versa.

The final observation is that, since the graph may have many connected components, the number of ways to color the graph will be 2 ^ (number of connected components) since all colorings of connected components are independent.

So we need to check for the number of connected components and return 2 ^ (number of connected components).

Thus the answer is,
0 if the graph is not bipartite.
else it is 2 ^ (number of connected components).
44 changes: 44 additions & 0 deletions editorials/problems/GRPSTU/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include<bits/stdc++.h>
using namespace std;

bool dfs(vector<vector<int> >& graph, vector<int>& vis, int i, int c) {
if(vis[i] == (c ^ 1)) return false;
if(vis[i] != -1) return true;
vis[i] = c;
bool res = true;
for(int x: graph[i]) res = res & dfs(graph, vis, x, c ^ 1);
return res;
}

void checkBiPartite(vector<vector<int> >& graph, int n, bool& check, int& count) {
vector<int> vis(n + 1, -1);
for(int i = 1; i <= n; ++i) {
if(vis[i] == -1) {
check &= dfs(graph, vis, i, 1);
++count;
}
}
}

int main() {
int n;
cin >> n;
int f;
cin >> f;
vector<vector<int> > graph(n + 1, vector<int>());
for(int i = 0; i < f; ++i) {
int x, y;
cin >> x >> y;
graph[x].push_back(y);
graph[y].push_back(x);
}

bool check = true;
int count = 0;

checkBiPartite(graph, n, check, count);

if(!check) cout << 0 << endl;
else cout << int(pow(2, count)) << endl;
return 0;
}
9 changes: 9 additions & 0 deletions editorials/problems/LZYFX/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Tags: Hashmap, Sets

Since the characters are independent of upper or lower case, we can make every character lower case (or upper case).

The problem then requires you to check the occurence of all 26 characters, a set can be used to store all unique character.
If the size of the set's 26, it implies that all characters occur in the string.

Alternatively, a hashmap of sorts can be used to track the occurence of each character. The hashmap can then be traversed to
verify 26 occurences.
22 changes: 22 additions & 0 deletions editorials/problems/LZYFX/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include<bits/stdc++.h>
using namespace std;

int main() {
int n;
cin >> n;
string s;
cin >> s;

vector<bool> occur(26, false);
for(char x: s) {
if(x <= 'Z') occur[x - 'A'] = true;
else occur[x - 'a'] = true;
}

int count = 0;
for(bool x: occur) if(x) ++count;

if(count == 26) cout << "YES\n";
else cout << "NO\n";
return 0;
}
11 changes: 11 additions & 0 deletions editorials/problems/LZYFX/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
n = int(input())
s = input()
s = s.lower()
a = set()
for c in s:
if c not in a:
a.add(c)
if len(a) == 26:
print("YES")
else:
print("NO")
10 changes: 10 additions & 0 deletions editorials/problems/MJJJO/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
**Tags**: Sorting


On visualizing the stacks, it can be seen that the crates fall to the right as long as there's no other crate
preventing this right-ward movement.

Following this visualization, the tallest stack will be the rightmost one, followed by the 2nd smallest one, in
non-decreasing order.

Hence, simply sorting the numbers would do the trick.
28 changes: 28 additions & 0 deletions editorials/problems/MJJJO/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main()
{
cin.tie(0) -> sync_with_stdio(0);

int tt;
cin >> tt;
while (tt--) {
ll n;
cin >> n;
vector<ll> stacks(n);
for(int i = 0; i < n; ++i) {
cin >> stacks[i];
}

sort(stacks.begin(), stacks.end());

for (ll i : stacks) {
cout << i << " ";
}
cout << "\n";
}

return 0;
}
10 changes: 10 additions & 0 deletions editorials/problems/NDMST/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Tags: Dynamic Programming

A valid subset contains points that have the following property: if we sort them increasingly by the x-coordinate, they will be sorted decreasingly by the y-coordinate.

First we sort all points, this way it's guarranteed that the x coordinates are in ascending order, now for a given set of coordinates, we find the number of coordinates before it which have the y coordinate greater than equal to it.

Hence, to count the total number of subsets, we can come up with the following dynamic programming solution:

DP[i] = the number of valid subsets such that the point with the greatest x-coordinate is "i".
We build DP[i] by iterating j along 0 to i - 1, such that DP[i] += DP[j] where j.x < i.x and j.y > i.y
40 changes: 40 additions & 0 deletions editorials/problems/NDMST/solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll mod = 1e9 + 7;

int main(void) {
int n;
cin >> n;

auto updateTotal = [&](ll total, ll value) -> ll {
// lambda function to update total
return (total + value) % mod;
};

vector<pair<int, int>> pointsSet; // Store all the points here
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
pointsSet.push_back({x, y});
}
sort(pointsSet.begin(), pointsSet.end()); // Sort points in ascending order
vector<ll> dp(n);
for (int i = 0; i < n; i++) {
ll total = 1;
for (int j = 0; j < i; j++) {
if (pointsSet[j].second > pointsSet[i].second) {
total = updateTotal(total, dp[j]);
// Update total if it matches the required condition
}
}
dp[i] = total;
}
ll ans = 0;
for (int i = 0; i < n; i++) {
ans = updateTotal(ans, dp[i]);
// Find the sum of all the values in the dp array
}
cout << ans << endl;
}
28 changes: 28 additions & 0 deletions editorials/problems/SCHAS/editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Tags: Binary Search

To find the minimum number of students that need to be moved around, we need to find the maximum number
of students that can stay in place. To do this, we must find the longest increasing subsequence (LIS).

It should be noted that this could've been a dynamic programming problem if the constraints allowed it.

Eg.
2 4 1 5 3 6 7

The longest increasing sequence in this example is 2 4 5 6 7.
Numbers that are left out are 1 and 3, these are the numbers that are needed to be rearranged.
Now, all we have to do is find len(sequence) - len(LIST) to get our answer.

Our goal is to find the longest increasing sequence.
We'll start by initializing an array *LIS* to *height[0]* (First element of height). The length of this array will provide us the length of the longest sequence.

1. Iterating through each element of the array height we check if element *height[i]* is greater than the last element of LIS. If it is, then the element is added to the end of LIS.
(This step ensures that LIS is a sorted list and, an element that is larger than the last element of LIS will be part of the longest sequence)

2. If the element is not larger then we'll have to find its position in LIS.
This is done by finding the lower bound(The next smallest number just greater than or equal to the element) in LIS.
This can be solved using binary search, or the in-build lower_bound() (C++) or bisect_left() (python)
Let this lower bound index be **idx**
LIS[idx] is updated to height[i].

At the end, the size of LIS corresponds to the length of the longest increasing subsequence, but it must be noted that the elements
itself do not correspond to a valid longest increasing subsequence.
27 changes: 27 additions & 0 deletions editorials/problems/SCHAS/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
def LowerBound(arr, x, l, h):
if h >= l:
mid = (h + l) // 2
if arr[mid] == x:
return mid
elif arr[mid] > x:
return LowerBound(arr, x, l, mid - 1)
elif(arr[mid] < x):
return LowerBound(arr, x, mid + 1, h)
else:
return l


t = int(input())

for _ in range(t):
n = int(input())
height = list(map(int,input().split()))
LIS = [height[0]]

for i in range(1, n):
if height[i] >= LIS[-1]:
LIS += [height[i]]
else:
idx = LowerBound(LIS, height[i], 0, len(LIS) - 1)
LIS[idx]=height[i]
print(n - len(LIS))
Loading

0 comments on commit b09bb46

Please sign in to comment.