Chef, Chefina and their friendship

CHEFSHIP

Codechef May Cook-Off 2020

 

 

Let's Take an Example to understand more about problem

s = "abcabcbcbc"

T1

T1

 

Let's Take an Example to understand more about problem

s = "abcabcbcbc"

T2

T2

 

Let's Take an Example to understand more about problem

s = "abcabcbcbc"

T2

T2

s = 2*T1 + 2*T2

T1 = "abc"

T2 = "bc"

 

There is only one way in which we can divide s into T1 and T2

 

So, first of All, let's go through the thought process of the Solution

 

Now to find number of possible ways we will have to first iterate for every even size substring of string starting from 0.

s = a b c a b c b c b c

a != b

&&

cabc != bcbc

 

So, first of All, let's go through the thought process of the Solution

 

Now to find number of possible ways we will have to first iterate for every even size substring of string starting from 0.

s = a b c a b c b c b c

ab != ca

&&

bcb != cbc

 

So, first of All, let's go through the thought process of the Solution

 

Now to find number of possible ways we will have to first iterate for every even size substring of string starting from 0.

s = a b c a b c b c b c

abc == abc

&&

bc == bc

T1

T1

T2

T2

 

Code

 

We can Easily code this solution for every even substring starting from 0, checking if we can form T1 and T2.

int cnt = 0;
for (int i = 1;i < s.size()-1;i+=2)
{
    int first_cut = (i+1)/2;
    int second_cut = (n+i)/2;
    if (s.substr(0, first_cut) == s.substr(first_cut, first_cut) && s.substr(i+1, (n-i-1)/2) == s.substr(second_cut+1, (n-i-1)/2))
    	cnt++;
}

Optimizing the Solution

We have coded the Brute Force solution which will run in O(n*n) complexity.

We have to traverse the string to count ways, Now we have to reduce complexity in string comparison which is taking another O(n) time, we need to do it in O(1).

Optimizing the Solution

We have algorithms that can perform string comparison in constant time.

These are 

KMP;

 Z algo;

String hashing

etc.

In this video we will talk about string hashing.

What is a string Hash?

Representation of a string into an integer value.

What is a string Hash?

Representation of a string into an integer value.

What is a hash function?

A function that gives converts the input string into an hashed integer.

hash("abc") = x

 

Properties Of Hash

1

Hash should satisfy following two property.

  1. if two strings s and t are equal (s=t), then also their hashes have to be equal (hash(s)=hash(t)).
  2. If the hashes are equal (hash(s)=hash(t)), then the strings do not necessarily have to be equal.

 

Calculation of a hash of a string.

You can create your own hash function provided that they satisfy hash properties.

widely used hash function

hash(s)=s[0]+s[1]⋅p+s[2]⋅p^2+...+s[n−1]⋅{p^{n−1}}\ mod\ m \newline =\displaystyle\sum_{i=0}^{n-1} s[i]⋅p^i\ mod\ m,

 

Calculation of a hash of a string.

widely used hash function

hash(s)=s[0]+s[1]⋅p+s[2]⋅p^2+...+s[n−1]⋅{p^{n−1}}\ mod\ m \newline =\displaystyle\sum_{i=0}^{n-1} s[i]⋅p^i\ mod\ m,

What is p and m?

you can choose any prime number as p and m.

p should be a prime number greater than 26.

you can choose m as 

10^9+7

 

Computation of hash for a substring of a string.

hash(s[i…j]) = \displaystyle\sum_{k=i}^j s[k]⋅p^{k−i}\ mod\ m

Multiplying both side by 

p^i
hash(s[i…j])⋅p^i = \displaystyle\sum_{k=i}^j s[k]⋅p^k\ mod\ m \newline=hash(s[0…j])−hash(s[0…i−1])\ mod\ m

 

Computation of hash for a substring of a string.

hash(s[i…j])⋅p^i = hash(s[0…j])−hash(s[0…i−1])\ mod\ m

 

Computation of hash for a substring of a string.

hash(s[i…j]) = hash(s[0…j])−hash(s[0…i−1])\ mod\ m\ /\ p^i

Multiplicative Modulo Inverse

 

Computation of hash for a substring of a string.

hash(s[i…j]).p^i = hash(s[0…j])−hash(s[0…i−1])\ mod\ m

Since here we only need to compare strings

suppose we want to compare s[i...j] and s[j+1...n]

 

Computation of hash for a substring of a string.

hash(s[i…j]).p^i = hash(s[0…j])−hash(s[0…i−1])\ mod\ m

Since here we only need to compare strings

suppose we want to compare s[i...j] and s[j+1...n]

But we don't have hash(s[i...j]) and hash(s[j+1...n]) instead we have hash(s[i...j]).          and hash(s[j+1,n]).

p^i
p^{j+1}

 

Computation of hash for a substring of a string.

hash(s[i…j]).p^i = hash(s[0…j])−hash(s[0…i−1])\ mod\ m

Since here we only need to compare strings

hash(s[i...j]).p^i.p^{j+1-i} = hash(s[0…j])−hash(s[0…i−1]).p^{j+1-i}\ mod\ m
hash(s[i...j]).p^{j+1} = hash(s[0…j])−hash(s[0…i−1]).p^{j+1-i}\ mod\ m
compare(s[i...j].p^i,\ s[j+1 ...n].p^{j+1})

 

Code for that approach

ll p = 31;
ll h[100001];
ll power[100001];
ll mod = 1e9 + 7;

void generate_hash(string s)
{
	h[0] = s[0]-'a'+1;
	power[0] = 1;
	for (int i = 1;i < s.size();i++)
	{
		power[i] = ((power[i-1] % mod) * (p % mod)) % mod;
		h[i] = (h[i-1] % mod + ((s[i]-'a'+1)%mod * (power[i]%mod)) % mod) % mod;
	}
}

ll get_hash(int l, int r)
{
	if (l == 0)
		return h[r]%mod;
	else
	{
		return ((h[r] - h[l-1] + mod))%mod;
	}
}

for(int i = 1; i<s.length()-1; i+=2)
{
    int id1 = i/2;
    int id2 = (n+i)/2;
//	cout << i << "\n";
    bool c1 = (get_hash(0,id1)*power[id1+1])%mod == get_hash(id1+1,i);
    bool c2 = (get_hash(i+1,id2)*power[id2-i])%mod == get_hash(id2+1,n-1);
    if (c1 && c2)
        count++;

}

 

Complexity of this Approach

As we can see we are comparing strings in O(1) as get_hash function works in O(1) complexity.

So the Total Complexity of code will be O(n)

Codechef CHEFSHIP solution

By gauravsahu

Codechef CHEFSHIP solution

  • 56