Google's Online Challenge - Coding - Intern Questions approach help

question 1 for single test case

lis = [1,2,3,4,5]
cnt = 0
dic = {}
lis2= []
for i in lis:
cnt = cnt+1
j=cnt

if j<len(lis):
    for k in range(j,len(lis)):
        if i == lis[k]:
            continue
        x = i|lis[k]
        t= i*10+lis[k]
        dic.update( {t : x} )
        if x not in lis2 :
            lis2.append(int(x))
elif(j==len(lis)):
    x = i|lis[0]
    dic.update({ i*10+lis[0] : x} )
    if x not in lis2 :
        lis2.append(int(x))

m= max(lis2)

dic2 = {}
lis3=[]
for k,v in dic.items():
if v == m:
l = list(str(k))
t = int(l[0])+int(l[1])

    dic2.update( {k:t} )
    if t not in lis3 :
        lis3.append(int(t))

y = min(lis3)
c=0
for k,v in dic2.items():
if v == y:
c=c+1
print©

1 Like

We do a dfs from top of the tree to bottom. Each time we go down the tree we pass a position array ‘pos’ of size 500. For example if pos[6]=2, this means node 2 which is an ancestor of current node is the closest ancestor that has value 6.

Now in each node we compare the current nodes value and all the previous nodes using the position array and the closest such node where both values are coprime is the answer for the current node. We do this for all nodes as we go down the tree.

Time complexity 0(n*max value of a node)

1 Like
int ans;

int max_reached=0;

void find_ans(int curr_val, int mx_val, int i, vi &v, int count) {

    

    if(curr_val>=max_reached) {

        if(curr_val==max_reached)

        ans=min(ans, count);

        else

        {

            max_reached=curr_val;

            ans=count;

        }

    }

    if(i==v.size())

    return;

    if(curr_val==mx_val)

    return;

    if(curr_val|v[i]>curr_val)

    find_ans(curr_val|v[i], mx_val, i+1, v, count+1);

    find_ans(curr_val, mx_val, i+1, v, count);

}

    void solve() {

        int n;

        cin >> n;

        ans=n;

        vi v(n);

        FOR(i,n)

        cin >> v[i];

        int mx = *max_element(v.begin(), v.end());

        mx = (1<< ((int)log2(mx)+1))-1;

        //max:  5 --> log2(5) --> 2 + 1 == size; max_bit to activate

        find_ans(0, mx, 0, v, 0);

        cout << ans << '\n';

    }
1 Like

For smallest subset. complexity of this code should 10^10 on given constraint. I think it can be reduced if we use dp such curr_val is used as bitset or string that way we only require maximum 20*10^5 space. if i apply dp directly on curr_val then space complexity will be 10^11 if we use map can be further reduced.

1 Like

hey, i solved one full and another almost as i got 27/30 in the second. so my total was 57/60. pls share if you are contacted.

/*Closest Pair problem Google */

#include<bits/stdc++.h>
using namespace std;

int n;
vector g[10000+5];
int val[10000+5];
int vis[10000+5]={0};
int ans[10000+5]={100};
vectorinside;

void dfs(int v,vector& inside){

vis[v]=1;
int in=inside.size();
int flag=1;
for(int i=in-1;i>=0;i–){
if(__gcd(val[v],val[inside[i]])==1){
ans[v]=inside[i];
flag=0;
break;
}
}
if(flag){
ans[v]=-1;
}

inside.push_back(v);
for(int i=0;i<g[v].size();i++){
if(vis[g[v][i]]==0)
dfs(g[v][i],inside);
}
inside.pop_back();
}

int main(){
cin>>n;

for(int i=1;i<=n;i++){
   int x;
   cin>>x;
   val[i]=x;
}

for(int i=1;i<=n-1;i++){
    int x,y;
    cin>>x>>y;
    g[x].push_back(y);
    g[y].push_back(x);
}
dfs(1,inside);

for(int i=1;i<=n;i++){
    cout<<ans[i]<<" ";
}
cout<<endl;

}

/*Closest Pair
*/
#include<bits/stdc++.h>
using namespace std;

int n;
vector g[10000+5];
int val[10000+5];
int vis[10000+5]={0};
int ans[10000+5]={100};
vectorinside;

void dfs(int v,vector& inside){

vis[v]=1;
int in=inside.size();
int flag=1;
for(int i=in-1;i>=0;i–){
if(__gcd(val[v],val[inside[i]])==1){
ans[v]=inside[i];
flag=0;
break;
}
}
if(flag){
ans[v]=-1;
}

inside.push_back(v);
for(int i=0;i<g[v].size();i++){
if(vis[g[v][i]]==0)
dfs(g[v][i],inside);
}
inside.pop_back();
}

int main(){

cin>>n;

for(int i=1;i<=n;i++){
   int x;
   cin>>x;
   val[i]=x;
}

for(int i=1;i<=n-1;i++){
    int x,y;
    cin>>x>>y;
    g[x].push_back(y);
    g[y].push_back(x);
}
dfs(1,inside);

for(int i=1;i<=n;i++){
    cout<<ans[i]<<" ";
}
cout<<endl;

}

For the first problem, I think we can use a greedy method. First find bitwise OR of whole array(let’s call it orval).Then we find all the critical elements that are must.
An element is critical if it’s the only one having a bit set at a position. Therefore, it’s not possible to get the max orval without this element. This can simply be done N*32(20) iterations. Then we can find the element that has most bits(that are 1) in common with orval and add it to a set. Then we remove all the common 1 bits from the orval (set it to 0 using orval = orval&(~element)) . Continue this procedure until orval becomes 0. The final set is the answer. The complexity of this is 32x32xN operations (O(n)). But since in the constraints a[i]<=10^6 which only needs 20 bits, it will be 20x20xN (i.e. 4x10^7)operations which should pass(we can modify bitOverlap function for 20 bits). Also, the while loop of orval>0 in the code won’t go over 32(or 20) beacuse everytime we find some integer with overlap it will remove atleast 1 bit from orval.

#include<bits/stdc++.h>
using namespace std;
int bitOverlap(int x,int y){
	int count=0;
	for(int i=0;i<32;i++){
		//if(((x>>i)&1)==((y>>i)&1)){
                   if(((x>>i)&1) && ((y>>i)&1)){
			count++;	
		}	
	}
	return count;	
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		vector<int> a(n,0);
		for(int i=0;i<n;i++){
			cin>>a[i];	
		}
		int orval=0;
		for(int x:a){
			orval = orval|x;	
		}
		//include critical elements first
		int arr[32];
		int element_index[32];
		memset(arr,0,sizeof(arr));
		for(int i=0;i<32;i++){element_index[i]=-1;}
		for(int j=0;j<(int)a.size();j++){
			for(int i=0;i<32;i++){
				if((a[j]>>i)&1){
					if(arr[i]==0){element_index[i]=j;}
					arr[i]+=1;
				}
			}
		}
		set<int> st;
		for(int i=0;i<32;i++){	
			if(arr[i]==1 ){
				st.insert(a[element_index[i]]);
				orval = orval&(~a[element_index[i]]);
			}
		}
		while(orval>0){
			int maxcount=0;
			int maxval=0;
			for(auto x:a){
				int val = bitOverlap(x,orval);
				if(val>maxcount){
					maxcount=val;
					maxval = x;	
				}	
			}
			st.insert(maxval);
			orval = orval&(~maxval); //fix this
			//cout<<orval<<endl;	
		}
		cout<<st.size()<<endl;
	}	
	return 0;
}

Correct me if I’m wrong

1 Like

Did any one who are 2022 passed outs get the invitation link?

Yes, There are organizing this competition in gap of every two weeks.

Does removing all the elements whose mask is a subset of an already existing mask get us the optimal solution. If that is so then I have a dp solution

Also if anyone has a solution to the Integer Distribution question please reply

Your greedy approach goes wrong if elements are like this:
0001111
1110000
0011111
1000000
1000000
What you think?

Ah! Sorry. I forgot to add one more thing… The bitOverlap we should be checking only for bits that at are set to 1
So it should be this

int bitOverlap(int x,int y){
	int count=0;
	for(int i=0;i<32;i++){
		if(((x>>i)&1)==((y>>i)&1) && ((x>>i)&1)){
			count++;	
		}	
	}
	return count;	
}

I’ve updated the code

Still the problem holds.

Isn’t the answer 2 for this case? I ran my code with input
1
5
15 112 31 64 64
and got output
2

keep checking google careers page. after applying to any particular job you will receive a mail for google online challenge. That’s how I did it.

Can anyone suggest an approach for question 2 ? I am not able to figure out even a brute force solution. How to apply bitmask dp to it?

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Solution for the 2nd question: Integer Distribution

For the 2^{nd} Question: Integer Distribution.
Here is the solution
Brute Force Approach
We first create 2 variables mx and mn to store the maximum and minimum values.
The brute force approach would be to generate all possible sequences/permutations and then loop over them, then updating the variable mx and mn accordingly depending on whether the Sum of the Xor values of the pairs in this sequence is greater than mx or lesser than mn.
Given a permutation, we group the adjacent elements into a pair and then xor that pair and then add them to the ans. The we update mx and mn.

In general for an array size of n, there are n! sequences. This translates to O(n!*n) time complexity, which wouldnt meet the time constraints, as n can be as large as 20

I have to admit that this brute force method is very bad, because there would be a lot of overcounting, for example in the array [1,2,3,4]
The sequences [2,3,1,4] and [2,3,4,1] correspond to the same pairs (2,3) and (1,4). But we end up recalculating them, leading to higher time complexity.

In fact for an array of size 4 [1,2,3,4], there are only 3 sequences that we need to check, but in this approach we end up checking 4!=24 sequences. Maybe using some sort of backtracking, we can generate just the right amount of distinct sequences, but I havent been able to figure that out yet. But I still believe that the solution I have discussed below would still be faster than any backtracking solution.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define int long long int 
vector<int> solve(vector<int>& nums){
    int n = nums.size();
    vector<int> result;
    int mx = 0, mn = 1e9 + 7;
    sort(nums.begin(), nums.end());
    do{
        int ans = 0;
        for (int i = 0; i < n;i+=2){
            ans += (nums[i] ^ nums[i + 1]);
        }
        mx = max(mx, ans);
        mn = min(mn, ans);
    } while (next_permutation(nums.begin(), nums.end()));
    result.push_back(mx);
    result.push_back(mn);
    return result;
}
signed main(){
    int n;
    cin>>n;
    vector<int> nums(n);
    for (int i = 0; i < n;i++)
        cin >> nums[i];
    vector<int> ans = solve(nums);
    cout << "Largest : " << ans[0] << endl;
    cout << "Smallest : " << ans[1] << endl;
    return 0;
}

DP Solution

I will first explain how we can get the maximum value.

Hint 1
This is a problem of bitmasking. The idea is to find the answer of some mask i where the positions where the bits are set represent that the number at the position of the array is considered and vice versa for the unset bits

Hint 2
Dp with bitmasking is a category of problems where we try to find the answer for a certain mask with x bits sets using the answers of the masks which have less than x bits set(also called submasks). Here a mask represents the array of numbers under consideration and the submasks would be the mask with any 2 bits unset(Think why?).

Solution

lets say we have the mask 1111. This means that arr[0],arr[1],arr[2] and arr[3] have been taken into consideration. So this is our subproblem that we need to solve, now. This can be done by first unsetting 2 bits and getting a new submask. The possible submasks that we can get are.

  1. 1100
  2. 1010
  3. 1001
  4. 0011
  5. 0110
  6. 0101

dp[mask] is the maximum sum of the xors that we can get when we consider only those elements that our mask represents

The reason we are unsetting 2 bits, is because these 2 bits that we unset now are the new pair that we are making right now. So we are basically checking all possible pairs that we can form in this mask and then the remaining bits that are set form our submask.

We loop over the submasks and then maximise our dp[mask]
Now our dp[mask]=max(dp[mask],arr[i]^arr[j]+dp[submask]);
Here our i and j are the indices where we unset the bits in our mask.

So we just have to loop over all masks(preferrably only those masks that have even number of bits set) and then find the dp[mask].
Our final answer would then be dp[2^n-1].

Code

#include<iostream>
#include<vector>
using namespace std;
#define int long long int
int inf = 1000 * 1000 * 1000 + 7;
int power(int a,int b){
    int ans = 1;
    while(b>0){
        if(b&1)
            ans = ans * a;
        a = a * a;
        b /= 2;
    }
    return ans;
}
vector<int> solve(int n,vector<int> nums){
    int max_masks = power(2, n);
    vector<int> dp_mx(max_masks,0);
    vector<int> dp_mn(max_masks, inf);
    dp_mx[0] = 0;
    dp_mn[0] = 0;
    vector<int> setbits;
    for (int mask = 3; mask < max_masks;mask++){
        setbits.clear();
        for (int i = 0; i < n;i++){
            if(mask&(1<<i))
                setbits.push_back(i);
        }
        if(setbits.size()%2)
            continue;
        for (int idx1 = 0; idx1 < setbits.size();idx1++){
            for (int idx2 = idx1 + 1; idx2 < setbits.size();idx2++){
                int index1 = setbits[idx1];
                int index2 = setbits[idx2];
                dp_mn[mask] = min(dp_mn[mask], (nums[index1] ^ nums[index2]) + dp_mn[mask ^ (1 << index1) ^ (1 << index2)]);
                dp_mx[mask] = max(dp_mx[mask], (nums[index1] ^ nums[index2]) + dp_mx[mask ^ (1 << index1) ^ (1 << index2)]);
            }
        }
    }
    vector<int> result;
    result.push_back(dp_mn.back());
    result.push_back(dp_mx.back());
    return result;
}
signed main(){
    int n;
    cin>>n;
    vector<int> nums(n);
    for (int i = 0; i < n;i++)
        cin >> nums[i];
    vector<int> result = solve(n, nums);
    int ans_mn = result[0];
    int ans_mx = result[1];
    cout << "Smallest : " << ans_mn << endl;
    cout<<"Largest: " <<ans_mx<< endl;
    return 0;
}

The time complexity of this approach is O(n^22^n). This is actually an upperbound, because we dont evaluate all masks, as I am skipping the masks with odd number of bits set. Also the actual complexity would be as follows:

\sum\limits_{i=2,i=even}^{n} (^{n}C_{i}) (^{i}C_{2}).

This is my 1^{st} time posting a solution on codechef. So feel free to make suggestions regarding the clarity in my explanation and my approach.
Thank you :slight_smile:
Also I would love to see, if there are any other much optimised solutions.