package com.interview.dynamic;
import java.util.*;
/**
* Date 10/19/2016
* @author Tushar Roy
*
* Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
* For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
*
* Solution 1 - Using DP similar to coin change problem with infinite supply
* Solution 2 - Using a BFS. Put all perfect squares in queue. Then considering each as a node try adding
* another perfect square and see if we can get n. Keep doing this in BFS fashion till you hit the number.
*
* https://leetcode.com/problems/perfect-squares/
*/
public class MinimumNumberOfPerfectSquares {
public int numSquaresUsingDP(int n) {
int count = (int)Math.ceil(Math.sqrt(n));
int[] T = new int[n + 1];
T[0] = 0;
for (int i = 1; i < T.length; i++) {
T[i] = Integer.MAX_VALUE;
for (int j = 1; j <= count; j++) {
if (i < j*j) {
break;
}
T[i] = Math.min(T[i], T[i - j*j] + 1);
}
}
return T[n];
}
public int numSquaresUsingBFS(int n) {
List<Integer> perfectSquares = new ArrayList<>();
int i = 1;
Queue<Integer> queue = new LinkedList<>();
Set<Integer> visited = new HashSet<>();
while (true) {
int square = i * i;
if (square == n) {
return 1;
}
if (square > n) {
break;
}
perfectSquares.add(square);
queue.offer(square);
visited.add(square);
i++;
}
int distance = 1;
while (!queue.isEmpty()) {
int size = queue.size();
distance++;
for (int j = 0; j < size; j++) {
int node = queue.poll();
for (int square : perfectSquares) {
int sum = node + square;
if (sum == n) {
return distance;
} else if (!visited.contains(sum)) {
visited.add(sum);
queue.add(sum);
} else if (sum > n) {
break;
}
}
}
}
return distance;
}
}