Achieving Y through integer splitting
Last Updated :
16 Nov, 2023
Given integers X and Y, the task is to check if Y can be formed from X by performing the following operations any number of times:
- Split X into 2 integers A and B such that:
- A is twice B
- The Sum of A and B is equal to X
- Update the value of X with either A or B
- Repeat the above steps till Y is achieved.
Examples:
Input: X = 9, Y = 4
Output: YES
Explanation: The operations can be performed as follows:
- Split X(= 9) into 6 and 3, such that A = 6 and B = 3. (as 6 = 2*3 and 6 + 3 = 9)
- Update X with A, i.e., X = 6
- Now Split X(= 6) into 4 and 2, such that A = 4 and B = 2. (as 4 = 2*2 and 2 + 4 = 6)
Therefore Y = 4 has been achieved after 2 operations. So print YES.
Input : X = 4, Y = 2
Output : NO
Explanation : It can be guaranteed that X = 4 cannot be further broken down into A and B such that it follows the given condition
Approach: To solve this problem, let us first see an observation:
Given that X is split into A and B, such that:
- A is twice B, i.e., ….. (Equation 1)
- The sum of A and B is X, i.e., ….. (Equation 2)
Therefore solving the above two equations:
- ….. (By Substituting Equation 1 in 2)
- Therefore, and
Hence for splitting X into A and B as per the given conditions, X must be a multiple of 3.
Now based on this observation, The problem can be solved easily by using Recursion. Following steps can be used to arrive at the solution:
- Case 1: If X is already equal to Y,
- Integer Y is feasible always, without doing any operations. Hence return YES
- Case 2: If X is not divisible by 3,
- it is not possible to arrive at the solution Y, as explained in the above observation. Hence return NO
- Case 3: If X is a multiple of 3,
- Divide X into X/3 and 2*X/3 recursively, and check if constructing Y is possible.
Following is the code based on the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool isYPossibleFromX( int X, int Y)
{
if (X == Y) {
return true ;
}
else if (X % 3 != 0) {
return false ;
}
else {
return (isYPossibleFromX(X / 3, Y)
|| isYPossibleFromX(2 * (X / 3), Y));
}
}
int main()
{
int X = 9, Y = 4;
if (isYPossibleFromX(X, Y)) {
cout << "YES" ;
}
else {
cout << "NO" ;
}
return 0;
}
|
Java
import java.io.*;
public class GFG {
public static boolean isYPossibleFromX( int X, int Y) {
if (X == Y) {
return true ;
}
else if (X % 3 != 0 ) {
return false ;
}
else {
return (isYPossibleFromX(X / 3 , Y) || isYPossibleFromX( 2 * (X / 3 ), Y));
}
}
public static void main(String[] args) {
int X = 9 , Y = 4 ;
if (isYPossibleFromX(X, Y)) {
System.out.println( "YES" );
} else {
System.out.println( "NO" );
}
}
}
|
Python
def is_y_possible_from_x(X, Y):
if X = = Y:
return True
elif X % 3 ! = 0 :
return False
else :
return is_y_possible_from_x(X / / 3 , Y) or is_y_possible_from_x( 2 * (X / / 3 ), Y)
if __name__ = = "__main__" :
X = 9
Y = 4
if is_y_possible_from_x(X, Y):
print ( "YES" )
else :
print ( "NO" )
|
C#
using System;
class Program
{
static bool IsYPossibleFromX( int X, int Y)
{
if (X == Y)
{
return true ;
}
else if (X % 3 != 0)
{
return false ;
}
else
{
return (IsYPossibleFromX(X / 3, Y)
|| IsYPossibleFromX(2 * (X / 3), Y));
}
}
static void Main( string [] args)
{
int X = 9, Y = 4;
if (IsYPossibleFromX(X, Y))
{
Console.WriteLine( "YES" );
}
else
{
Console.WriteLine( "NO" );
}
}
}
|
Javascript
function isYPossibleFromX(X, Y) {
if (X === Y) {
return true ;
}
else if (X % 3 !== 0) {
return false ;
}
else {
return isYPossibleFromX(Math.floor(X / 3), Y) || isYPossibleFromX(2 * Math.floor(X / 3), Y);
}
}
const X = 9;
const Y = 4;
if (isYPossibleFromX(X, Y)) {
console.log( "YES" );
} else {
console.log( "NO" );
}
|
Time Complexity: O(2^(log3 X))
Auxiliary Space: O(1)
Efficient Approach: We can optimize the above recursive approach using memoization. Let us see an observation:
Let’s recursively break X as follow:
- Firstly we break X into A=2X/3 and B=X/3.
- Now, breaking 2X/3 gives us 4X/9 and 2X/9.
- Also, breaking X/3 gives us 2X/9 and X/9.
We can clearly see that 2X/3 is calculated twice. Hence we can use memoization to avoid this recomputation.
Based on the above observation we can clearly see that 2X/3 is calculated twice. Hence we can use memoization to avoid this recomputation.
The following steps can be used to arrive at the solution:
- Initialize an array dp[] of size X+1 with dp[i] = -1 for each 0 < i <= X.
- While each recursive call stores dp[i] = 0(i.e. false) if Y cannot be derived from current X and dp[i] = 1(i.e. true) if Y can be derived from the current X.
- return back from a recursive call if dp[X] != -1(i.e current X is already computed and we can avoid recomputation)
Following is the code based on the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool isYPossibleFromX( int X, int Y, int dp[])
{
if (dp[X] != -1)
return dp[X];
if (X == Y) {
dp[X] = 1;
return true ;
}
else if (X % 3 != 0) {
dp[X] = 0;
return false ;
}
else {
if (isYPossibleFromX(X / 3, Y, dp)
|| isYPossibleFromX(2 * (X / 3), Y, dp)) {
dp[X] = 1;
return true ;
}
else {
dp[X] = 0;
return false ;
}
}
}
int main()
{
int X = 9, Y = 4;
int dp[X + 1];
for ( int i = 0; i <= X; i++) {
dp[i] = -1;
}
bool answer = isYPossibleFromX(X, Y, dp);
if (answer) {
cout << "YES" ;
}
else {
cout << "NO" ;
}
return 0;
}
|
Java
import java.util.Arrays;
class Main {
static boolean isYPossibleFromX( int X, int Y, int [] dp) {
if (dp[X] != - 1 )
return dp[X] == 1 ;
if (X == Y) {
dp[X] = 1 ;
return true ;
}
else if (X % 3 != 0 ) {
dp[X] = 0 ;
return false ;
}
else {
if (isYPossibleFromX(X / 3 , Y, dp)
|| isYPossibleFromX( 2 * (X / 3 ), Y, dp)) {
dp[X] = 1 ;
return true ;
}
else {
dp[X] = 0 ;
return false ;
}
}
}
public static void main(String[] args) {
int X = 4 , Y = 4 ;
int [] dp = new int [X + 1 ];
Arrays.fill(dp, - 1 );
boolean answer = isYPossibleFromX(X, Y, dp);
if (answer) {
System.out.println( "YES" );
}
else {
System.out.println( "NO" );
}
}
}
|
Python3
def is_Y_possible_from_X(X, Y, dp):
if dp[X] ! = - 1 :
return dp[X]
if X = = Y:
dp[X] = 1
return True
elif X % 3 ! = 0 :
dp[X] = 0
return False
else :
if is_Y_possible_from_X(X / / 3 , Y, dp) or is_Y_possible_from_X( 2 * (X / / 3 ), Y, dp):
dp[X] = 1
return True
else :
dp[X] = 0
return False
X = 9
Y = 4
dp = [ - 1 ] * (X + 1 )
answer = is_Y_possible_from_X(X, Y, dp)
if answer:
print ( "YES" )
else :
print ( "NO" )
|
C#
using System;
class MainClass
{
static bool IsYPossibleFromX( int X, int Y, int [] dp)
{
if (dp[X] != -1)
return dp[X] == 1;
if (X == Y)
{
dp[X] = 1;
return true ;
}
else if (X % 3 != 0)
{
dp[X] = 0;
return false ;
}
else
{
if (IsYPossibleFromX(X / 3, Y, dp)
|| IsYPossibleFromX(2 * (X / 3), Y, dp))
{
dp[X] = 1;
return true ;
}
else
{
dp[X] = 0;
return false ;
}
}
}
public static void Main( string [] args)
{
int X = 4, Y = 4;
int [] dp = new int [X + 1];
for ( int i = 0; i <= X; i++)
{
dp[i] = -1;
}
bool answer = IsYPossibleFromX(X, Y, dp);
if (answer)
{
Console.WriteLine( "YES" );
}
else
{
Console.WriteLine( "NO" );
}
}
}
|
Javascript
function isYPossibleFromX(X, Y, dp) {
if (dp[X] !== -1) {
return dp[X];
}
if (X === Y) {
dp[X] = 1;
return true ;
}
else if (X % 3 !== 0) {
dp[X] = 0;
return false ;
}
else {
if (isYPossibleFromX(X / 3, Y, dp)
|| isYPossibleFromX(2 * (X / 3), Y, dp)) {
dp[X] = 1;
return true ;
} else {
dp[X] = 0;
return false ;
}
}
}
function main() {
const X = 9, Y = 4;
const dp = new Array(X + 1).fill(-1);
const answer = isYPossibleFromX(X, Y, dp);
if (answer) {
console.log( "YES" );
} else {
console.log( "NO" );
}
}
main();
|
Time Complexity: O
Auxiliary Space: O(X)
Share your thoughts in the comments
Please Login to comment...