restructure files

This commit is contained in:
Pragy Agarwal
2020-03-19 12:33:50 +05:30
parent 480d4cf830
commit 98a49c6a01
33 changed files with 3 additions and 1 deletions

View File

@@ -0,0 +1,457 @@
# Amazon and Microsoft Interviews
## Interview Tips
1. Always give Brute Force for every question.
- Benefits:
- It favours against worse odds. It is better to give a brute force then to be totally blank.
- Predicts Optimal Solution
2. Data Structures/ Algorithms
Time Complexity| Datastructure and Algorithms
:--|:--
$O(n\log{n})$ | Sorting
$O(n)$ | Two Pointers/ Smart Sorting/ dfs/ bfs
$O(n^2)$ | Dynamic Programming
$O(\log{n})$ | Binary Search
$O(1)$ | HashMap
3. Writing a working code
- Google/Facebook/Uber/Microsoft
- They need working code
- Take care of Edge cases
- Candidates may get rejected for not taking care of Edge cases
- Spend $10\%$ of your time on Edge cases
- Give proper names to characters
- Benefits
- Less Confusion, Error free code
- Good presentation and easier to explain
## Question 1 Binary Tree Maximum Path Sum
Given a non-empty binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.
Example 1:
```C++
Input: [1,2,3]
1
/ \
2 3
Output: 6
```
Example 2:
```C++
Input: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
Output: 42
```
-----
__Brute Force:__
- For Every Pair of node find the path sum
- Find maximum among all the paths
- $O(n^3)$
__Hints:__
- Are all the pairs required?
- For a tree, what are the possibilities of maximum path sum
1. Only root
2. Path from left subtree that ends at root
3. Path from right subtree that ends at root
4. Path from left to right passing through the root
- Are these enough?
6. Path only in left
7. Path only in right
- If we take care of all these paths, we can recursively find the maximum path sum.
__Code__:
```C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int global_max;
int pathEndingAtRoot(TreeNode* root){
if(root == NULL) return 0;
int left = max(pathEndingAtRoot(root->left),0);
int right = max(pathEndingAtRoot(root->right),0);
int path_with_root = left+right+root->val;
global_max = max(path_with_root, global_max);
return max(left+root->val , right+root->val);
}
int maxPathSum(TreeNode* root) {
global_max = root->val;
pathEndingAtRoot(root);
return global_max;
}
};
```
__Time Complexity__
- $O(n)$ as all the nodes are visited exactly once.
__Dry Run__
```C++
Input: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
Output: 42
```
|Root| Left|Right|Path_with_root| global_max|
|:--|:--|:--|:--|:--|
|-10|9|35|34|-10|
|9|0|0|9|9|
|20|15|7|42|42|
|15|0|0|15|15|
|7|0|0|7|15|
## Question 2 Find Median from Data Stream
Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.
For example,
\[2,3,4\], the median is 3
\[2,3\], the median is (2 + 3) / 2 = 2.5
Design a data structure that supports the following two operations:
void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.
Example:
```C++
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
```
-----
__Brute Force__
- Create a sorted array
- Keep on adding nodes at there appropriate places just like insertion sort
- addNum: $O(n)$
- findMedian: $O(1)$
__Hints:__
- In the above solution we do not care about the ordering in the lower half and upper half of the array.
- All we need is that the maximum element of lower half is smaller than minimum element of the upper half.
- Also, the sizes of the two parts are equal.
- Can we use two heaps to solve this question?
__Code:__
```C++
class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int> max_heap_lesser_part;
priority_queue<int, vector<int>, greater<int>> min_heap_greater_part;
MedianFinder() {
}
void addNum(int num) {
if(max_heap_lesser_part.size() == 0){
max_heap_lesser_part.push(num);
return;
}
if(max_heap_lesser_part.top() > num){
max_heap_lesser_part.push(num);
}else{
min_heap_greater_part.push(num);
}
while(max_heap_lesser_part.size() > min_heap_greater_part.size() + 1){
int temp = max_heap_lesser_part.top();
max_heap_lesser_part.pop();
min_heap_greater_part.push(temp);
}
while(min_heap_greater_part.size() > max_heap_lesser_part.size()){
int temp = min_heap_greater_part.top();
min_heap_greater_part.pop();
max_heap_lesser_part.push(temp);
}
}
double findMedian() {
int n = max_heap_lesser_part.size() + min_heap_greater_part.size();
if(n%2 == 0){
return (max_heap_lesser_part.top() + min_heap_greater_part.top())/2.0;
}else{
return max_heap_lesser_part.top()*1.0;
}
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
```
__Time Complexity__
- AddNum : $O(1)$ as there can be only constant operations in the heaps.
- FindMedian: $O(1)$ trivially.
- Space: $O(n)$ we need to store every number.
__Dry Run:__
```
Array : [10,3,5,8,4]
```
|Max Heap(Lower Half)|Min Heap(Upper Half)|Median|
|:--|:--|:--|
|10| |10|
|10,3| | |
|3|10|6.5|
|3,5|10|5|
|3,5|8,10|6.5|
|3,4,5|8,10|5|
## Question 3 Count Complete Tree Nodes
Given a complete binary tree, count the number of nodes.
__Note:__
Definition of a complete binary tree from __Wikipedia__:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
__Example:__
```C++
Input:
1
/ \
2 3
/ \ /
4 5 6
Output: 6
```
-----
__Brute Force__
- By doing any tree traversal we can find the number of nodes in the tree.
__Hints:__
- This is a complete tree. Can we use this property?
- Can we find the height of a complete binary tree in $O(\log{n})$ time?
- All the level except the last level are full in a Complete Binary Tree.
- What will be the total number of nodes in all the levels except the last level?
- If the height is h, it will be $2^{h-1} - 1$
- How many nodes will be there in the last level?
- The nodes will belong to $[1,2^{h-1}]$.
- All the nodes in the last level are towards left.
- Let's number the nodes from $0$ to $2^{h-1}-1$. And look at their binary representation.
```C++
X
/ \
X X
/ \ / \
X X X X
/ \ / \ / \ / \
0 1 2 3 4 5 6 7
----------------
0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1
```
- In this binary representation we can see if $0$ means left and $1$ means right, we know the path to the node.
- Now, we know how to check if a given node is present or not. We also know that all the nodes are towards the left.
- Can we do a binary search to find the last node that is persent?
__Code__:
```C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int getHeight(TreeNode * root){
if(root == NULL) return 0;
return getHeight(root->left) + 1;
}
bool present(TreeNode * root, int node, int h){
if(root == NULL) return false;
if(h == 1){
return node == 0;
}
if((node>>(h-2))&1 == 1){
int new_node = node%((int)pow(2,h-2));
return present(root->right, new_node, h-1);
}else{
int new_node = node%((int)pow(2,h-2));
return present(root->left, new_node, h-1);
}
}
int countNodes(TreeNode* root) {
if(root == NULL) return 0;
int h = getHeight(root);
int lo = 0, hi = pow(2,h-1) - 1;
int ans = -1;
while(lo<=hi){
int mid = lo+(hi-lo)/2;
if(present(root,mid,h)){
ans = mid + 1;
lo = mid+1;
}else{
hi = mid-1;
}
}
return ans + pow(2,h-1) - 1;
}
};
```
__Dry Run__
```C++
Input:
1
/ \
2 3
/ \ /
4 5 6
--------
0 1 2 3
```
|Lo|Hi|Mid|Present|Answer|
|:--|:--|:--|:--|:--|
|0|3|1|Yes|1|
|2|3|2|Yes|2|
|3|3|3|No|2|
|3|2|Break| | |
__Time Complexity__
- For every check $O(\log{n})$
- Total number of checks $O(\log{n})$
- Time Complexity : $O(\log^2{n})$
## Question 4
In a given integer array A, we must move every element of A to either list B or list C. (B and C initially start empty.)
Return true if and only if after such a move, it is possible that the average value of B is equal to the average value of C, and B and C are both non-empty.
```C++
Example :
Input:
[1,2,3,4,5,6,7,8]
Output: true
Explanation: We can split the array into [1,4,5,8] and [2,3,6,7],
and both of them have the average of 4.5.
```
Note:
- The length of A will be in the range \[1, 30\].
- A\[i\] will be in the range of \[0, 10000\].
-----
__Another version__
- Find two subarrays such that their average is same?
- Average of the whole array will be equal to the average of the two sub-arrays.
- Run a pointer from 0 to n-1. Check if the average of nodes from zero to the pointer is equal to the average of the array.
__Brute Force__
- Create all the possible subsets. Check their averages and report if found.
- $O(2^n*n)$
__Hints__
- We will be doing something similar here too. We will only be optimising a little bit.
- Average of the whole array will be equal to the average of the two sub-arrays.
$$\frac{S}{n} = \text{Average of the whole array}$$
$$\frac{S_k}{k} = \text{Average of the first Sub Array}$$
$$\frac{S-S_k}{n-k} = \text{Average of the second Sub Array}$$
$$\text{Both the averagers are equal}$$
$$\frac{S_k}{k} = \frac{S-S_k}{n-k}$$
$$S_k*(n-k) = (S-S_k) * k$$
$$S_k* n - S_k * k = S * k - S_k * k$$
$$\frac{S_k}{k}= \frac{S}{n}$$
__Solution__
First, this problem is NP, and the worst case runtime is exponential. But the expected runtime for random input could be very fast.
If the array of size n can be splitted into group A and B with same mean, assuming A is the smaller group, then
```
totalSum/n = Asum/k = Bsum/(n-k),
where k = A.size() and 1 <= k <= n/2;
Asum = totalSum*k/n, which is an integer.
So we have totalSum*k%n == 0;
In general, not many k are valid.
```
__Solution 2__: early pruning + knapsack DP, O(n^3 * M) 33 ms
If there are still some k valid after early pruning by checking totalSum*k%n == 0,
we can generate all possible combination sum of k numbers from the array using DP, like knapsack problem. (Note: 1 <= k <= n/2)
Next, for each valid k, simply check whether the group sum, i.e. totalSum * k / n, exists in the kth combination sum hashset.
```
vector<vector<unordered_set<int>>> sums(n, vector<unordered_set<int>>(n/2+1));
sums[i][j] is all possible combination
sum of j numbers from the subarray A[0, i];
```
__Goal__: sums$[n-1][k]$, for all k in range $[1, n/2]$
__Initial condition__: $sums[i][0] = {0}, 0 <= i <= n-1; sums[0][1] =${all numbers in the array};
__Deduction__: $sums[i+1][j] = sums[i][j]$ "join" $(sums[i][j-1] + A[i+1])$
The following code uses less space but the same DP formula.
__Runtime analysis__:
All numbers in the array are in range [0, 10000]. Let M = 10000.
So the size of kth combination sum hashset, i.e. sums[...][k], is <= k * M;
For each number in the array, the code need loop through all combination sum hashsets, so
the total runtime is n * (1 * M + 2 * M + ... + (n/2) * M) = O(n^3 * M)
__Code__
```C++
class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int n = A.size(), m = n/2, totalSum = accumulate(A.begin(), A.end(), 0);
// early pruning
bool isPossible = false;
for (int i = 1; i <= m && !isPossible; ++i)
if (totalSum*i%n == 0) isPossible = true;
if (!isPossible) return false;
// DP like knapsack
vector<unordered_set<int>> sums(m+1);
sums[0].insert(0);
for (int num: A) {
for (int i = m; i >= 1; --i)
for (const int t: sums[i-1])
sums[i].insert(t + num);
}
for (int i = 1; i <= m; ++i)
if (totalSum*i%n == 0 && sums[i].find(totalSum*i/n) != sums[i].end()) return true;
return false;
}
};
```

View File

@@ -0,0 +1,479 @@
# Google and Facebook Interviews
## Interview Tips
1. Always give Brute Force for every question.
- Benefits:
- It favours against worse odds. It is better to give a brute force then to be totally blank.
- Predicts Optimal Solution
2. Data Structures/ Algorithms
Time Complexity| Datastructure and Algorithms
:--|:--
$O(n\log{n})$ | Sorting
$O(n)$ | Two Pointers/ Smart Sorting/ dfs/ bfs
$O(n^2)$ | Dynamic Programming
$O(\log{n})$ | Binary Search
$O(1)$ | HashMap
3. Writing a working code
- Google/Facebook/Uber/Microsoft
- They need working code
- Take care of Edge cases
- Candidates may get rejected for not taking care of Edge cases
- Spend $10\%$ of your time on Edge cases
- Give proper names to characters
- Benefits
- Less Confusion, Error free code
- Good presentation and easier to explain
## Question 1 Time Based Key-Value Store
Create a timebased key-value store class TimeMap, that supports two operations.
1. set(string key, string value, int timestamp)
- Stores the key and value, along with the given timestamp.
2. get(string key, int timestamp)
- Returns a value such that set(key, value, times tamp_prev) was called previously, with timestamp_prev <= timestamp.
- If there are multiple such values, it returns the one with the largest timestamp_prev.
- If there are no values, it returns the empty string ("").
Example 1:
```C++
Input:
inputs = ["TimeMap","set","get","get","set","get","get"],
inputs = [[],["foo","bar",1],["foo",1],["foo",3],
["foo","bar2",4],["foo",4],["foo",5]]
Output: [null,null,"bar","bar",null,"bar2","bar2"]
Explanation:
TimeMap kv;
kv.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1
kv.get("foo", 1); // output "bar"
kv.get("foo", 3); // output "bar" since there is no value corresponding to foo at timestamp 3 and timestamp 2, then the only value is at timestamp 1 ie "bar"
kv.set("foo", "bar2", 4);
kv.get("foo", 4); // output "bar2"
kv.get("foo", 5); //output "bar2"
```
Example 2:
```C++
Input: inputs = ["TimeMap","set","set","get","get","get","get","get"], inputs = [[],["love","high",10],["love","low",20],["love",5],["love",10],["love",15],["love",20],["love",25]]
Output: [null,null,null,"","high","high","low","low"]
```
__Note:__
- All key/value strings are lowercase.
- All key/value strings have length in the range [1, 100]
- The timestamps for all TimeMap.set operations are strictly increasing.
- 1 <= timestamp <= 10^7
- TimeMap.set and TimeMap.get functions will be called a total of 120000 times (combined) per test case.
__Brute Force__
- Store key, value and timestamp in an array.
- For every get request run a linear loop to find the largest timestamp in the given bounds with the given key. Return value.
- Time complexity:
- TimeMap.set = $O(1)$.
- TimeMap.get = $O(n)$. Because you are iterating over the whole array.
__Hints__
- Suppose there were no time stamps. What would be the best data structure for this problem. Hashmap, As it gives $O(1)$ look up.
- If we store all the timestamps corresponding to a key in an array, and store that array as value in a HashMap. Then for a given key we can run a loop on the corresponding array and find our answer.
- This approach is still $O(n)$ as we may have only one key.
- It is given that "The timestamps for all TimeMap.set operations are strictly increasing." Can we do a binary search to find our answer?
- The time complexity now will be $O(\log{n})$.
__Code__
```C++
class TimeMap {
public:
/** Initialize your data structure here. */
unordered_map<string, vector<pair<int,string>>> mp;
TimeMap() {
}
void set(string key, string value, int timestamp) {
if(mp.find(key)!= mp.end()){
mp[key].push_back({timestamp,value});
}else{
vector<pair<int,string>> temp;
temp.push_back({timestamp,value});
mp[key] = temp;
}
}
string get(string key, int timestamp) {
if(mp.find(key) == mp.end()){
return NULL;
}
int lo = 0, hi = mp[key].size()-1;
string ans;
while(lo<=hi){
int mid = lo + (hi-lo)/2;
if(mp[key][mid].first <= timestamp){
ans = mp[key][mid].second;
lo = mid+1;
}else{
hi = mid-1;
}
}
return ans;
}
};
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap* obj = new TimeMap();
* obj->set(key,value,timestamp);
* string param_2 = obj->get(key,timestamp);
*/
```
__Time Complexity__
- Worst case it will $O(\log{n})$ for each get query, where n is the number of set queries.
- For set query it will be $O(1)$.
__Dry Run__
```C++
TimeMap kv;
kv.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1
kv.set("foo", "bar2", 2);
kv.set("foo", "bar3", 3);
kv.set("foo", "bar4", 4);
kv.get("foo", 3);
```
|lo|hi|mid|key|mp[key]|Answer|
|:--|:--|:--|:--|:--|:--|
|0|3|1|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar2|
|2|3|2|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar3|
|3|3|3|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar3|
|3|2| ||||
## Question 2 Order of People Heights
You are given the following :
A positive number N
Heights : A list of heights of N persons standing in a queue
Infronts : A list of numbers corresponding to each person (P) that gives the number of persons who are taller than P and standing in front of P
You need to return list of actual order of personss height
Consider that heights will be unique
Example
```C++
Input :
Heights: 5 3 2 6 1 4
InFronts: 0 1 2 0 3 2
Output :
actual order is: 5 3 2 1 6 4
Explaination:
So, you can see that for the person with height 5,
there is no one taller than him who is in front of him,
and hence Infronts has 0 for him.
For person with height 3, there is 1 person
( Height : 5 ) in front of him who is taller than him.
You can do similar inference for other people in the list.
```
__Brute Force__
- Go through all the permutations of the heights and for every permutation check if it holds true with Infronts order.
- The time complexity of this approach will be $O(n!* n)$
__Hints__
- If we sort the arrays based on heights, can we do something?
```C++
Heights: 1 2 3 4 5 6
Infront: 3 2 1 2 0 0
```
- We know the largest element will always have $0$ infront value. No matter how many elements we put in front of largest element there will be no larger element than the largest element.
- Lets put largest element at first place.
```C++
Ans: 6
```
- Now for the next largest element we know the position to insert.
```C++
Ans: 5 6
Ans: 5 6 4
Ans: 5 3 6 4
Ans: 5 3 2 6 4
Ans: 5 3 2 1 6 4
```
- Putting a smaller element in front a given element will not affect it. Thus if we move from the largest to smallest we can insert elements at their respective positions.
- Time complexity: $O(n^2)$. As we are shifting all the elements while inserting a given element. This is similar to insertion sort.
- Can we do better than this?
- If we already know which place a given element should go, we would not have to move the elements.
- For this we need to know the number of empty places infront a given position.
- If we fill elements in sorted order of ascending values, at every step we will know what ever is coming next will be greater than the given element.
- We can use segment trees to do the range queries.
__Code__
```C++
void buildST(int s, int e, int index, vector<int> &tree){
if(s == e){
tree[index] = 1;
return;
}
int mid = s + (e-s)/2;
buildST(s, mid, index*2+1, tree);
buildST(mid+1, e, index*2+2, tree);
tree[index] = tree[index*2+1] + tree[index*2+2];
}
int getPos(vector<int>&tree, int s, int e, int index, int pos){
if(s==e){
tree[index]--;
return s;
}
int mid = s+(e-s)/2;
if(pos >= tree[index*2+1]){
tree[index]--;
return getPos(tree, mid+1, e,index*2+2, pos-tree[index*2+1]);
}else{
tree[index]--;
return getPos(tree, s, mid, index*2+1, pos);
}
}
vector<int> Solution::order(vector<int> &A, vector<int> &B) {
int n = A.size();
vector<int> tree(4*n);
vector<pair<int,int>> person;
for(int i = 0; i<n; i++){
person.push_back({A[i],B[i]});
}
sort(person.begin(), person.end());
buildST(0,n-1,0,tree);
vector<int> res(n);
for(auto p: person){
int pos = getPos(tree,0,n-1,0,p.second);
//cout << pos << endl;
res[pos] = p.first;
}
return res;
}
```
__Time Complexity__
- For each element we will spend $O(\log{n})$ time to find the proper position. Total time will be $O(n\log{n})$.
- Space Complexity will be $O(n)$ as we will be storing the elements in a segment tree.
__Dry Run__
```C++
Heights: 1 2 3 4 5 6
Infront: 3 2 1 2 0 0
```
|Segment Tree|Height|Infront|Answer|
|:--|:--|:--|:--|
|{0,5,6}{0,2,3}{3,5,3}{0,1,2}{2,2,1}{3,4,2}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,1}{4,4,1}{}{}|1|3|{, , ,1, , }|
|{0,5,5}{0,2,3}{3,5,2}{0,1,2}{2,2,1}{3,4,1}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,0}{4,4,1}{}{}|2|2|{ , ,2,1, , }|
|{0,5,4}{0,2,2}{3,5,2}{0,1,2}{2,2,0}{3,4,1}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,0}{4,4,1}{}{}|3|1|{,3,2,1, , }|
|{0,5,3}{0,2,1}{3,5,2}{0,1,1}{2,2,0}{3,4,1}{5,5,1}{0,0,1}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|4|2|{,3,2,1, ,4}|
|{0,5,2}{0,2,1}{3,5,1}{0,1,1}{2,2,0}{3,4,1}{5,5,0}{0,0,1}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|5|0|{5,3,2,1, ,4}|
|{0,5,1}{0,2,0}{3,5,1}{0,1,0}{2,2,0}{3,4,1}{5,5,0}{0,0,0}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|6|0|{5,3,2,1,6,4}|
|{0,5,0}{0,2,0}{3,5,0}{0,1,0}{2,2,0}{3,4,0}{5,5,0}{0,0,0}{1,1,0}{}{}{3,3,0}{4,4,0}{}{}||||
## Question 3 Merge Overlapping Intervals
Given a collection of intervals, merge all overlapping intervals.
For example:
```C++
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].
```
Make sure the returned intervals are sorted.
__Brute Force__
- If we iterate over all the intervals and for each interval try to find another interval that is overlapping.
- When we find an overlapping pair we can merge them and again start our iterations.
- Time Complexity: For finding a pair we may take $O(n^2)$ time. Every time we merge a pair we reduce the list by one. There can be at maximum $O(n)$ pairs. So, the overall time complexity will be $O(n^3)$.
__Hint__
- If we sort the intervals based on the starting time, all the overlapping itervals will be adjacent to each other.
- We can then merge the overlapping intervals in linear time.
__Code__
```C++
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
bool compareIntervals(Interval a, Interval b){
return a.start < b.start;
}
vector<Interval> Solution::merge(vector<Interval> &A) {
// Do not write main() function.
// Do not read input, instead use the arguments to the function.
// Do not print the output, instead return values as specified
// Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
sort(A.begin(), A.end(), compareIntervals);
vector<Interval> res;
int cur_start, cur_end;
bool first = true;
for(auto a:A){
if(first){
first = false;
cur_start = a.start;
cur_end = a.end;
continue;
}
if(a.start <= cur_end){
cur_end = max(a.end,cur_end);
}else{
Interval *i = new Interval(cur_start, cur_end);
res.push_back(*i);
cur_start = a.start;
cur_end = a.end;
}
}
Interval* i = new Interval(cur_start, cur_end);
res.push_back(*i);
return res;
}
```
__Time Complexity__
- $O(n)$
__Dry Run__
```C++
Array: [1,3],[2,6],[8,10],[15,18]
```
|cur_start|cur_end|cur_interval|Answer|
|:--|:--|:--|:--|
| | |[1,3]|{}|
|1|3|[2,6]|{}|
|1|6|[8,10]|{{1,6}}|
|8|10|[15,18]|{{1,6},{8,10}}|
|15|18| | {{1,6},{8,10},{15,18}}|
## Question 4 Remove Invalid Parentheses
Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
Note: The input string may contain letters other than the parentheses ( and ).
Example 1:
```C++
Input: "()())()"
Output: ["()()()", "(())()"]
```
Example 2:
```C++
Input: "(a)())()"
Output: ["(a)()()", "(a())()"]
```
Example 3:
```C++
Input: ")("
Output: [""]
```
__Brute Force__
- If we are given a string of parentheses, we can check if it is valid or not. We can use a stack or a counter to do so. This will be an $O(n)$ algorithm.
- We can recursively solve this question by keeping track of number of characters removed.
- We will first remove no character and check the string. Then we will remove one character to iteratively using backtracking.
- We will check when ever the number of characters to remove becomes zero.
- When we find a valid string we can add it to the result set. As there can be multiple calls to same string.
- Whenever the result array becomes non-empty we will stop increasing the number of characters to be removed and return.
__Hint__
- Questions like this do not have good algorithms.
- I am sharing it so that you understand the importance of Brute force.
- However, you can apply some pruning to considerably improve the actual running time.
- I have used several ideas to improve time complexity.
- Count the number of bad parentheses. And you know your minimum.
- I also counted number of bad open parentheses and bad close parentheses saperately.
- I counted number of open and close parentheses so far.
__Code__
```C++
class Solution {
public:
bool isValid(string s){
if(s=="")return true;
int count = 0;
for(auto c: s){
if(c == '('){
count++;
}else if (c== ')'){
if(count <= 0) return false;
count--;
}
}
if(count!=0) return false;
return true;
}
void makevalid(string s, int open_to_remove, int close_to_remove, int open_count, int close_count, int from, unordered_set<string> &res){
if(close_count > open_count) return;
int toDelete = open_to_remove + close_to_remove;
if(toDelete > s.size() - from){
return;
}
if(toDelete == 0 && isValid(s)){
res.insert(s);
}else{
for(int i = from; i<=s.size()-toDelete; i++){
if(s[i] == ')' && close_to_remove>0){
string newS = s.substr(0,i);
newS += (i+1<s.size())? s.substr(i+1, s.size()-i-1):"";
makevalid(newS,open_to_remove, close_to_remove-1, open_count, close_count, i, res);
}
if(s[i] == '(' && open_to_remove>0){
string newS = s.substr(0,i);
newS += (i+1<s.size())? s.substr(i+1, s.size()-i-1):"";
makevalid(newS,open_to_remove-1, close_to_remove , open_count, close_count, i, res);
}
if(s[i] == ')') close_count++;
else if(s[i] == '(') open_count++;
}
}
}
int findMin(string s, int &open_to_remove, int &close_to_remove){
int ans = 0, count =0;
for(auto c:s){
if(c==')'){
count--;
}else if(c=='('){
count++;
}
if(count < 0){
ans++;
count=0;
}
}
open_to_remove = count;
close_to_remove = ans;
return ans+count;
}
vector<string> removeInvalidParentheses(string s) {
unordered_set<string> res;
int open_to_remove, close_to_remove;
findMin(s, open_to_remove, close_to_remove);
makevalid(s,open_to_remove, close_to_remove,0,0,0,res);
vector<string> res2;
for(auto s: res){
res2.push_back(s);
}
return res2;
}
};
```
__Time Complexity__
- $O(2^n)$ For every i, every element will either be removed or included.
__Dry Run__
```C++
s = "())"
```
|Main Call|Children Calls|res|
|:--|:--|:--|
|makevalid("())",1,0)|makevalid("))",0,0), makevalid("()",0,1), makevalid("()",0,2)| |
|makevalid("))",0,0)| Invalid | |
|makevalid("()",0,1)| Valid| {"()"}|
|makevalid("()",0,2)| Valid| {"()"}|

View File

@@ -0,0 +1,317 @@
# Miscelleneous Problems 12
## 423 Good Graph
### Problem Statement
Given a directed graph of N nodes where each node is pointing to any one of the N nodes (can possibly point to itself). Ishu, the coder, is bored and he has discovered a problem out of it to keep himself busy. Problem is as follows:
A node is ```'good' ```if it satisfies one of the following:
```
1. It is the special node (marked as node 1)
2. It is pointing to the special node (node 1)
3. It is pointing to a good node.
```
Ishu is going to change pointers of some nodes to make them all 'good'. You have to find the min. number of pointers to change in order to
make all the nodes good (Thus, a Good Graph).
Note: Resultant Graph should hold the property that all nodes are good and each node must point to exactly one node.
**Constraints:**
```
1 <= N <= 100,000
```
**Input:**
```
A vector of N integers containing N numbers
all between 1 to N, where i-th number is
the number of node that i-th node is pointing to.
```
**Output:**
```
An Integer denoting min. number of pointer changes.
```
**Example:**
```C++
input: [1, 2, 1, 2]
output: 1 (Pointer of node 2 is made to point to node 1)
input: [3, 1, 3, 1]
output: 1 (Pointer of node 3 is made to point to node 1)
```
### Wrong Approach
- Initialize count = 0.
- From every point do a BFS/DFS. If you can't reach any special node, increase count by 1.
- This approach will tell us the total number of non-good nodes.
- We can change the pointer in every good node. Thus we can say after count number of pointer changes we will have a good graph.
- This approach is wrong. Because there might a case like following:
```C++
input: [1,2,1,2]
```
- Here if we change the pointer of second element, we do not need to change the pointer of forth element. Thus we can say the minimum pointer change is 1. Here, the count of non-good nodes is two.
- How can we improve this approach?
### Brute Force
- For every node find the top most node that can reached from it.
- Save that node in a set.
- Return set.size()
### Hints
- We can see that if there is path from a node to a good node then it is a good node.
- If we can reach a good node from a given node we can mark it as good node.
- If we can not reach a good node from a given node, we will need at least one pointer change to make it good.
- If there is a chain like $5->4->3->2->4$. Now, if we change pointer of 4 to 1, all the nodes will become good.
- So, we can see again we just one pointer change to make the whole chain good.
- Let's color all the chains one by one.
- Since every node is only connected to at maximum one other node. BFS and DFS are same. It is similar to linked list traversal.
```C++
input: [1,2,2,3,4,5,7,7,8,9]
Linked list representation:
1
2<-2<-3<-4<-5<-6
7<-7<-8<-9<-10
```
### Code
```C++
int Solution::solve(vector<int> &A) {
int n = A.size();
bool good[n];
good[0] = true;
for(int i = 1; i < n; i += 1){
good[i] = false;
}
bool visited[n];
for(int i = 0; i < n; i += 1){
visited[i] = false;
}
int curr, next;
int ans = 0, c = 0;
int color[n];
for(int i = 0; i < n; i += 1) {
if(visited[i] == false){
curr = i;
visited[i] = true;
next = A[curr] - 1;
color[curr] = c;
while(visited[next] == false){
good[curr] = true;
visited[next] = true;
color[next] = c;
curr = next;
next = A[curr] - 1;
}
if(color[next] == c && next != 0 ){
ans += 1;
}
c += 1;
}
}
return ans;
}
```
### Time Complexity
Since every node will be visited at max twice, the time complexity will be $O(n)$.
### Dry Run
|Visited|Color|Good|i|A|count|
|:--|:--|:--|:--|:--|:--|
|[f,f,f,f,f,f]|[]|[t,f,f,f,f,f]|0|[1,2,2,5,6,3]|0|
|[t,f,f,f,f,f]|[0,]|[t,f,f,f,f,f]|1|[1,2,2,5,6,3]|0|
|[t,t,f,f,f,f]|[0,1]|[t,t,f,f,f,f]|2|[1,2,2,5,6,3]|1|
|[t,t,t,f,f,f]|[0,1,2]|[t,t,t,f,f,f]|3|[1,2,2,5,6,3]|1|
|[t,t,t,t,t,t]|[0,1,2,3,3,3]|[t,t,t,t,t,t]|4|[1,2,2,5,6,3]|1|
|All visited||||||
[Good Graph](https://www.interviewbit.com/hire/test/problem/423/)
## 438 King Graph
### Problem
Kingdom JenaRajya is a well planned kingdom. They have N houses numbered [0,1,..,N-1] in the city and some bidirectional roads connecting the houses. King Jena has decided to meet his people and so he will visit one of the house in the kingdom where others can gather and meet him. King Jena is very kind and do not want anyone to travel far to meet him. So, he has come up with the following criteria to decide the house he will be visiting:
Assuming that the people from other houses will take the shortest possible path to reach the house the king is visiting, King Jena wants to minimize the maximum distance one has to travel to meet him. In other words, he will choose the house where the shortest distance to the farthest house is minimum possible.
Output the house number which King Jena will visit.
**Note:**
1. In case there is a tie, he will visit the house with minimum house number.
2. You can assume that the graph is connected and so everyone will be able to visit.
**Constraints:**
1 <= N <= 500
1 <= Length of road <= 1000000
**Input format:**
Adjacency matrix representation of the graph.
A[i][j] = distance between house i and j. (A[i][i] = 0 and A[i][j] = -1, if house i and house j have no road between them)
As the roads are bidirectional, A[i][j] = A[j][i]
**Example:**
```C++
Input:
A = [[0, 6, 8, -1],
[6, 0, 9, -1],
[8, 9, 0, 4],
[-1, -1, 4, 0]]
Output:
2
```
### Brute Force
- We can run Dijkstra from each house to find the distance of every other house to this house.
- We can get a distance matrix for each node.
- Then we can find for every house the distance of the furtherest house from that house.
- Find the house which has minimum such distance.
- Time Complexity $O(V* ElogV)$
### Hint
- $E$ can be as big as $V^2$. The above brute force can take $O(V^3logV)$.
- We can reduce the time complexity by using Floyd Warsal all pair shortest path algorithm.
- Floyd Warsal will take only $O(V^3)$ time. This is not much better. However, the implementation is much simpler.
- Inductive Hypothesis
- Suppose that prior to the kth iteration it holds that for $i, j \in V$, $d_{ij}$ contains the length of the shortest path Q from i to j in G containing only vertices in the set ${1, 2, ..., k 1}$
- We can prove floyd warsal using this hypothesis.
### Code
```C++
#define INF 1000000000
int Solution::solve(vector<vector<int> >& A){
//No. of places
int n = A.size();
//Floyd-Warshall Algorithm implementation to find all pairs shortest paths
vector<vector<int> > d(n,vector<int>(n,INF));
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
if(A[i][j] != -1) d[i][j] = A[i][j];
}
}
for(int i=0; i<n; i++) d[i][i]=0;
for(int k=0; k<n; k++)
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(d[i][j] > d[i][k]+d[k][j])
d[i][j] = d[i][k]+d[k][j];
//Find the required answer
int maxDist = -1, ans = -1, temp = INF;
for(int i=0; i<n; i++){
maxDist = -1;
for(int j=0; j<n; j++) maxDist = max(d[i][j], maxDist);
if(maxDist < temp){
temp = maxDist; ans = i;
}
}
return ans;
}
```
### Time Complexity
- $O(V^3)$
### Dry Run
- Adjacency Matrix : $\begin{bmatrix}
0&3&6\\
3&0&2\\
6&2&0
\end{bmatrix}$
- Distance Matrix :$\begin{bmatrix}
0&3&5\\
3&0&2\\
5&2&0
\end{bmatrix}$
- We can see that the answer will be node at index 1. As the distances are ${3,0,2}$ for it.
[King Graph](https://www.interviewbit.com/admin/new_problems/438/#/hints)
## 441 Snake And Ladder Game
### Problem Statement
Given a `snake and ladder` board.
You have to find the ```minimum number of dice throws``` required to reach the last cell(Nth cell) from first cell(1st cell).
For example:
![before](https://images8.alphacoders.com/448/448009.jpg)
```
Here N is 30 and you have to reach 30 from 1.
Here minimum number of dice throws are 3
In first dice throw you will get a 2
In second dice throw you will get a 6
And in third dice throw you will get a 2
```
For snake and ladders there are two arrays A and B of same size.
Ladder or a Snake at position A[i] will take you to a position B[i].
[Snake And Ladder](https://www.interviewbit.com/hire/test/problem/441/)
### Easier Problem
- If there were no snakes and ladders, the problem will become simpler. We can visit 6th node after the given node in one roll. So, for n we will need to do ceiling of $n/6$ rolls.
### Hint
- Having snakes and ladders changes the problem. Jumping to the 6th node might not be optimal.
- Here we can replace every node i that has a ladder to j or snake to j with j.
- Now, we can do a bfs to find the shortest path.
### Code
```C++
int solve(int N, vector<int> &A, vector<int> &B)
{
vector<int> moves(N+1, -1);
vector<bool> visited(N+1, false);
for(int i=0;i<A.size();i++){
moves[A[i]] = B[i];
}
queue<pair<int,int> > que;
que.push(make_pair(1,0));
pair<int,int> entryExtracted ;
visited[1]=true;
while(!que.empty())
{
entryExtracted = que.front();
if(entryExtracted.first==N)
break;
que.pop();
for(int i=entryExtracted.first+1;i<=entryExtracted.first+6 && i<=N;i++)
{
pair<int,int> entry;
if(!visited[i])
{
entry.second = entryExtracted.second+1;
visited[i]=true;
if(moves[i]!=-1)
{
entry.first = moves[i];
}else
entry.first =i;
que.push(entry);
}
}
}
return entryExtracted.second;
}
```

View File

@@ -0,0 +1,569 @@
# Miscelleneous Problems 13
## Game Of Ways
### Problem Statement
Batman is about to take off from Gothams airport which has m runways(numbered from 1 to m) of length n units.
As always, the Joker has come up with an insane game to have fun with Batman.
The rules of the game are as follows::
- Batmans plane can take off only after running for n-units distance in the runways.
- Batman can start on any runway and end on any runway.
- Batman can switch his plane from runway i to j only if i and j are coprime.
- If the batman fails to switch his plane to a coprime runway, after running for 1 unit distance on a single runway, the Joker will bomb the plane.
The Joker does not want to kill the batman, because what will he do without him. So he asks for your help to find out number of ways in which Batman can take off his plane without getting bombed.
As the answer can be very large, output answer modulo (1000000007)
----------
**Input Format**
```
First argument given is an Integer A, Length of the runway.
Second argument given is an Integer B,
Number of different runways available
```
**Output Format**
```
Return a single integer X, the number of ways Batman can take off his plane without getting bombed.
As X can be very large, return X MOD 10^9+7
```
**Constraints**
```
1 <= A <= 1000000000
0 <= B <= 10
```
**For Example**
```C++
Input 1:
A = 1
B = 3
Output 1:
3
Input 2:
A = 2
B = 3
Output 1:
7
Explanation:
For test 1:
3 Ways Starting at 1, 2, 3
For test 2:
1st way: starting and covering whole distance at runway 1.
i.e 1 -> 1 (1 and 1 are co-prime so Batman can continue on
runway 1 without getting bombed)
2nd way: starting and covering distance of 1 at runway 1
and covering remaining distance at runway 2. i.e 1 -> 2
3rd way: starting and covering distance of 1 at runway 1
and covering remaining distance at runway 3. i.e 1 -> 3
similarly there are 4 more ways i.e 2 -> 1, 2 -> 3, 3 ->
1, 3 -> 2
we can't go from 2 -> 2 and 3 -> 3 as per given rules.
```
### Brute force
- Generate all permutations of 1,...,B of size A.
- Check if all the consicutive elements are co-prime. Count all such permutations.
- Time Complexity: B^A.
### First Approach
- It should be clear from the question that we need a graph of size B.
- Let's apply dynamic programing on this graph.
- Let dp[i][k] be the number of ways to start at i and run a length of k.
- dp[i][1] = 1 for all i.
- $dp[i][k] = \sum_{j \in adj[i]}dp[j][k-1]$
**Code**
```C++
int gcd(int i, int j){
if(i>j) return gcd(j,i);
else if (i == 0) return j;
else{
int k = j%i;
return gcd(k, i);
}
}
bool coPrime(int i, int j){
return gcd(i,j) == 1;
}
void printArray(vector<vector<int>> adj){
for(int i = 0 ; i<adj.size(); ++i){
cout << i << ": " ;
for(auto cell: adj[i]){
cout << cell << " ";
}
cout << endl;
}
}
int Solution::solve(int A, int B) {
if(A == 0) return 0;
vector<vector<int>> adj(B);
for(int i = 0; i< B; ++i){
for(int j = i ; j<B; ++j){
if(coPrime(i+1,j+1)){
adj[i].push_back(j);
if(i!=j){
adj[j].push_back(i);
}
}
}
}
//printArray(adj);
vector<int> dp_old(B);
vector<int> dp_new(B);
for(int i = 0; i < B; ++i){
dp_new[i] = 1;
}
int mod = 1000000007;
for(int k = 2; k<=A; ++k){
dp_old = dp_new;
for(int i = 0; i< B; ++i){
dp_new[i] = 0;
for(auto j : adj[i]){
dp_new[i] += dp_old[j]%mod;
dp_new[i] %= mod;
}
}
}
int res= 0;
for(int i= 0; i<B; ++i){
res += dp_new[i]%mod;
res %= mod;
}
return res;
}
```
### Second Approach(Matrix Exponentiation)
- If we look at the adj matrix, $A$ and its powers, we find some nice patterns.
- $A^1[i][j]$ will be 1 if there is an edge between i and j.
- $A^2[i][j] = \sum_{k \in\{0,n-1\}}A^1[i][k]* A^1[k][j]$
- $A^2[i][j]$ will have number of paths of size two between i and j.
- $A^4[i][j] = \sum_{k \in\{0,n-1\}}A^2[i][k]* A^2[k][j]$
- $A^4[i][j]$ will have number of paths of size four between i and j.
- In general $A^n[i][j]$ will have number of paths of size n between i and j.
- If our track length is t, then $\sum_{i,j \in\{0,n-1\}}A^t[i][j]$ will be give us all the possible paths of length t.
**Code**
```C++
#define ll long long int
int mod = 1000000007;
int gcd(int i, int j){
if(i>j) return gcd(j,i);
else if (i == 0) return j;
else{
int k = j%i;
return gcd(k, i);
}
}
bool coPrime(int i, int j){
return gcd(i,j) == 1;
}
void printArray(vector<vector<ll>> adj){
for(int i = 0 ; i<adj.size(); ++i){
cout << i << ": " ;
for(auto cell: adj[i]){
cout << cell << " ";
}
cout << endl;
}
}
void copy(vector<vector<ll>> &A, vector<vector<ll>> &B){
int n = A.size();
for(int i= 0; i<n ; ++i){
for(int j = 0; j<n ;++j){
B[i][j] = A[i][j];
}
}
}
void square(vector<vector<ll>> &A){
int n = A.size();
vector<vector<ll>> temp(n, vector<ll>(n));
copy(A,temp);
for(int i = 0; i<n ; ++i){
for(int j = 0; j<n ;++j){
A[i][j] = 0;
for(int k = 0; k<n; ++k){
A[i][j] = (A[i][j]%mod + ((temp[i][k]%mod)*(temp[k][j]%mod))%mod)%mod;
}
}
}
}
void multiply(vector<vector<ll>> &A, vector<vector<ll>> &B){
int n = A.size();
vector<vector<ll>> temp(n, vector<ll>(n));
copy(A,temp);
for(int i = 0; i<n ; ++i){
for(int j = 0; j<n ;++j){
A[i][j] = 0;
for(int k = 0; k<n; ++k){
A[i][j] = (A[i][j]%mod + ((temp[i][k]%mod)*(B[k][j]%mod))%mod)%mod;
}
}
}
}
void print(vector<vector<ll>> A){
cout << "-------------" << endl;
for(auto row: A){
for(auto cell: row){
cout << cell << " " ;
}
cout << endl;
}
}
void pow_matrix(vector<vector<ll>> &adj,int A, vector<vector<ll>> &orignal){
//print(adj);
//cout << A << endl;
if(A == 1) return;
int n = adj.size();
pow_matrix(adj, A/2, orignal);
square(adj);
if(A%2 == 1){
multiply(adj, orignal);
}
}
int Solution::solve(int A, int B) {
if(A == 0) return 0;
if(A == 1) return B;
vector<vector<ll> > adj(B, vector<ll> (B,0));
for(int i = 0; i< B; ++i){
for(int j = 0 ; j<B; ++j){
adj[i][j] = (coPrime(i+1, j+1))? 1: 0;
}
}
int n = B;
vector<vector<ll>> identity(n, vector<ll>(n,0));
copy(adj,identity);
pow_matrix(adj, A-1, identity);
long long int sum = 0;
for(int i= 0; i<B; ++i){
for(int j = 0; j<B; ++j){
sum = (sum%mod + adj[i][j]%mod)%mod;
sum %= mod;
}
}
return (int)sum;
}
```
## Subarray Transformations
### Problem Statement
Given an array A of size N **(1-indexed)** with all elements **initially 0**. You have to perform T transformations and return the **final** value of array.
Each transformation is of the form Xi , Yi.
In the ith transformation do the following operation Yi times,
**Subarray from index 1 to Xi is taken and choose the cell having minimum value and if there are many cells with same minimum value then choose cell having minimum index. Add 1 to the chosen cell.**
**Input**
```
2D array with 1st transformation as (array[0][0],
array[0][1]),...Tth transformation as (array[T - 1][0],
array[T - 1][1]).
```
**Output**
```
Return array of length N with arr[0] with value of 1st
element,... arr[N - 1] with value of Nth element.
```
**Constraints**
```C++
1 <= N <= 1000
0 <= T <= 10000
1 <= Xi <= N
1 <= Yi <= 100000
```
### Brute Force
- We can find the minimum cell in $O(X)$.
- In every step we have to increase it by one $Y$ times. This will in total take $O(X* Y)$.
- There are $T$ such updates. Thus it will take $O(X* Y* T)$ time.
- That will be $O(10^{12})$ it will give TLE.
- We are doing repetative work while increasing the minimum.
### Hints
- Observation: All nodes will be in non-increasing order.
- To find patterns in questions like these it is advisable to do a dry run on an small array.
- Initially, the array is all zeros. Let it be $[0,0,0,0,0]$
- X = 3, Y = 7
- $3,2,2,0,0$
- X = 5, Y = 6
- $3,2,2,2,2$, | Y = 2
- $3,3,3,2,2$, | Y = 0
- In first case we filled all nodes till $X$ by $Y/X$. And added 1 in $Y%X$ nodes.
- In second case we filled all nodes after 2 to level of 2. And then filled remaining $Y$ after 3.
- So, we will have two nodes $i,j$ such that if we fill all nodes after j the gain will be less than or equal to $Y$. And if we fill all nodes after i to level of i the gain will be greater than $Y$
- Here
- $i<j$
- $A[i] > A[i+1]$
- $A[j] > A[j+1]$
- We fill all the nodes after j to level of j. And fill nodes after $i$ like the first case.
### Code
```C++
bool isValid(vector<long long> psum, int i, int X, int Y, int h){
long long sum = psum[X] - psum[i];
return h*(X-i) - sum <= Y;
}
void update(vector<int> &array, int X, int Y){
int n = array.size();
vector<long long> psum(n,0);
psum[0] = array[0];
for(int i=1; i<n; ++i){
psum[i] += psum[i-1] + array[i];
}
int h;
for(int i = 0; i<=X; ++i){
h = array[i];
if(i<X && array[i] != array[i+1] && isValid(psum, i, X, Y, h)){
for(int j = i+1; j <= X; ++j){
Y -= h-array[j];
array[j] = h;
}
break;
}
}
int idx = 0;
while(array[idx] != h){
++idx;
}
int layers = Y/(X-idx+1);
int remaining = Y%(X-idx+1);
for(int i = idx ; i <= X; ++i){
array[i] += layers;
Y -= layers;
if(remaining > 0){
array[i]++;
Y--;
remaining--;
}
}
return;
}
vector<int> Solution::solve(int A, vector<vector<int> > &B) {
vector<int> array(A,0);
for(auto b : B){
update(array, b[0]-1, b[1]);
}
return array;
}
```
### Time Complexity
- Since we are running a loop of size $O(X)$ twice for every update, $O(X* T)$.
## Sum of Inversions
### Problem Statement
Consider a random permutation P of numbers [1, 2, .., N]. This permutation is called special if there is no element P[i] in P such that **P[i] = i+1** (Consider 0 based indexing). In other words, a permutation is special if it is a derangement (no number is at its "natural" (ordered) place).
Given a number N, find the sum of inversions in all the special permutations of numbers [1, 2, ..., N] modulo **1000000007**. An inversion in an array P is a pair P[i], P[j] such that P[i] > P[j] and i<j.
**Constraints:**
1 <= N <= 20
**Example:**
```C++
Input:
N = 3
Output:
4
Explanation:
For N=3, special permutations are [3,1,2] and [2,3,1]
Number of inversions in [3,1,2] = 2 ( (3,1) and (3,2) )
Number of inversions in [2,3,1] = 2 ( (3,1) and (2,1) )
Thus, sum of inversions = 2+2 = 4.
```
-----------
### Brute Force
- We can create all the permutations.
- Check if they are derangements.
- And find inversions in them.
- This will take $O(n!* n\log{n})$ time.
### Hints
- When ever the brute force is of the order $n!$. Try to think of bit masking dp.
- In bit masking we represented the subset of a set of size n by a n-digit binary number.
- The benefit of this representation is that we can use that number as key in a hash map to store information about perticular sets.
- In this problem, the information that we want to store is the number of inverstions in all the special permutations of a given subset. We also need to store the number of special permutations of every given subset.
- Set bits in mask would be arranged at positions [idx, idx+1, ...., n]
- Here $ids = n - unset_bit + 1$
```C++
int cnt = setbits_count(mask, n); //no. of set bits in mask
int idx = n-cnt+1; //set bits in mask would be arranged at positions [idx, idx+1, ...., n]
ll rank = 0;
for(int i=0; i<n; i++){
if(mask & (1<<i) ){ //if number i+1 is yet to be arranged
if(idx != i+1){ //according to our rule, a number cannot be at its original index
node temp = util(mask^(1<<i), n); //arrange the number (i+1) and calculate the ans for resulting mask
dp[mask].ans = (dp[mask].ans +
(temp.ans + ((temp.perm)*rank)%mod)%mod)%mod;
dp[mask].perm = (dp[mask].perm + temp.perm)%mod;
}
//rank = no. of numbers less than (i+1) in the mask
//for mask 11010 -> rank in iteration i=3 in for loop is 1 which means
// there is 1 number in the mask less than 4 (and that number is 2 in this case)
rank += 1;
}
}
```
### Hints on Website
This type of problems requires a special DP formulation known as Bitmask DP. Those who are not familiar with the concept are advised to Google it before proceeding further.
Consider the following DP formulation:
mask = bitmask where i-th set bit from the left means number i is yet to be used in generating a special permutation.
e.g.: mask = 5 => mask = 101 (binary) => Current permutation 2 _ _. Use numbers [1,3] to fill the blanks in the current permutation.
cnt = no. of unset bits in mask (mask = 5 => mask = 101 (binary) => no. of unset bits = 1)
dp[mask] = sum of inversions of all the special permutations that can be generated using the numbers corresponding to set bits in mask such that the numbers should be arranged at positions [cnt+1, cnt+2, .., N]
e.g.:
mask = 101
One number is already fixed at position 1 and that number is 2. Permutation generated till this point is 2 _ _. Now we have to arrange the remaining numbers [1,3] at blank positions and form a special permutation.
Recursion tree for N = 3 looks like following:
```
111
/ | \
011(1__) 101(2__) 110(3__)
/ \ / \
001 100 100 010
(21_) (23_) (32_) (31_)
```
Here, 011 at level 2 in the tree is not extended further as it is not a valid permutation (011 corresponds to permutation 1 _ _ and 1 cannot be at its correct position according to our rule of special permutations). Similarly "100" (child of "110" in level 3) is also not a valid permutation as that corresponds to permutation 32_.
This type of formulation will require us to ignore the branches of tree that form a non-valid permutation and consider those which forms a valid permutation. Now, the only challenge is to count the sum of inversions at every node of the tree. This is left as an exercise to the reader. Coding part is very easy once you have thought of a way to augment the recursion tree to store necessary information.
Time complexity of this approach would be O(C*N*(2^N)) which is much less than O(N!).
For any given N, our answer is simply dp[(1<<N)-1].
For N=3, our answer is dp[7] ( 7 = "111" in binary)
**Code**
```C++
#define mod 1000000007
#define maxn 20
#define ll long long
//Node to store the information of a state in dp
struct node{
ll perm;
ll ans;
bool vis;
node(): perm(0), ans(0), vis(0){}
}dp[1<<maxn];
//count the number of set bits in mask
int setbits_count(int mask, const int n){
int cnt = 0;
for(int i=0; i<n; i++){
if(mask & (1<<i)) cnt++;
}
return cnt;
}
node util(int mask, const int n){
//Check if this subproblem is already solved
if(dp[mask].vis != 0) return dp[mask];
//base case
if(mask == 0){
dp[mask].perm = 1;
dp[mask].vis = 1;
return dp[mask];
}
int cnt = setbits_count(mask, n); //no. of set bits in mask
int idx = n-cnt+1; //set bits in mask would be arranged at positions [idx, idx+1, ...., n]
ll rank = 0;
for(int i=0; i<n; i++){
if(mask & (1<<i) ){ //if number i+1 is yet to be arranged
if(idx != i+1){ //according to our rule, a number cannot be at its original index
node temp = util(mask^(1<<i), n); //arrange the number (i+1) and calculate the ans for resulting mask
dp[mask].ans = (dp[mask].ans + (temp.ans + ((temp.perm)*rank)%mod)%mod)%mod;
dp[mask].perm = (dp[mask].perm + temp.perm)%mod;
}
//rank = no. of numbers less than (i+1) in the mask
//for mask 11010 -> rank in iteration i=3 in for loop is 1 which means
// there is 1 number in the mask less than 4 (and that number is 2 in this case)
rank += 1;
}
}
dp[mask].vis = 1;
return dp[mask];
}
int Solution::solve(int n){
int mask = (1<<n) - 1; //initial mask --> 111...1 "n ones"
for(int i=0; i< (1<<n); i++){
dp[i].ans = 0;
dp[i].perm = 0;
dp[i].vis = 0;
}
return util(mask , n).ans;
}
```
### Dry Run
- A = 3
- 100 0 0
001 0 1
101 1 1
010 0 1
011 0 1
111 4 2
- 111 4 2
- 101 1 1
- 100 0 0
- 001 0 1
- 011 0 1
- 010 0 1
### Time Complexity
- $O(n* 2^n)$

View File

@@ -0,0 +1,284 @@
# Miscelleneous Problems 14
## Valuable Nodes
### Problem Statement
Given a tree T containing N nodes numbered [1,2, ..., N] rooted at node 1. Each node has a value associated with it. You need to choose some of the nodes from the tree such that the sum of values of the chosen nodes is maximum possible. Moreover, if you have chosen a node V you cannot choose any of its children or grand children.
In simple words, you have to choose a subset of nodes such that no two nodes in the chosen set have a parent-child relation or grandfather-grandchild relation between them.
**Constraints:**
1 <= N <= 500,000
1 <= value of node <= 10,000
**Input:**
```
vector<int> A : A[i] --> Parent of node number i+1.
(A[2] = 1 means parent of node number 3 is 1).
vector<int> B : value[i] --> value associated with
node number i+1.
Note: Parent of node number 1 is 0 (A[0] = 0).
```
**Output:**
A number containing the maximum possible sum.
`(As the answer can be large, output the answer modulo 1000000007)`
**Example:**
```
Input:
A : [0, 1, 1, 1, 3, 3, 6, 6]
B: [1, 2, 3, 4, 5, 100, 7, 8]
Output:
111
Node number 2, 4, 5 and 6 are chosen. Sum = 2 + 4 + 5 + 100 = 111
```
### Brute Force
- The absolute brute force would be to take every subset.
- Check if it contains a child-parent or grandchild-grandparent relationship.
- Maximize the sum of values among these subsets.
### Hints
- Can we optimize the above brute force?
- We can select the node only if its child and grandchild are not selected.
- Can we reduce this problem to an array problem? That array problem will look as follows:
- You are given an array. There is a value stored at every cell. You need to find a subset with highest value sum. If you include A[i] into the set, you cannot include A[i-2], A[i-1], A[i+1], and A[i+2] into the set.
- The above problem can be solved using Dynamic Programming.
- We can store, for all index i, the maximum value of a valid subset of A[0..i].
- $dp[i] = max(dp[i-3]+A[i], dp[i-1])$
- We just look at $dp[i-3]$ and $dp[i-1]$ as $dp[i-2]$ is already included in $dp[i-1]$.
- Can we apply a similar approach to our tree problem?
### Code
```C++
#define ll long long int
int mod = 1000000007;
int getMaxDP(int node, vector<vector<int>> &child, vector<vector<int>> &ggchild, vector<int> &dp, vector<int> &value){
if(dp[node] != -1) return dp[node];
int first = 0, second = 0;
first = value[node]%mod;
for(auto ggc: ggchild[node]){
first = (first%mod + getMaxDP(ggc,child,ggchild,dp,value)%mod)%mod;
}
for(auto c: child[node]){
second = (second%mod + getMaxDP(c,child,ggchild,dp,value)%mod)%mod;
}
return max(first, second);
}
int Solution::solve(vector<int> &A, vector<int> &B) {
int n = A.size();
vector<vector<int>> adj(n);
vector<vector<int>> ggchild(n);
vector<int> dp(n,-1);
for(int i = 1; i<n; ++i){
adj[A[i]-1].push_back(i);
}
for(int i = 0; i<n; ++i){
for(auto c: adj[i]){
for(auto gc: adj[c]){
for(auto ggc: adj[gc]){
ggchild[i].push_back(ggc);
}
}
}
}
return getMaxDP(0,adj,ggchild,dp,B);
}
```
### Time Complexity
- Since we are calculating every dp only once the time complexity will be $O(E+V)$. Since it is a tree the time complexity will be $O(n)$.
### Dry Run
```C++
A : [0, 1, 1, 1, 3, 3, 6, 6]
B: [1, 2, 3, 4, 5, 100, 7, 8]
Children:
1: 2,3,4
2:
3: 5, 6
4:
5:
6: 7, 8
7:
8:
Great Grand Children
1: 7,8
2:
3:
4:
5:
6:
7:
8:
DP:
1: max(DP(2)+DP(3)+DP(4), B(1)+DP(7)+DP(8))
= max(2+105+4, 1+7+8) = 111
2: B(2) = 2
3: max(DP(5) + DP(6), B(3)) = max(100+5, 3) = 105
4: B(4) = 4
5: B(5) = 5
6: max(DP(7)+DP(8), B(6)) = max(7+8, 100) = 100
7: B(7) = 7
8: B(8) = 8
```
## String Rotation
### Problem Statement
Give a string S find lexicographically smallest string possible after circular rotation.
**Lexicographically smallest**: First string in dictionary order.
**Circular rotation**: Pushing the last character to the start.
**Input Format**
```
Argument 1: Length of the String
Argument 2: Given string
```
**Constraint**
```
0 < |S| <= 5000
```
**Sample Input 1**
```
BCABDADAB
```
**Sample Output 1**
```
ABBCABDAD
```
### Brute Force
- Consider all rotations and minimize over all of them.
### Hints
- This is a simple question included to encourage all of you to solve at least one problem.
- So, Go ahead and solve this question.
### Code
```C++
string Solution::solve(int A, string B) {
string doubleB = B + B;
set<string> s;
for(int i = 0; i < A; ++i){
s.insert(doubleB.substr(i,A));
}
return *s.begin();
}
```
### Time Complexity
- Each string comparision may take $O(n)$ time. Here, $n$ is the length of string.
- We have to compare strings $O(n)$ times. Thus the total time complexity will be $O(n^2)$.
- If we use a set, the time complexity will be $O(n^2\log{n})$. This is because insertion in set will take $O(n\log{n})$ time.
## Ways to Arrange Two Objects
### Problem Statement
You are given two types of objects : A and B. There is an infinite supply of both the type of objects .
All the objects of type A are identical and same is the case with all the objects of type B.
Given two integers N and L, find the number of ways in which you can arrange the N objects such that you don't have L or more
consecutive objects of type A together.
**Constraints:**
```
1 < N < 100001
1 < L < 100001
1 < N*L < 100001
```
**Input Format**
```
Input consists on one line containing the value of N and L.
```
**Output Format**
```
Return number of ways modulo 10^9 + 7
```
**Example:**
```
Input:4 2
Output: 8
Explanation:
{B,B,B,B}
{B,B,B,A}
{B,B,A,B}
{B,A,B,B}
{A,B,B,B}
{A,B,A,B}
{A,B,B,A}
{B,A,B,A}
```
### Brute Force
- We can consider all the possible arrangements of A and B.
- For each arrangement, we can check if there are L consicutive A's. We can neglect those arrangements and count others.
- This approach will take $O(n * 2^n)$ time.
### Hints
- We can neglact some arrangements even before making them if at each i we keep count of consecutive A's ending at i.
- Suppose there are L-1 A's ending at i. For example L = 3 and N = 6 and i = 3
- ${B, A, A}$ now on the next step we can not include A.
- Can we memoize these states in dp?
### Solution
- Dp state: dp[i][j] number of arrangements of A and B of length i with j consicutive A's towards the end.
- $dp[i][0]=\sum_{k\in{[0,L-1]}}dp[i-1][k]$
- $dp[i][j]_{j>0} = dp[i-1][j-1]$
### Code
```C++
int mod = 1000000007;
int Solution::solve(int A, int B) {
vector<vector<int>> dp(A+1, vector<int>(B,0));
dp[0][0] = 1;
for(int i = 1; i <= A; ++i){
for(int j = 0; j< B; ++j){
if(j == 0){
int val = 0;
for(int k = 0; k<B; ++k){
val = (val%mod + dp[i-1][k]%mod)%mod;
}
dp[i][j] = val;
}else{
dp[i][j] = dp[i-1][j-1];
}
}
}
int res = 0;
for(int k=0; k < B; ++k){
res = (res%mod + dp[A][k]%mod)%mod;
}
return res;
}
```
### Time Complexity
- It takes $O(1)$ time to calculate most of the dp states. There are $O(N)$ corresponding to $dp[i][0]$ that will take $O(L)$ time.
- There are $O(N* L)$ dp states. Thus the time complexity will be $O(N* L)$.
### Dry Run
N = 4, L = 2
|j->|0|1|
|:--|:--|:--|
|i = 0|1|0|
|1|1|1|
|2|2|1|
|3|3|2|
|4|5|3|
|Answer| 8||

View File

@@ -0,0 +1,480 @@
# Miscelleneous Problems 15
## Bits and Bytes
### Problem Statement
You are given a binary string **S**.
You process it through a series of operations starting from the left where:
1) In the first operation, you remove the first bit of the number and append it to the right.
2) In the second operation, you remove the first 2 bits of the processed string one by one and append them to the right.
3) In the third operation, you now remove the first 3 bits of the new string one by one and append them to the right.
4) In the ith operation, you remove the first i bits of the new string one by one and append them to the right.
You have to find the minimum number of operations it takes to get back the original string.
Number of operations cannot be 0.
**Constraints:**
```
1 <= length of S <= 10^5
```
**Input:**
```
S : Binary string
```
**Output:**
```
Minimum number of operations to get back the
original string.
```
**Example:**
```
Input:
S: 111
Output:
1
In the first operation, the leftmost bit (1)
gets appended to the end of the string, and you
get the same string as the original, hence
answer is 1.
Input:
S: 101
Output:
2
In the first operation, the leftmost bit (1)
gets appended to the end of the string, and you
get the string 011.
In the second operation, the 2 leftmost bits get
appended to the end (011 => 110 => 101), we get
the same string as the original, hence answer is
2.
```
### Brute Force
- For every i from 1 to $\infty$, We can rotate the string by i digits and check if the new string is same as the original string.
- Time Complexity, We may run into an infinity loop.
- Suppose we can be sure that we will get our result in $O(n)$. For every i we will need $O(n)$ time. So, the total time will be $O(n^2)$.
### Hints
- We can see that by $i^{th}$ operation we will have rotated $\frac{i*(i+1)}{2}$ times. Let's call this $T_i$.
- If for some $i$, $T_i$ is divisible by $len(s)$, we can say we will definetely get our string back.
- For $i = 2* len(s)-1$, $T_i$ will obviously be divisible by $len(s)$.
- So, we can run a loop from $1$ to $2* len(s) -1$ on $i$. And check if $T_i$ will be divisible by $len(s)$ or not.
- This will run in $O(n)$ time.
- Will it give the smallest such i?
- The string may have a pattern repeating over and over again. For example : $s=101101101$, answer will be $2$.
- Can we find the length of the shortest repeating sequence? We can use KMP algorithm to do that.
- What will be the lps of above string? Answer: $LPS = [001123456]$.
- If $len(s)-LPS[len(s)-1]$ divides $len(s)$, $len(s)-LPS[len(s)-1]$ is the length of the repeating sequence.
- Now, we have to match $T_i$ with length of repeating pattern if there is a repeating pattern.
### Code
```C++
typedef long long ll;
ll minLEN(string s,ll lps[]){
lps[0]=0;
ll len=0;
ll p=1;
while(p<s.length()){
if(s[p]==s[len]){
len++;
lps[p]=len;
p++;
}else{
if(len!=0){
len=lps[len-1];
}else{
lps[p]=0;
p++;
}
}
}
len=lps[s.length()-1];
if(s.length()%(s.length()-len)==0){
return s.length()-len;
}else return s.length();
}
int Solution::minOperations(string A) {
ll lps[200003];
ll len=minLEN(A,lps);
ll ans;
for(ll i=1;;i++){
if((i*(i+1)/2)%len==0){
ans=i;
break;
}
}
return ans;
}
```
### Time Complexity
- $i$ ranges from $1$ to $2* len(s)$ in worst case. For each i we do constant amount of work. Thus the time complexity will be $O(n)$.
- KMP will take $O(n)$ additional time.
### Dry Run
```
s = 100100100
lps = [0,0,0,1,2,3,4,5,6]
length we need = 9-6 = 3
i = 2 , T_i = 3
answer = 2
```
## Conditional Swaps
### Problem Statement
Given an array A consisting of every number from 1 to N arranged in a random order.
It is also possible to swap a particular element at index i with an element at index i+1 for a particular set of indices.
The indices for which these swaps are allowed are given in the form of a string S of 1's and 0's.
If the i'th position of a string has 1, then it is possible to swap the i'th element of index with the (i+1)'th element else it is not allowed.
There is no limit on the number of swaps allowed, that is, you can make any number of swaps (as long as they are valid).
Find if it is possible to arrange the array in ascending order using any amount of swaps.
**Constraints:**
```
1. 2 <= N <= 100000
2. String S contains n-1 characters and is
made up of only 0's and 1's.
```
**Input:**
Integer N (size of array) , array of containing elements from 1 to N in random order, string S made up of 1's and 0's
**Output:**
Return a string "YES" if it is possible to arrange array in ascending order, else return "NO".
**Example:**
Input:
```
N:6
Array:[1 2 5 3 4 6]
S:01010
```
Function return:
```
NO
```
### Brute Force
- We can try to run bubble sort or insertion sort on the array based on the string S.
- If in any step of bubble sort we encounter that we can not swap an element which needs to be swaped we output "NO". If we are able to sort the array, we output "YES".
- Time Complexity: $O(n^2)$.
### Hints
- Can we take element at position $i$ and bring it to position $j$ if there are $0's$ between $i$ and $j-1$? No.
- Numbers are between $1$ to $N$. So, we already know the exact position of every entry.
- Can we not just check if the current position of an element and its sorted position are swapable? Yes
- Can we use prefix sum to do the above in $O(1)$ time? Yes
### Code
```C++
typedef int ll;
string Solution::solve(int A, vector<int> &B, string C) {
ll n,use;
n=A;ll arr[n+1];
// cin>>use;
for(ll i=1;i<=n;i++)
{
arr[i]=B[i-1];
}
string s,ans;
s=C;
ll pref[n];
pref[1]=s[0]-'0';
for(ll i=2;i<n;i++)
{
pref[i]=pref[i-1]+s[i-1]-'0';
}
ll flag=0;
for(ll i=1;i<=n;i++)
{
ll temp=arr[i];
if(i<temp)
{
if(i==1)
{
if(pref[temp-1]==temp-i or i==temp)
continue;
else
{
ans="NO";
flag=1;
break;
}
}
else
{
if(pref[temp-1]-pref[i-1]==temp-i or i==temp)
continue;
else
{
ans="NO";
flag=1;
break;
}
}
}
else
{
if(temp==1)
{
if(pref[i-1]==i-temp or i==temp)
continue;
else
{
ans="NO";
flag=1;
break;
}
}
else
{
if(pref[i-1]-pref[temp-1]==i-temp or i==temp)
continue;
else
{
ans="NO";
flag=1;
break;
}
}
}
}
if(!flag)
ans="YES";
return ans;
}
```
### Time Complexity
- The above algorithm runs in $O(n)$ time.
### Dry Run
```
N:6
Array:[1 2 5 3 4 6]
S:01010
Sorted Position: [0 1 4 2 3 5]
Prefix Sum Array: [0 1 0 1 0]
```
|i|Sorted Position| Equal| Is it possible to Move|
|:--|:--|:--|:--|
|0|0|Yes|-|
|1|1|Yes|-|
|2|4|No|No|
|Break ||||
## Random Attendance
### Problem Statement
Dr. Dhruv is a superb professor of Mathematics. He is so lenient that he doesn't even take attendance. But his students are not so cooperative.
Frustrating of all aspects is that students have stopped attending classes of Dr. Dhruv. Dr. Dhruv is really disappointed and he has decided to start taking attendance. There are A students in his class. Ordinary professors take a roll call as [1, 2, 3, ..., A] but Dr. Dhruv is no ordinary man. He has come up with a different method of taking roll call. His method is as follows:
He has a list B of K random integers which means that he will call out only K students. He will first treat the numbers [1, 2, 3, .., A] as strings
["1", "2", "3", .., "A"]. Then he will sort this vector of strings in lexicographic order (see example below). Now, Dr. Dhruv will call the numbers
which are at B[i]-th (0 <= i < K) position in the sorted order (see example below).
Simply putting, if the sorted order is S, then he will call students in the order { S[B[0] - 1], S[B[1] - 1], ..., S[B[K-1] - 1] }. You need to output the numbers in the sequence that Dr. Dhruv will call.
Note: Dr. Dhruv needs this task to finish quickly and hence expected time complexity `O(K*log(A))`
**Constraints:**
```
1 <= K <= 1000 and K <= A
1 <= B[i] <= A (Elements of B may not be distinct,
i.e, he can call a student multiple times)
1 <= A <= 10^9 (Yes, Dr. Dhruv can teach
10^9 students at a time)
```
**Example:**
```
Input:
A = 12, B = [2, 5]
Output:
ans = [10, 2]
Sorted list S: ["1", "10", "11", "12",
"2", "3", "4", "5", ...., "9"]
ans = [2nd number, 5th number] = [10, 2]
```
### Brute Force
- We can create a list of strings S: ["1", "2","3","4"...,"A"].
- We can sort this list.
- And for every i store S[B[i]-1] in answer array.
- This approach will take $O(k\times n\log^2{n})$.
- This will give TLE.
### Hints
- Without creating S, can we calculate the number of elements starting with "1".
|Number Of Digits|Numbers|Total|
|:--|:--|:--|
|1|1|1|
|2|10,11, ... 19|11|
|3|100, 101, ... 199|111|
- For every digit we can calculate the number of elements starting with that digit.
- We can calculate this number for every position in the answer.
### Code
```C++
//Note: Two functions are defined just
//for the sake of understanding.
//function_one and function_two can be
//combined into one function using a flag variable
/*
function_two(n,k) computes the rest
of the digits of the kth required number.
*/
string function_two(string s, int k){
// Base case, first string is empty in this case
if(k==1) return "";
k-=1; //Don't consider empty string
int l = s.size();
int f = s[0]-'0';
int temp = stoi(string(l,'1')); // 1111111... l digits
//Case when length of s is 1
if(l==1) return to_string(k-1);
string rem = s.substr(1);
//Note that i here starts from 0
for(int i=0; i<10; i++){
//Here we calculate the number
//of numbers starting from i.
//There will be multiple cases
//to handle which becomes clear
//after a little thinking.
if(i == f) temp/=10;
int buffer = temp;
if(i == f) buffer += stoi(rem) + 1;
if(k > buffer){
k-=buffer;
continue;
}
if(i == f) return to_string(i) + function_two(rem, k);
return to_string(i) + function_two(to_string(9*(temp/10)), k);
}
}
/*
function_one(n,k) computes the first
digit of the kth required number.
function_one and function_two are
separate as 1st digit can't be zero whereas
rest of the digits can be zero.
*/
string function_one(string s, int k){
int l = s.size(); //length of the number
int f = s[0]-'0'; //first digit of the number
int temp = stoi(string(l,'1')); // 1111111... l digits
//Base case, only 1 digit number
if(l==1) return to_string(k);
//Utility string, used below in the for loop
string rem = s.substr(1);
//find the number of numbers say
//num starting from x (x <= i).
//if k > num, first digit is not i,
//else first digit is i.
//Note that i here starts from 1.
for(int i=1; i<10; i++){
//Here we calculate the number of
//numbers starting from i.
//There will be multiple cases
//to handle which becomes clear
//after a little thinking.
if(i == f) temp/=10;
int buffer = temp;
if(i == f) buffer += stoi(rem) + 1;
if(k > buffer){
k-=buffer;
continue;
}
if(i == f) return to_string(i) + function_two(rem, k);
return to_string(i) + function_two(to_string(9*(temp/10)), k);
}
}
vector<int> Solution::solve(int A,const vector<int> &B){
string str = to_string(A);
int m = B.size();
vector<int> ans(m);
//function_one(n,k) give kth
//number in the sorted order of strings ["1", "2", ..., "n"]
for(int i=0; i<m; i++)
ans[i] = stoi(function_one(str,B[i]));
return ans;
}
```
### Time Complexity
- This approach will work in $O(k \times \log{n})$. Because there are $O(\log{n})$ digits in A and every digit take $O(1)$ time.
### Dry Run
```
A : 5789
B : [ 1789]
```
|Place|Digits|Rank|Numbers with Digit|
|:--|:--|:--|:--|
|1|1|1789|1111|
|1|2|678|1111|
|2||||
|Empty will first element||||
|2|0|677|111|
|2|1|566|111|
|2|2|455|111|
|2|3|344|111|
|2|4|233|111|
|2|5|122|111|
|2|6|11|111|
|26||||
|3|0|10|11|
|260||||
|4|0|9|1|
|...||||
|4|8|1|1|
|2608||||

View File

@@ -0,0 +1,366 @@
# Miscelleneous Problems 20
## Balls in Boxes
### Problem Statement
Given an array of integers **A** of size **N** and an another array of strings **B** of size **N**. Each string in **B** is binary and of exact size **10**.
There are some Boxes having following characterstics:-
```
A[i] represents the cost of ith Box.
One Box can contain atmost 10 different colored balls in it.
B[i][j] = '1' indicates that ith Box contains jth colored ball.
B[i][j] = '0' indicates that ith Box doesn't contains jth colored ball.
```
Find and return **minimum** amount of money needed to buy the boxes such that you have **maximum distinct colored balls** in the end.
**Input Format**
```
The first argument given is the integer array A.
The second argument given is the string array B.
```
**Output Format**
```
Return minimum amount of money needed to buy the boxes such that you have maximum distinct
colored balls in the end.
```
**Constraints**
```
1 <= N <= 10000
0 <= A[i] <= 10^9
B[i][j] = {'0' ,'1'}
```
**For Example**
```
Example Input 1:
A = [20, 10, 9]
B = ["0110001010",
"0111110000", "1111111111"]
Example Output 1:
9
Example Explanation 1:
As box 3 contains balls of all colors, buying only this box is sufficient.
Input 2:
A = [20, 10, 9]
B = ["0110001010",
"0111110001", "1111111110"]
Output 2:
19
```
### Brute Force
- We can consider all subsets of boxes. For each subset we can calculate the total number of distinct balls and total cost to buy.
- Now, we can find the minimum cost among all the subsets with maximum distint balls.
- This approach will take $O(2^A \times A)$
### Hints
- With the brute force we are taking subsets of boxes. Can we take subsets of balls?
- For a given subset of balls we have to find the minimum cost to get that subset using first i boxes.
- At a given dp state, we have two variables a mask and an index. Now, we have the choice either to take index'th box or not to take it.
- We can calculate the maximum possible distinct balls. Now, after running the loop if we find that the number of ones in the mask is less than maximum we can set that dp to be Infinity. This will make sure that we ignore all the cases where our 1-count will be less than max possible.
### Code
```C++
#include <iostream>
#include <cstdio>
#include <cassert>
#include <fstream>
#include <set>
#define lli long long
#define MAX 10004
#define INF 10000000000000000LL
using namespace std;
int mx;
lli A[MAX];
int val[MAX];
bool vis[MAX][1024];
lli dp[MAX][1024];
int n;
void validate(string s)
{
int sz = (int)s.size();
assert(sz == 10);
for ( int i = 0; i < 10; i++ ) assert(s[i] == '0' || s[i] == '1');
}
lli f(int idx, int mask)
{
if ( idx == n ) {
if ( __builtin_popcount(mask) == mx ) return 0;
return INF;
}
if ( vis[idx][mask] ) return dp[idx][mask];
vis[idx][mask] = true;
lli ans = min(f(idx + 1, mask), A[idx] + f(idx + 1, mask | val[idx]));
dp[idx][mask] = ans;
return ans;
}
int main()
{
freopen("inp5.txt", "r", stdin);
freopen("out5.txt", "w", stdout);
string s;
set <int> distinctBalls;
cin >> n;
assert(n >= 1 && n <= 10000);
for ( int i = 0; i < n; i++ ) {
cin >> A[i];
cin >> s;
assert(A[i] >= 0 && A[i] <= 1000000000);
validate(s);
for ( int j = 0; j < 10; j++ ) {
if ( s[j] == '1' ) distinctBalls.insert(j), val[i] |= (1 << j);
}
}
mx = (int)distinctBalls.size();
cout << f(0, 0) << endl;
return 0;
}
```
### Time Complexity
- Since we are calculating the every dp state only once. The time complexity will be $O(n \times 2^{10})$.
### Dry Run
- Let's say we have only two colors.
- N = 3
- A = {5, 10, 20}
- B = {10, 01, 11}
|Mask|Index|Dp|Expression(min)|
|:--|:--|:--|:--|
|00|0|15 |dp[1][00],A[0](=5) + dp[1][10]|
|00|1|20 |dp[2][00],A[1](=10) + dp[2][01]|
|10|1|10 |dp[2][10],A[1](=10) + dp[2][11]|
|00|2|20 |dp[3][00],A[2](=20) + dp[3][11]|
|01|2|20 |dp[3][01],A[2](=20) + dp[3][11]|
|10|2|20 |dp[3][10],A[2](=20) + dp[3][11]|
|11|2|0 |dp[3][11],A[2](=20) + dp[3][11]|
|00|3|INF||
|01|3|INF||
|10|3|INF||
|11|3|0| |
## The Ghost Type
### Problem Statement
Gengar has got an integer **A**. Now using his ghostly powers, he can create the permutation from **1** to **A** of this given number.
Since, he's a special kind of Poke'mon, so he thinks he deserves special permutations. He wants to find the total number of special permutations of length **N**, consisting of the integers from **1** to **A**.
A permutation is called special if it satisfies following condition:
If **P<sub>x</sub> & P<sub>y</sub> == P<sub>x</sub>**, then **x** < **y**, where **x** and **y** are two distinct indices of permutation and **P** is the permutation itself. "**&**" denotes the bitwise and operation.
Help Gengar in finding the number of such permutations.
**Input Format:**
```
First and only argument of
input conatins a single integer A
```
**Output Format:**
Ouput a string denoting the answer.
**Constraints:**
1 <= A <= 20
**For Example:**
```
Example Input 1:
A = 3
Example Output 1:
2
Explanation 1:
Special Permutation are: [1, 2, 3] and [2, 1, 3]
Example Input 2:
A = 4
Example Output 2:
8
```
### Brute Force
- Given a permutation we can check in $O(n^2)$ time whether it is special or not.
- We can consider all the permutations of $1...A$. Then we can count special permutations.
- This approach will take $O(2^n \times n^2)$.
### Hints
- If we look at a subset of numbers which are already there in the permutation from $1...i$, we can choose the next number to include.
- Next element to include will be one whose all x's are included.
- Thus if we start from an empty subset, we can build the complete set in buttom up manner.
### Code
```C++
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cassert>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define ll long long int
#define pi pair<ll,ll>
#define pii pair<ll,pi>
#define f first
#define mp make_pair
#define mod 1000000007
#define s second
#define pb push_back
vector<int>submask[22];
bool vis[1<<22];
ll dp[1<<22];
int N;
ll rec(int mask){
if(mask==(1<<(N+1))-2) return 1;
if(vis[mask]) return dp[mask];
vis[mask] = 1;
ll &ret = dp[mask];
ret=0;
int x;
for(int i=1;i<=N;i++){
if(!(mask&(1<<i))){
bool ok = true;
for(int j = 0; j < submask[i].size(); j++){
x = submask[i][j];
if(!(mask&(1 << x ))) ok=false;
}
if(ok){
ret += rec(mask|(1<<i));
}
}
}
return ret;
}
int main(){
for(int i=1;i<=20;i++){
for(int j=i-1;j>=1;j--){
if( (i&j)==j ) submask[i].pb(j);
}
}
cin >> N;
cout<<rec(0);
}
```
### Time Complexity
- We are running a loop of $O(n)$ for every mask. For every candidate we need to check with all its x's. That will also take $O(n)$ time.
- Thus the total time will be $O(n! \times 2^n)$.
### Dry Run
- N = 4
- Submask
- 1(001) : {}
- 2(010) : {}
- 3(011) : {1,2}
- Dp
|Mask|Expression|Dp Value|
|000|dp[001] + dp[010]|2|
|001|dp[011]|1|
|010|dp[011]|1|
|011|dp[111]|1|
|111| | 1|
## Micro and Lucky Tree
### Problem Statement
Micro purchased a tree having **A** nodes numbered from **1** to **A**. It is rooted at node numbered **1**. But unfortunately that tree turned out to be bad luck. After he purchased that tree, he lost his job and girlfriend. So he went to his astrologer friend Mike for help.
Mike told him to assign a value in the range **1** to **B** (inclusive) to each node making sure that luck factor of all leaf nodes is **1**. Luck factor of a leaf node **v** is defined as *gcd* of values of all nodes lying in path from root to **v** (inclusive). Now Micro wants to know how many ways are there to make his tree lucky. That's where Mike failed, so he asked for your help.
**Input Format:**
```
First argument of input is a integer A
Second argument of input is a integer B
Third argument of input is an integer array C of size A. where C[i] denote the parent of i+1 th
node. C[0] = 1
```
**Output Format:**
```
Return a single integer denoting
answer mod 1000000007
```
**Constraints:**
```
1 <= A <= 50000
1 <= M <= 30
1 <= C[i] <= A
```
**For Example:**
```
Example Input 1:
A = 3, B = 2, C = [1, 1, 1]
Example Output 1:
5
Explanation 1:
possible values of node1, node2,
node3 are:
(2, 1, 1)
(1, 1, 2)
(1, 2, 2)
(1, 1, 1)
(1, 2, 1)
Example Input 2:
A = 4, B = 3, C = [1, 3, 1, 3]
Example Output 2:
71
```
### Brute Force
- We can take all arrangements and test the conditions by doing a traversal on the tree. This will take $O(n)$ per arrangement.
- This approach will take $O(A^B \times A)$.
### Hints
- If we can calculate the number of arrangements possible, for a sub tree rooted at a given node, we can solve this question.
- All we need to know is the gcd of all the numbers till that node.
### Code
```Python
dfs(from, g)
{
if DP[from][g] != -1:
// If we have already computed the values we will just return it
return DP[from][g]
if node from is a leaf:
ret = 0
for i from 1 to m: // Trying all the possible values at leaf
if gcd(i, g) == 1: // and checking number of integers, i, assigned at leaf
ret = ret + 1 // such that gcd(i, j)=1
dp[from][g] = ret
return ret
ret = 0
for i from 1 to m: // Trying all the possible values at node i (from 1 to m)
g1 = gcd(i, g) // and compute the GCD of values of all nodes lying in path from 1 to i
ways = 1 // and pass it in the DFS call to children of i
for to = children of node from // Computing the value \(DP\) of the node
ways = (ways * dfs(to, g1)) // by multiplying the values of the children
ret = (ret + ways)
dp[from][g] = ret
return ret
}
```
### Time Complexity
- $O(A \times B)$.
### Dry Run
```
Tree:
1
/ \
2 3
```
B = 3
```
1 -> 9
2 -> 4
3 -> 4
---------
17
```

View File

@@ -0,0 +1,235 @@
Recursion
----------
Recursion - process of function calling itself
directly or indirectly.
__Steps involved:__
- Base case
- Self Work
- Recursive Calls
```python
def fib(n):
if n <= 1 : return n # base case
return fib(n-1) + fib(n-2) # recursive calls
fib(10) # initial call
```
In the recursive program, the solution to the base case is provided and the solution of the bigger problem is expressed in terms of smaller problems.
In the above example, base case for n < = 1 is defined and larger value of number can be solved by converting to smaller one till base case is reached.
__Intuition__
The main idea is to represent a problem in terms of one or more smaller problems, and add one or more base conditions that stop the recursion.
_For example_, we compute factorial n if we know factorial of (n-1). The base case for factorial would be n = 0. We return 1 when n = 0.
Power
-----
> Given n, k. Find $n^k$
```python
def pow(n, k):
if k == 0: return 1
return n*pow(n, k - 1)
```
__Time Complexity__: O(n)
__Optimised solution:__
```python
def pow(n, k):
if k == 0: return 1
nk = pow(n, k//2)
if k % 2 == 0:
return nk * nk
else:
return nk * nk * n
```
Why not f(n, k/2) * f(n, k/2+1) in the else condition?
To allow reuse of answers.
<img src="https://user-images.githubusercontent.com/35702912/66316190-d30e1f00-e934-11e9-8089-85c6dc69baa7.jpg" data-canonical-src="https://user-images.githubusercontent.com/35702912/66316190-d30e1f00-e934-11e9-8089-85c6dc69baa7.jpg" width="500" />
__Time Complexity__ (assuming all multiplications are O(1))? O(\log_2 k)$O(\log_{2}k)$
Break it into 3 parts? k//3 and take care of mod1 and mod2.
Binary is still better, just like in binary search.
-- --
All Subsets
-----------
> Given A[N], print all subsets
The idea is to consider two cases for every element.
(i) Consider current element as part of current subset.
(ii) Do not consider current element as part of current subset.
Number of subsets? $2^{n}$
Explain that we want combinations, and not permutations. [1, 4] = [4, 1]
Number of permutations will be much larger than combinations.
```python
def subsets(A, i, aux):
if i == len(A):
print(aux)
return
take = subsets(A, i+1, aux + [A[i]]) # Case 1
no_take = subsets(A, i+1, aux) # Case 2
```
<img src="https://user-images.githubusercontent.com/35702912/66323471-7a914e80-e941-11e9-84a9-11a333ac4f77.jpg" width="500"
/>
How many leaf nodes? $2^n$ - one for each subset
How many total nodes? $2^{n+1} - 1$
__Time Complexity__: $O(2^n)$
Subsets using Iteration
-----------------------
Look at recursion Tree.
Going left = 0
Going right = 1
Basically, for each element, choose = 1, skip = 0
So, generate numbers from 0 to $2^n-1$ and look at the bits of the numbers. Each subset is formed using each number.
```
For A = [1 2 3]
000 []
001 [c]
010 [b]
011 [b c]
100 [a]
101 [a c]
110 [a b]
111 [a b c]
```
Lexicographic subsets
---------------------
Explain what is lexicographic order.
```
For Array [0,1,2,3,4] Subsets in Lexicographical order,
[]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 3]
[0, 2]
[0, 2, 3]
[0, 3]
[1]
[1, 2]
[1, 2, 3]
[1, 3]
[2]
[2, 3]
[3]
```
- The idea is to sort the array first.
- After sorting, one by one fix characters and recursively generates all subsets starting from them.
- After every recursive call, we remove current character so that next permutation can be generated.
- Basically, we're doing DFS. Print when encountering node
But don't print when going left - because already printed in parent.
<img src="https://user-images.githubusercontent.com/35702912/66468106-3d44d200-eaa3-11e9-96e7-c6a050be1219.jpg" width="500"
/>
<img src="https://user-images.githubusercontent.com/35702912/66468119-42098600-eaa3-11e9-8f24-237be2a91d12.jpg" width="500"
/>
```python
def subsets(A, i, aux, p):
if p: print(aux)
if i == len(A):
return
take = subsets(A, i+1, aux + [A[i]], True)
no_take = subsets(A, i+1, aux, False)
```
__Time Complexity__: $O(2^n)$ <br>
__Space Complexity__: $O(n^2)$, because we're creating new aux arrays.
-- --
Number of Subsets with a given Sum
--------------------
> Given an array of integers and a sum, the task is to print all subsets of given array with sum equal to given sum.
> A = [2, 3, 5, 6, 8, 10] Sum = 10
> Output: [5, 2, 3] [2, 8] [10]
The subsetSum problem can be divided into two subproblems.
- Include the current element in the sum and recur (i = i + 1) for the rest of the array
- Exclude the current element from the sum and recur (i = i + 1) for the rest of the array.
<img src="https://user-images.githubusercontent.com/35702912/66469192-11c2e700-eaa5-11e9-9094-252ce842464a.jpg" width="500"
/>
```python
def subsetSum(A,N,cur_sum, i, target):
if i == N:
if cur_sum == target:
return 1
else :
return 0
take = subsetSum(A,N,cur_sum + A[i], i+1, target)
no_take = subsetSum(A,N,cur_sum, i+1, target)
return take + no_take
```
Why can't terminate earlier when cur_sum == target?
Because we can have negative values in the array as well and this condition will prevent us from considering negative values.
For eg,
target = 6
1, 2, 3 is good, but
1, 2, 3, -1, 1 is also good.
__Time Complexity__: $O(2^n)$
__Space Complexity__: $O(n)$
Number of Subsets with a given Sum (Repetition Allowed)
---------------
> Given a set of m distinct positive integers and a value N. The problem is to count the total number of ways we can form N by doing sum of the array elements. Repetitions and different arrangements are allowed.
> All array elements are positive.
The subsetSum2 problem can be divided into two subproblems.
- Include the current element in the sum and recur for the rest of the array. Here the value of i is not incremented to incorporate the condition of including multiple occurances of a element.
- Exclude the current element from the sum and recur (i = i + 1) for the rest of the array.
<img src="https://user-images.githubusercontent.com/35702912/66470200-c27db600-eaa6-11e9-8744-ca572d6000e1.jpg" width="500"
/>
```python
def subsetSum2(A,N,cur_sum, i, target):
if i == N:
if cur_sum == target:
return 1
else :
return 0
elif cur_sum > target:
return 0;
take = subsetSum2(A,N,cur_sum + A[i], i, target)
no_take = subsetSum2(A,N,cur_sum, i+1, target)
return take + no_take
```
__Time Complexity__ : $O(2 ** (Target/MinElement))$ <br>
__Space Complexity__: $O(Target/Min Element)$

View File

@@ -0,0 +1,165 @@
Backtracking
------------
Backtracking is a methodical way of trying out various sequences of decisions, until you find one that “works”. It is a systematic way to go through all the possible configurations of a search space.
- do
- recurse
- undo
Backtracking is easily implemented with recursion because:
- The run-time stack takes care of keeping track of the choices that got us to a given point.
- Upon failure we can get to the previous choice simply by returning a failure code from the recursive call.
Backtracking can help reduce the space complexity, because we're reusing the same storage.
__Backtracking Algorithm__:
Backtracking is really quite simple--we “explore” each node, as follows:
```python
To explore node N:
1. If N is a goal node, return success
2. If N is a leaf node, return failure
3. For each child C of N,
3.1. Explore C
3.1.1. If C was successful, return success
4. Return failure
```
Print all Permutations of a String
-------------
> A permutation, also called an “arrangement number” or “order,” is a rearrangement of the elements of an ordered string S into a one-to-one correspondence with S itself. <br>
String: ABC <br>
Permutations: ABC ACB BAC BCA CBA CAB
Total permutations = n!
<img src="https://user-images.githubusercontent.com/35702912/66570095-7e63e180-eb8a-11e9-8e3c-31d8e04f2d67.jpg" width="500"
/>
<img src="https://user-images.githubusercontent.com/35702912/66570104-83c12c00-eb8a-11e9-802d-f0f0ede4a14a.jpg" width="500"
/>
```python
def permute(S, i):
if i == len(S):
print(S)
for j in range(i, len(S)):
S[i], S[j] = S[j], S[i]
permute(S, i+1)
S[i], S[j] = S[j], S[i] # backtrack
```
__Time Complexity:__ _O(n*n!)_ because there are n! permutations and it requires _O(n)_ to print a permutation.
<br>
__Space Complexity:__ _O(n)_
_Note: Output not in Lexicographic Order._
Print all Unique Permutations of a String
--------------------
> String: AAB
> Permutations: AAB ABA BAA
Basically, if we're swapping S[i] with S[j], but S[j] already occured earlier from S[i] .. S[j-1], then swapping will result in repetition.
<img src="https://user-images.githubusercontent.com/35702912/66570690-bc153a00-eb8b-11e9-8a00-9dfb728df5f9.jpg" width="500"
/>
```python
def permute_distinct(S, i):
if i == len(S):
print(S)
for j in range(i, len(S)):
if S[j] in S[i:j]:
continue
S[i], S[j] = S[j], S[i]
permute_distinct(S, i+1)
S[i], S[j] = S[j], S[i] # backtrack
```
__Time Complexity:__ _O(n*n!)_ <br>
__Space Complexity:__ _O(n)_
Print Permutations Lexicographically
---
> Given a string, print all permutations of it in sorted order. <br>
For example, if the input string is “ABC”, then output should be “ABC, ACB, BAC, BCA, CAB, CBA”.
- Right shift the elements before making the recursive call.
- Left shift the elements while backtracking.
```python
def permute(S, i):
if i == len(S):
print(S)
for j in range(i, len(S)):
S[i], S[j] = S[j], S[i]
permute(S, i+1)
S[i], S[j] = S[j], S[i] # backtrack
```
__Time Complexity:__ _O(n* n*n!)_ <br>
__Space Complexity:__ _O(n)_
Kth Permutation Sequence (Optional)
----
> Given a string of length n containing lowercase alphabets only. You have to find the k-th permutation of string lexicographically.
$\dfrac{k}{(n-1)!}$ will give us the index of the first digit. Remove that digit, and continue.
```python
def get_perm(A, k):
perm = []
while A:
# get the index of current digit
div = factorial(len(A)-1)
i, k = divmod(k, div)
perm.append(A[i])
# remove handled number
del A[index]
return perm
```
Sorted Permutation Rank (Optional)
--
> Given S, find the rank of the string amongst its permutations sorted lexicographically.
Assume that no characters are repeated.
```
Input : 'acb'
Output : 2
Explanation:
The order permutations with letters 'a', 'c', and 'b' :
abc
acb
bac
bca
cab
cba
```
**Hint:**
If the first character is X, all permutations which had the first character less than X would come before this permutation when sorted lexicographically.
Number of permutation with a character C as the first character = number of permutation possible with remaining $N-1$ character = $(N-1)!$
**Approach:**
rank = number of characters less than first character * (N-1)! + rank of permutation of string with the first character removed
```
Lets say out string is “VIEW”.
Character 1 : 'V'
All permutations which start with 'I', 'E' would come before 'VIEW'.
Number of such permutations = 3! * 2 = 12
Lets now remove V and look at the rank of the permutation IEW.
Character 2 : I
All permutations which start with E will come before IEW
Number of such permutation = 2! = 2.
Now, we will limit ourself to the rank of EW.
Character 3:
EW is the first permutation when the 2 permutations are arranged.
So, we see that there are 12 + 2 = 14 permutations that would come before "VIEW".
Hence, rank of permutation = 15.
```

View File

@@ -0,0 +1,109 @@
Number of Squareful Arrays
--------------------------
> Given A[N]
> array is squareful if for every pair of adjacent elements, their sum is a perfect square
> Find and return the number of permutations of A that are squareful
>
Example:
A = [2, 2, 2]
output: 1
A = [1, 17, 8]
output: 2
[1, 8, 17], [17, 8, 1]
```python
def check(a, b):
sq = int((a + b) ** 0.5)
return (sq * sq) == (a + b)
if len(A) == 1: # corner case
return int(check(A[0], 0))
count = 0
def permute_distinct(S, i):
global count
if i == len(S):
count += 1
for j in range(i, len(S)):
if S[j] in S[i:j]: # prevent duplicates
continue
if i > 0 and (not check(S[j], S[i-1])): # invalid solution - branch and bound
continue
S[i], S[j] = S[j], S[i]
permute_distinct(S, i+1)
S[i], S[j] = S[j], S[i] # backtrack
permute_distinct(A, 0)
return count
```
Gray Code
---------
> Given a non-negative integer N representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
> The gray code is a binary numeral system where two successive values differ in only one bit.
G(n+1) can be constructed as:
0 G(n)
1 R(n)
```
Example G(2) to G(3):
0 00
0 01
0 11
0 10
----
1 10
1 11
1 01
1 00
```
```python
def gray(self, n):
codes = [0, 1] # length 1
for i in range(1, n):
new_codes = [s | (1 << i) for s in reversed(codes)]
codes += new_codes
return codes
```
N Queens
--------
[NQueens - InterviewBit](https://www.interviewbit.com/problems/nqueens/)
Backtracking
- Place one queen per row
- backtrack if failed
Word Break II
-------------
> Given a string A and a dictionary of words B, add spaces in A to construct a sentence where each word is a valid dictionary word.
```
Input 1:
A = "catsanddog",
B = ["cat", "cats", "and", "sand", "dog"]
Output 1:
["cat sand dog", "cats and dog"]
```python
def wordBreak(A, B):
B = set(B)
sents = []
def foo(i, start, sent):
word = A[start:i+1]
if i == len(A):
if word in B:
sents.append((sent + ' ' + word).strip())
return
if word in B:
foo(i+1, i+1, sent + ' ' + word)
foo(i+1, start, sent)
foo(0, 0, '')
```

View File

@@ -0,0 +1,169 @@
# Sorting
- Define sorting: permuting the sequence to enforce some order.
- Brute force Approach: $O(n! \times n)$.
Here n! is for finding out all the permutations for a list of number and n is for traversing all the permutations to pick the relevant one.
## Sorting Terminologies
__Stability__
- __Definition__: A sorting algorithm is said to be stable if two objects with equal keys appear in the same order in sorted output as they appear in the input array to be sorted.
- __Importance:__
- preserving order - values could be orders and chronological order may be important.
- sorting tuples - sort on first column, then on second column. s
- __Example__: Bubble Sort, Insertion Sort, Selection Sort etc.
__In-Place Sorting__
- __Definition__: In-Place Sorting algorithms uses constant extra space to produce the output. <br>
- **Example:** Insertion Sort, Selection Sort
Insertion Sort
--------------
**Explain:** <br>
- 1st element is sorted.
- Invariant: for i, the array uptil i-1 is sorted.
- Take the element at index i, and insert it at correct position.
**Pseudo code:**
```c++
void insertionSort(int arr[], int length) {
int i, j, key;
for (i = 1; i < length; i++) {
key = arr[i];
j = i-1;
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
```
- **Stablility:** Yes Stable, because swap only when strictly >. Had it been >=, it would be unstable
- **In Place Sorting**
- **Complexity:** $O(n^2)$
- **Auxiliary Space:** O(1)
- **Boundary Cases:** Insertion sort takes maximum time to sort if elements are sorted in reverse order. And it takes minimum time (Order of n) when elements are already sorted.
- **Uses:** Insertion sort is used when number of elements is small. It can also be useful when input array is almost sorted, only few elements are misplaced in complete big array.
Bubble Sort
-----------
**Explain:**
- Invariant: last i elements are the largest one and are in correct place.
- Why "bubble": largest unsorted element bubbles up - just like bubbles.
- Works by repeatedly swapping the adjacent elements if they are in wrong order.
**Pseudo code:**
```c++
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
if (arr[j] > arr[j+1])
swap(&arr[j], &arr[j+1]);
}
```
- **Stability:** Stable
- **Complexity:** $O(n^2)$ ( Worst Case ) $O(n)$ Best Case
- **Auxiliary Space:** O(1)
- **In Place Sorting**
- **Boundary Cases:** Bubble sort takes minimum time ( Order n ) when elements are already sorted.
Bubble Sort with window of size 3
---------------------------------
- Explain bubble sort as window of size 2
- Propose window of size 3
- Does this work?
- No - even and odd elements are never compared
Selection Sort
-----
**Explain**
- Works by repeatedly finding the minimum element from unsorted part and putting it at the beginning.
- The algorithm maintains two subarrays in a given array.
- The subarray which is already sorted.
- Remaining subarray which is unsorted.
- In every iteration of selection sort, the minimum element from the unsorted subarray is picked and moved to the sorted subarray.
**PseudoCode**
```c++
void selectionSort(int arr[], int n)
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n-1; i++)
{
// Find the minimum element in unsorted array
min_idx = i;
for (j = i+1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;
// Swap the found minimum element with the first element
swap(&arr[min_idx], &arr[i]);
}
}
```
**Time Complexity**: $O(n^2)$ <br>
**Space Complexity**: O(1)
Counting Sort
-------------
**Explain:**
- Given array, first find min and max in O(n) time.
- Create space of O(max-min)
- Count the number of elements
- Take prefix sum
- _Constraint_: can only be used when the numbers are bounded.
**Pseudo code:**
```c++
void counting_sort(char arr[]) {
// find min, max
// create output space
// count elements
// take prefix sum
// To make it stable we are operating in reverse order.
for (int i = n-1; i >= 0; i--) {
output[count[arr[i]] - 1] = arr[i];
-- count[arr[i]];
}
}
```
- **Stability:** Stable, if imlpemented correctly
- **Time Complexity**: $O(n + \max(a[i]))$
- why not just put the element there? if numbers/value, can do. Else, could be objects
- **Space Complexity**: $O(n + \max(a[i]))$
Partition Array
---------------
> Array of size $n$
> Given $k$, $k <= n$
> Partition array into two parts $A, ||A|| = k$ and $B, ||B|| = n-k$ elements, such that $|\sum A - \sum B|$ is maximized
- Sort and choose smallest k?
- Counterexample
```
1 2 3 4 5
k = 3
bad: {1, 2, 3}, {4, 5}
good: {1, 2}, {3, 4, 5}
```
- choose based on n/2 - because we want the small sum to be smaller, so choose less elements, and the larger sum to be larger, so choose more elements
-- --

View File

@@ -0,0 +1,26 @@
Radix Sort
----------
- sort elements from lowest significant to most significant values
- explain: basically counting sort on each bit / digit
- **Stability:** inherently stable - won't work if unstable
- **complexity:** $O(n \log\max a[i])$
Sex-Tuples
----------
> Given A[n], all distinct
> find the count of sex-tuples such that
> $$\frac{a b + c}{d} - e = f$$
> Note: numbers can repeat in the sextuple
- Naive: ${n \choose 6} = O(n^6)$
- Optimization. Rewrite the equation as $ab + c = d(e + f)$
- Now, we only need ${n \choose 3} = O(n^3)$
- Caution: $d \neq 0$
- Once you have array of RHS, sort it in $O(\log n^3)$ time.
- Then for each value of LHS, count using binary search in the sorted array in $\log n$ time.
- Total: $O(n^3 \log n)$

View File

@@ -0,0 +1,138 @@
# Sorting 3
Merge Sort
----------
- Divide and Conquer
- didive into 2
- sort individually
- combine the solution
- Merging takes $O(n+m)$ time.
- needs extra space
- code for merging:
```c++
// arr1[n1]
// arr2[n2]
int i = 0, j = 0, k = 0;
// output[n1+n2]
while (i<n1 && j <n2) {
if (arr1[i] <= arr2[j]) // if <, then unstable
output[k++] = arr1[i++];
else
output[k++] = arr2[j++];
}
// only one array can be non-empty
while (i < n1)
output[k++] = arr1[i++];
while (j < n2)
output[k++] = arr2[j++];
```
- stable? Yes
- in-place? No
- Time complexity recurrence: $T(n) = 2T(n/2) + O(n)$
- Solve by Master Theorem.
- Solve by algebra
- Solve by Tree height ($\log n$) * level complexity ($O(n)$)
-- --
Intersection of sorted arrays
-----------------------------
> 2 sorted arrays
> ```
> 1 2 2 3 4 9
> 2 3 3 9 9
>
> intersection: 2 3 9
> ```
- calculate intersection. Report an element only once
- Naive:
- Search each element in the other array. $O(n \log m)$
- Optimied:
- Use merge.
- Ignore unequal.
- Add equal.
- Move pointer ahead till next element
-- --
Merging without extra space
---------------------------
- can use extra time
- if a[i] < b[j], i++
- else: swap put b[i] in place of a[i]. Sorted insert a[i] in b array
- so, $O(n^2)$ time
-- --
Count inversions
---------------
> inversion:
> i < j, but a[i] > a[j] (strict inequalities)
- naive: $O(n^2)$
- Split array into 2.
- Number of inversions = number of inversions in A + B + cross terms
- count the cross inversions by example
- does number of cross inversions change when sub-arrays are permuted?
- no
- can we permute so that it becomes easier to count cross inversions?
- sort both subarrays and count inversions in A, B recursively
- then, merge A and B and during the merge count the number of inversions
- A_i B_j
- if A[i] > B[j], then there are inversions
- num inversions for A[i], B[j] = |A| - i
- intra array inversions? Counted in recursive case.
-- --
Find doubled-inversions
-----------------------
> same as inversion
> just i < j, a[i] > 2 * a[j]
- same as previous. Split and recursilvely count
- while merging, for some b[j], I need to find how many elements in A are greater than 2 * b[j]
- linear search for that, but keep index
- linear search is better than binary search
-- --
Sort n strings of length n each
- $T(n) = 2T(n/2) + O(n^2) = O(n^2)$ is wrong
- $T(n) = 2T(n/2) + O(n) * O(m) = O(nm\log n)$ is correct. Here m = the initial value of n
-- --
> .
>
> I G N O R E
>
> .
Bounded Subarray Sum Count
--------------------------
> given A[N]
> can have -ve
> given lower <= upper
> find numbe of subarrays such that lower <= sum <= upper
- naive: $O(n^2)$ (keep prefix sum to calculate sum in O(1), n^2 loop)
- if only +ve, $O(n\log n)$ using prefix sum
- but what if -ve?
-
-- --